diff --git a/src/CLASS2/pair_lj_class2_coul_long.cpp b/src/CLASS2/pair_lj_class2_coul_long.cpp index 34ff47d80..3dbf8e2ec 100644 --- a/src/CLASS2/pair_lj_class2_coul_long.cpp +++ b/src/CLASS2/pair_lj_class2_coul_long.cpp @@ -1,468 +1,468 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "pair_lj_class2_coul_long.h" #include "atom.h" #include "comm.h" #include "force.h" #include "kspace.h" #include "neighbor.h" #include "neigh_list.h" #include "math_const.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace MathConst; #define EWALD_F 1.12837917 #define EWALD_P 0.3275911 #define A1 0.254829592 #define A2 -0.284496736 #define A3 1.421413741 #define A4 -1.453152027 #define A5 1.061405429 /* ---------------------------------------------------------------------- */ PairLJClass2CoulLong::PairLJClass2CoulLong(LAMMPS *lmp) : Pair(lmp) {} /* ---------------------------------------------------------------------- */ PairLJClass2CoulLong::~PairLJClass2CoulLong() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut_lj); memory->destroy(cut_ljsq); memory->destroy(epsilon); memory->destroy(sigma); memory->destroy(lj1); memory->destroy(lj2); memory->destroy(lj3); memory->destroy(lj4); memory->destroy(offset); } } /* ---------------------------------------------------------------------- */ void PairLJClass2CoulLong::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair; double rsq,r,rinv,r2inv,r3inv,r6inv,forcecoul,forcelj; double grij,expm2,prefactor,t,erfc; double factor_coul,factor_lj; int *ilist,*jlist,*numneigh,**firstneigh; evdwl = ecoul = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; double **x = atom->x; double **f = atom->f; double *q = atom->q; int *type = atom->type; int nlocal = atom->nlocal; double *special_coul = force->special_coul; double *special_lj = force->special_lj; int newton_pair = force->newton_pair; double qqrd2e = force->qqrd2e; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // loop over neighbors of my atoms for (ii = 0; ii < inum; ii++) { i = ilist[ii]; qtmp = q[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; factor_lj = special_lj[sbmask(j)]; factor_coul = special_coul[sbmask(j)]; j &= NEIGHMASK; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; jtype = type[j]; if (rsq < cutsq[itype][jtype]) { r2inv = 1.0/rsq; if (rsq < cut_coulsq) { r = sqrt(rsq); grij = g_ewald * r; expm2 = exp(-grij*grij); t = 1.0 / (1.0 + EWALD_P*grij); erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2; prefactor = qqrd2e * qtmp*q[j]/r; forcecoul = prefactor * (erfc + EWALD_F*grij*expm2); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor; } else forcecoul = 0.0; if (rsq < cut_ljsq[itype][jtype]) { rinv = sqrt(r2inv); r3inv = r2inv*rinv; r6inv = r3inv*r3inv; forcelj = r6inv * (lj1[itype][jtype]*r3inv - lj2[itype][jtype]); } else forcelj = 0.0; fpair = (forcecoul + factor_lj*forcelj) * r2inv; f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; if (newton_pair || j < nlocal) { f[j][0] -= delx*fpair; f[j][1] -= dely*fpair; f[j][2] -= delz*fpair; } if (eflag) { if (rsq < cut_coulsq) { ecoul = prefactor*erfc; if (factor_coul < 1.0) ecoul -= (1.0-factor_coul)*prefactor; } else ecoul = 0.0; if (rsq < cut_ljsq[itype][jtype]) { evdwl = r6inv*(lj3[itype][jtype]*r3inv-lj4[itype][jtype]) - offset[itype][jtype]; evdwl *= factor_lj; } else evdwl = 0.0; } if (evflag) ev_tally(i,j,nlocal,newton_pair, evdwl,ecoul,fpair,delx,dely,delz); } } } if (vflag_fdotr) virial_fdotr_compute(); } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairLJClass2CoulLong::allocate() { allocated = 1; int n = atom->ntypes; memory->create(setflag,n+1,n+1,"pair:setflag"); for (int i = 1; i <= n; i++) for (int j = i; j <= n; j++) setflag[i][j] = 0; memory->create(cutsq,n+1,n+1,"pair:cutsq"); memory->create(cut_lj,n+1,n+1,"pair:cut_lj"); memory->create(cut_ljsq,n+1,n+1,"pair:cut_ljsq"); memory->create(epsilon,n+1,n+1,"pair:epsilon"); memory->create(sigma,n+1,n+1,"pair:sigma"); memory->create(lj1,n+1,n+1,"pair:lj1"); memory->create(lj2,n+1,n+1,"pair:lj2"); memory->create(lj3,n+1,n+1,"pair:lj3"); memory->create(lj4,n+1,n+1,"pair:lj4"); memory->create(offset,n+1,n+1,"pair:offset"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairLJClass2CoulLong::settings(int narg, char **arg) { if (narg < 1 || narg > 2) error->all(FLERR,"Illegal pair_style command"); cut_lj_global = force->numeric(arg[0]); if (narg == 1) cut_coul = cut_lj_global; else cut_coul = force->numeric(arg[1]); // reset cutoffs that have been explicitly set if (allocated) { int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i+1; j <= atom->ntypes; j++) if (setflag[i][j]) cut_lj[i][j] = cut_lj_global; } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairLJClass2CoulLong::coeff(int narg, char **arg) { if (narg < 4 || narg > 6) error->all(FLERR,"Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(arg[2]); double sigma_one = force->numeric(arg[3]); double cut_lj_one = cut_lj_global; if (narg == 5) cut_lj_one = force->numeric(arg[4]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { epsilon[i][j] = epsilon_one; sigma[i][j] = sigma_one; cut_lj[i][j] = cut_lj_one; setflag[i][j] = 1; count++; } } if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairLJClass2CoulLong::init_style() { if (!atom->q_flag) error->all(FLERR,"Pair style lj/class2/coul/long requires atom attribute q"); neighbor->request(this); cut_coulsq = cut_coul * cut_coul; // insure use of KSpace long-range solver, set g_ewald if (force->kspace == NULL) error->all(FLERR,"Pair style is incompatible with KSpace style"); g_ewald = force->kspace->g_ewald; } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairLJClass2CoulLong::init_one(int i, int j) { // always mix epsilon,sigma via sixthpower rules // mix distance via user-defined rule if (setflag[i][j] == 0) { epsilon[i][j] = 2.0 * sqrt(epsilon[i][i]*epsilon[j][j]) * pow(sigma[i][i],3.0) * pow(sigma[j][j],3.0) / (pow(sigma[i][i],6.0) + pow(sigma[j][j],6.0)); sigma[i][j] = pow((0.5 * (pow(sigma[i][i],6.0) + pow(sigma[j][j],6.0))),1.0/6.0); cut_lj[i][j] = mix_distance(cut_lj[i][i],cut_lj[j][j]); } double cut = MAX(cut_lj[i][j],cut_coul); cut_ljsq[i][j] = cut_lj[i][j] * cut_lj[i][j]; lj1[i][j] = 18.0 * epsilon[i][j] * pow(sigma[i][j],9.0); lj2[i][j] = 18.0 * epsilon[i][j] * pow(sigma[i][j],6.0); lj3[i][j] = 2.0 * epsilon[i][j] * pow(sigma[i][j],9.0); lj4[i][j] = 3.0 * epsilon[i][j] * pow(sigma[i][j],6.0); if (offset_flag) { double ratio = sigma[i][j] / cut_lj[i][j]; offset[i][j] = epsilon[i][j] * (2.0*pow(ratio,9.0) - 3.0*pow(ratio,6.0)); } else offset[i][j] = 0.0; cut_ljsq[j][i] = cut_ljsq[i][j]; lj1[j][i] = lj1[i][j]; lj2[j][i] = lj2[i][j]; lj3[j][i] = lj3[i][j]; lj4[j][i] = lj4[i][j]; offset[j][i] = offset[i][j]; // compute I,J contribution to long-range tail correction // count total # of atoms of type I and J via Allreduce if (tail_flag) { int *type = atom->type; int nlocal = atom->nlocal; double count[2],all[2]; count[0] = count[1] = 0.0; for (int k = 0; k < nlocal; k++) { if (type[k] == i) count[0] += 1.0; if (type[k] == j) count[1] += 1.0; } MPI_Allreduce(count,all,2,MPI_DOUBLE,MPI_SUM,world); double sig3 = sigma[i][j]*sigma[i][j]*sigma[i][j]; double sig6 = sig3*sig3; double rc3 = cut_lj[i][j]*cut_lj[i][j]*cut_lj[i][j]; double rc6 = rc3*rc3; etail_ij = 2.0*MY_PI*all[0]*all[1]*epsilon[i][j] * sig6 * (sig3 - 3.0*rc3) / (3.0*rc6); ptail_ij = 2.0*MY_PI*all[0]*all[1]*epsilon[i][j] * sig6 * (sig3 - 2.0*rc3) / rc6; } return cut; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJClass2CoulLong::write_restart(FILE *fp) { write_restart_settings(fp); int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { fwrite(&setflag[i][j],sizeof(int),1,fp); if (setflag[i][j]) { fwrite(&epsilon[i][j],sizeof(double),1,fp); fwrite(&sigma[i][j],sizeof(double),1,fp); fwrite(&cut_lj[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJClass2CoulLong::read_restart(FILE *fp) { read_restart_settings(fp); allocate(); int i,j; int me = comm->me; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp); MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world); if (setflag[i][j]) { if (me == 0) { fread(&epsilon[i][j],sizeof(double),1,fp); fread(&sigma[i][j],sizeof(double),1,fp); fread(&cut_lj[i][j],sizeof(double),1,fp); } MPI_Bcast(&epsilon[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_lj[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJClass2CoulLong::write_restart_settings(FILE *fp) { fwrite(&cut_lj_global,sizeof(double),1,fp); fwrite(&cut_coul,sizeof(double),1,fp); fwrite(&offset_flag,sizeof(int),1,fp); fwrite(&mix_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJClass2CoulLong::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&cut_lj_global,sizeof(double),1,fp); fread(&cut_coul,sizeof(double),1,fp); fread(&offset_flag,sizeof(int),1,fp); fread(&mix_flag,sizeof(int),1,fp); } MPI_Bcast(&cut_lj_global,1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_coul,1,MPI_DOUBLE,0,world); MPI_Bcast(&offset_flag,1,MPI_INT,0,world); MPI_Bcast(&mix_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- */ double PairLJClass2CoulLong::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r2inv,r,rinv,r3inv,r6inv,grij,expm2,t,erfc,prefactor; double forcecoul,forcelj,phicoul,philj; r2inv = 1.0/rsq; if (rsq < cut_coulsq) { r = sqrt(rsq); grij = g_ewald * r; expm2 = exp(-grij*grij); t = 1.0 / (1.0 + EWALD_P*grij); erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2; prefactor = force->qqrd2e * atom->q[i]*atom->q[j]/r; forcecoul = prefactor * (erfc + EWALD_F*grij*expm2); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor; } else forcecoul = 0.0; if (rsq < cut_ljsq[itype][jtype]) { rinv = sqrt(r2inv); r3inv = r2inv*rinv; r6inv = r3inv*r3inv; forcelj = r6inv * (lj1[itype][jtype]*r3inv - lj2[itype][jtype]); } else forcelj = 0.0; fforce = (forcecoul + factor_lj*forcelj) * r2inv; double eng = 0.0; if (rsq < cut_coulsq) { phicoul = prefactor*erfc; if (factor_coul < 1.0) phicoul -= (1.0-factor_coul)*prefactor; eng += phicoul; } if (rsq < cut_ljsq[itype][jtype]) { philj = r6inv*(lj3[itype][jtype]*r3inv-lj4[itype][jtype]) - offset[itype][jtype]; eng += factor_lj*philj; } return eng; } /* ---------------------------------------------------------------------- */ -void *PairLJClass2CoulLong::extract(char *str, int &dim) +void *PairLJClass2CoulLong::extract(const char *str, int &dim) { dim = 0; if (strcmp(str,"cut_coul") == 0) return (void *) &cut_coul; return NULL; } diff --git a/src/CLASS2/pair_lj_class2_coul_long.h b/src/CLASS2/pair_lj_class2_coul_long.h index e2f1b17e7..0e5ebd6a1 100644 --- a/src/CLASS2/pair_lj_class2_coul_long.h +++ b/src/CLASS2/pair_lj_class2_coul_long.h @@ -1,80 +1,80 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ #ifdef PAIR_CLASS PairStyle(lj/class2/coul/long,PairLJClass2CoulLong) #else #ifndef LMP_PAIR_LJ_CLASS2_COUL_LONG_H #define LMP_PAIR_LJ_CLASS2_COUL_LONG_H #include "pair.h" namespace LAMMPS_NS { class PairLJClass2CoulLong : public Pair { public: PairLJClass2CoulLong(class LAMMPS *); virtual ~PairLJClass2CoulLong(); virtual void compute(int, int); void settings(int, char **); void coeff(int, char **); void init_style(); double init_one(int, int); void write_restart(FILE *); void read_restart(FILE *); void write_restart_settings(FILE *); void read_restart_settings(FILE *); double single(int, int, int, int, double, double, double, double &); - void *extract(char *, int &); + void *extract(const char *, int &); protected: double cut_lj_global; double **cut_lj,**cut_ljsq; double cut_coul,cut_coulsq; double **epsilon,**sigma; double **lj1,**lj2,**lj3,**lj4,**offset; double g_ewald; void allocate(); }; } #endif #endif /* ERROR/WARNING messages: E: Illegal ... command Self-explanatory. Check the input script syntax and compare to the documentation for the command. You can use -echo screen as a command-line option when running LAMMPS to see the offending line. E: Incorrect args for pair coefficients Self-explanatory. Check the input script or data file. E: Pair style lj/class2/coul/long requires atom attribute q The atom style defined does not have this attribute. E: Pair style is incompatible with KSpace style If a pair style with a long-range Coulombic component is selected, then a kspace style must also be used. */ diff --git a/src/KSPACE/pair_born_coul_long.cpp b/src/KSPACE/pair_born_coul_long.cpp index 2e607cd74..88112d549 100644 --- a/src/KSPACE/pair_born_coul_long.cpp +++ b/src/KSPACE/pair_born_coul_long.cpp @@ -1,497 +1,497 @@ /* ---------------------------------------------------------------------- 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 author: Ahmed Ismail (SNL) ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "pair_born_coul_long.h" #include "atom.h" #include "comm.h" #include "force.h" #include "kspace.h" #include "neighbor.h" #include "neigh_list.h" #include "math_const.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace MathConst; #define EWALD_F 1.12837917 #define EWALD_P 0.3275911 #define A1 0.254829592 #define A2 -0.284496736 #define A3 1.421413741 #define A4 -1.453152027 #define A5 1.061405429 /* ---------------------------------------------------------------------- */ PairBornCoulLong::PairBornCoulLong(LAMMPS *lmp) : Pair(lmp) {} /* ---------------------------------------------------------------------- */ PairBornCoulLong::~PairBornCoulLong() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut_lj); memory->destroy(cut_ljsq); memory->destroy(a); memory->destroy(rho); memory->destroy(sigma); memory->destroy(c); memory->destroy(d); memory->destroy(rhoinv); memory->destroy(born1); memory->destroy(born2); memory->destroy(born3); memory->destroy(offset); } } /* ---------------------------------------------------------------------- */ void PairBornCoulLong::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair; double rsq,r2inv,r6inv,forcecoul,forceborn,factor_coul,factor_lj; double grij,expm2,prefactor,t,erfc; double r,rexp; int *ilist,*jlist,*numneigh,**firstneigh; evdwl = ecoul = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; double **x = atom->x; double **f = atom->f; double *q = atom->q; int *type = atom->type; int nlocal = atom->nlocal; double *special_coul = force->special_coul; double *special_lj = force->special_lj; int newton_pair = force->newton_pair; double qqrd2e = force->qqrd2e; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // loop over neighbors of my atoms for (ii = 0; ii < inum; ii++) { i = ilist[ii]; qtmp = q[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; factor_lj = special_lj[sbmask(j)]; factor_coul = special_coul[sbmask(j)]; j &= NEIGHMASK; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; jtype = type[j]; if (rsq < cutsq[itype][jtype]) { r2inv = 1.0/rsq; r = sqrt(rsq); if (rsq < cut_coulsq) { grij = g_ewald * r; expm2 = exp(-grij*grij); t = 1.0 / (1.0 + EWALD_P*grij); erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2; prefactor = qqrd2e * qtmp*q[j]/r; forcecoul = prefactor * (erfc + EWALD_F*grij*expm2); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor; } else forcecoul = 0.0; if (rsq < cut_ljsq[itype][jtype]) { r6inv = r2inv*r2inv*r2inv; rexp = exp((sigma[itype][jtype]-r)*rhoinv[itype][jtype]); forceborn = born1[itype][jtype]*r*rexp - born2[itype][jtype]*r6inv + born3[itype][jtype]*r2inv*r6inv; } else forceborn = 0.0; fpair = (forcecoul + factor_lj*forceborn) * r2inv; f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; if (newton_pair || j < nlocal) { f[j][0] -= delx*fpair; f[j][1] -= dely*fpair; f[j][2] -= delz*fpair; } if (eflag) { if (rsq < cut_coulsq) { ecoul = prefactor*erfc; if (factor_coul < 1.0) ecoul -= (1.0-factor_coul)*prefactor; } else ecoul = 0.0; if (rsq < cut_ljsq[itype][jtype]) { evdwl = a[itype][jtype]*rexp - c[itype][jtype]*r6inv + d[itype][jtype]*r6inv*r2inv - offset[itype][jtype]; evdwl *= factor_lj; } else evdwl = 0.0; } if (evflag) ev_tally(i,j,nlocal,newton_pair, evdwl,ecoul,fpair,delx,dely,delz); } } } if (vflag_fdotr) virial_fdotr_compute(); } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairBornCoulLong::allocate() { allocated = 1; int n = atom->ntypes; memory->create(setflag,n+1,n+1,"pair:setflag"); for (int i = 1; i <= n; i++) for (int j = i; j <= n; j++) setflag[i][j] = 0; memory->create(cutsq,n+1,n+1,"pair:cutsq"); memory->create(cut_lj,n+1,n+1,"pair:cut_lj"); memory->create(cut_ljsq,n+1,n+1,"pair:cut_ljsq"); memory->create(a,n+1,n+1,"pair:a"); memory->create(rho,n+1,n+1,"pair:rho"); memory->create(sigma,n+1,n+1,"pair:sigma"); memory->create(c,n+1,n+1,"pair:c"); memory->create(d,n+1,n+1,"pair:d"); memory->create(rhoinv,n+1,n+1,"pair:rhoinv"); memory->create(born1,n+1,n+1,"pair:born1"); memory->create(born2,n+1,n+1,"pair:born2"); memory->create(born3,n+1,n+1,"pair:born3"); memory->create(offset,n+1,n+1,"pair:offset"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairBornCoulLong::settings(int narg, char **arg) { if (narg < 1 || narg > 2) error->all(FLERR,"Illegal pair_style command"); cut_lj_global = force->numeric(arg[0]); if (narg == 1) cut_coul = cut_lj_global; else cut_coul = force->numeric(arg[1]); // reset cutoffs that have been explicitly set if (allocated) { int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i+1; j <= atom->ntypes; j++) if (setflag[i][j]) cut_lj[i][j] = cut_lj_global; } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairBornCoulLong::coeff(int narg, char **arg) { if (narg < 7 || narg > 8) error->all(FLERR,"Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); double a_one = force->numeric(arg[2]); double rho_one = force->numeric(arg[3]); double sigma_one = force->numeric(arg[4]); if (rho_one <= 0) error->all(FLERR,"Incorrect args for pair coefficients"); double c_one = force->numeric(arg[5]); double d_one = force->numeric(arg[6]); double cut_lj_one = cut_lj_global; if (narg == 8) cut_lj_one = force->numeric(arg[7]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { a[i][j] = a_one; rho[i][j] = rho_one; sigma[i][j] = sigma_one; c[i][j] = c_one; d[i][j] = d_one; cut_lj[i][j] = cut_lj_one; setflag[i][j] = 1; count++; } } if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairBornCoulLong::init_one(int i, int j) { if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set"); double cut = MAX(cut_lj[i][j],cut_coul); cut_ljsq[i][j] = cut_lj[i][j] * cut_lj[i][j]; rhoinv[i][j] = 1.0/rho[i][j]; born1[i][j] = a[i][j]/rho[i][j]; born2[i][j] = 6.0*c[i][j]; born3[i][j] = 8.0*d[i][j]; if (offset_flag) { double rexp = exp(-cut_lj[i][j]*rhoinv[i][j]); offset[i][j] = a[i][j]*rexp - c[i][j]/pow(cut_lj[i][j],6.0) + d[i][j]/pow(cut_lj[i][j],8.0); } else offset[i][j] = 0.0; cut_ljsq[j][i] = cut_ljsq[i][j]; a[j][i] = a[i][j]; c[j][i] = c[i][j]; d[j][i] = d[i][j]; rhoinv[j][i] = rhoinv[i][j]; sigma[j][i] = sigma[i][j]; born1[j][i] = born1[i][j]; born2[j][i] = born2[i][j]; born3[j][i] = born3[i][j]; offset[j][i] = offset[i][j]; // compute I,J contribution to long-range tail correction // count total # of atoms of type I and J via Allreduce if (tail_flag) { int *type = atom->type; int nlocal = atom->nlocal; double count[2],all[2]; count[0] = count[1] = 0.0; for (int k = 0; k < nlocal; k++) { if (type[k] == i) count[0] += 1.0; if (type[k] == j) count[1] += 1.0; } MPI_Allreduce(count,all,2,MPI_DOUBLE,MPI_SUM,world); double rho1 = rho[i][j]; double rho2 = rho1*rho1; double rho3 = rho2*rho1; double rc = cut_lj[i][j]; double rc2 = rc*rc; double rc3 = rc2*rc; double rc5 = rc3*rc2; etail_ij = 2.0*MY_PI*all[0]*all[1] * (a[i][j]*exp((sigma[i][j]-rc)/rho1)*rho1* (rc2 + 2.0*rho1*rc + 2.0*rho2) - c[i][j]/(3.0*rc3) + d[i][j]/(5.0*rc5)); ptail_ij = (-1/3.0)*2.0*MY_PI*all[0]*all[1] * (-a[i][j]*exp((sigma[i][j]-rc)/rho1) * (rc3 + 3.0*rho1*rc2 + 6.0*rho2*rc + 6.0*rho3) + 2.0*c[i][j]/rc3 - 8.0*d[i][j]/(5.0*rc5)); } return cut; } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairBornCoulLong::init_style() { if (!atom->q_flag) error->all(FLERR,"Pair style born/coul/long requires atom attribute q"); cut_coulsq = cut_coul * cut_coul; // insure use of KSpace long-range solver, set g_ewald if (force->kspace == NULL) error->all(FLERR,"Pair style is incompatible with KSpace style"); g_ewald = force->kspace->g_ewald; neighbor->request(this); } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairBornCoulLong::write_restart(FILE *fp) { write_restart_settings(fp); int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { fwrite(&setflag[i][j],sizeof(int),1,fp); if (setflag[i][j]) { fwrite(&a[i][j],sizeof(double),1,fp); fwrite(&rho[i][j],sizeof(double),1,fp); fwrite(&sigma[i][j],sizeof(double),1,fp); fwrite(&c[i][j],sizeof(double),1,fp); fwrite(&d[i][j],sizeof(double),1,fp); fwrite(&cut_lj[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairBornCoulLong::read_restart(FILE *fp) { read_restart_settings(fp); allocate(); int i,j; int me = comm->me; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp); MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world); if (setflag[i][j]) { if (me == 0) { fread(&a[i][j],sizeof(double),1,fp); fread(&rho[i][j],sizeof(double),1,fp); fread(&sigma[i][j],sizeof(double),1,fp); fread(&c[i][j],sizeof(double),1,fp); fread(&d[i][j],sizeof(double),1,fp); fread(&cut_lj[i][j],sizeof(double),1,fp); } MPI_Bcast(&a[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&rho[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&c[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&d[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_lj[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairBornCoulLong::write_restart_settings(FILE *fp) { fwrite(&cut_lj_global,sizeof(double),1,fp); fwrite(&cut_coul,sizeof(double),1,fp); fwrite(&offset_flag,sizeof(int),1,fp); fwrite(&mix_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairBornCoulLong::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&cut_lj_global,sizeof(double),1,fp); fread(&cut_coul,sizeof(double),1,fp); fread(&offset_flag,sizeof(int),1,fp); fread(&mix_flag,sizeof(int),1,fp); } MPI_Bcast(&cut_lj_global,1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_coul,1,MPI_DOUBLE,0,world); MPI_Bcast(&offset_flag,1,MPI_INT,0,world); MPI_Bcast(&mix_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- */ double PairBornCoulLong::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r2inv,r6inv,r,rexp,grij,expm2,t,erfc,prefactor; double forcecoul,forceborn,phicoul,phiborn; r2inv = 1.0/rsq; if (rsq < cut_coulsq) { r = sqrt(rsq); grij = g_ewald * r; expm2 = exp(-grij*grij); t = 1.0 / (1.0 + EWALD_P*grij); erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2; prefactor = force->qqrd2e * atom->q[i]*atom->q[j]/r; forcecoul = prefactor * (erfc + EWALD_F*grij*expm2); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor; } else forcecoul = 0.0; if (rsq < cut_ljsq[itype][jtype]) { r6inv = r2inv*r2inv*r2inv; r = sqrt(rsq); rexp = exp((sigma[itype][jtype]-r)*rhoinv[itype][jtype]); forceborn = born1[itype][jtype]*r*rexp - born2[itype][jtype]*r6inv + born3[itype][jtype]*r2inv*r6inv; } else forceborn = 0.0; fforce = (forcecoul + factor_lj*forceborn) * r2inv; double eng = 0.0; if (rsq < cut_coulsq) { phicoul = prefactor*erfc; if (factor_coul < 1.0) phicoul -= (1.0-factor_coul)*prefactor; eng += phicoul; } if (rsq < cut_ljsq[itype][jtype]) { phiborn = a[itype][jtype]*rexp - c[itype][jtype]*r6inv + d[itype][jtype]*r2inv*r6inv - offset[itype][jtype]; eng += factor_lj*phiborn; } return eng; } /* ---------------------------------------------------------------------- */ -void *PairBornCoulLong::extract(char *str, int &dim) +void *PairBornCoulLong::extract(const char *str, int &dim) { dim = 0; if (strcmp(str,"cut_coul") == 0) return (void *) &cut_coul; return NULL; } diff --git a/src/KSPACE/pair_born_coul_long.h b/src/KSPACE/pair_born_coul_long.h index ec60f2927..5debacd85 100644 --- a/src/KSPACE/pair_born_coul_long.h +++ b/src/KSPACE/pair_born_coul_long.h @@ -1,85 +1,85 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ #ifdef PAIR_CLASS PairStyle(born/coul/long,PairBornCoulLong) #else #ifndef LMP_PAIR_BORN_COUL_LONG_H #define LMP_PAIR_BORN_COUL_LONG_H #include "pair.h" namespace LAMMPS_NS { class PairBornCoulLong : public Pair { public: PairBornCoulLong(class LAMMPS *); virtual ~PairBornCoulLong(); virtual void compute(int, int); void settings(int, char **); void coeff(int, char **); void init_style(); double init_one(int, int); void write_restart(FILE *); void read_restart(FILE *); void write_restart_settings(FILE *); void read_restart_settings(FILE *); double single(int, int, int, int, double, double, double, double &); - void *extract(char *, int &); + void *extract(const char *, int &); protected: double cut_lj_global; double **cut_lj,**cut_ljsq; double cut_coul,cut_coulsq; double **a,**rho,**sigma,**c,**d; double **rhoinv,**born1,**born2,**born3,**offset; double g_ewald; void allocate(); }; } #endif #endif /* ERROR/WARNING messages: E: Illegal ... command Self-explanatory. Check the input script syntax and compare to the documentation for the command. You can use -echo screen as a command-line option when running LAMMPS to see the offending line. E: Incorrect args for pair coefficients Self-explanatory. Check the input script or data file. E: All pair coeffs are not set All pair coefficients must be set in the data file or by the pair_coeff command before running a simulation. E: Pair style born/coul/long requires atom attribute q An atom style that defines this attribute must be used. E: Pair style is incompatible with KSpace style If a pair style with a long-range Coulombic component is selected, then a kspace style must also be used. */ diff --git a/src/KSPACE/pair_buck_coul_long.cpp b/src/KSPACE/pair_buck_coul_long.cpp index a68029f36..f3fa4d50d 100644 --- a/src/KSPACE/pair_buck_coul_long.cpp +++ b/src/KSPACE/pair_buck_coul_long.cpp @@ -1,467 +1,467 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "pair_buck_coul_long.h" #include "atom.h" #include "comm.h" #include "force.h" #include "kspace.h" #include "neighbor.h" #include "neigh_list.h" #include "math_const.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace MathConst; #define EWALD_F 1.12837917 #define EWALD_P 0.3275911 #define A1 0.254829592 #define A2 -0.284496736 #define A3 1.421413741 #define A4 -1.453152027 #define A5 1.061405429 /* ---------------------------------------------------------------------- */ PairBuckCoulLong::PairBuckCoulLong(LAMMPS *lmp) : Pair(lmp) {} /* ---------------------------------------------------------------------- */ PairBuckCoulLong::~PairBuckCoulLong() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut_lj); memory->destroy(cut_ljsq); memory->destroy(a); memory->destroy(rho); memory->destroy(c); memory->destroy(rhoinv); memory->destroy(buck1); memory->destroy(buck2); memory->destroy(offset); } } /* ---------------------------------------------------------------------- */ void PairBuckCoulLong::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair; double rsq,r2inv,r6inv,forcecoul,forcebuck,factor_coul,factor_lj; double grij,expm2,prefactor,t,erfc; double r,rexp; int *ilist,*jlist,*numneigh,**firstneigh; evdwl = ecoul = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; double **x = atom->x; double **f = atom->f; double *q = atom->q; int *type = atom->type; int nlocal = atom->nlocal; double *special_coul = force->special_coul; double *special_lj = force->special_lj; int newton_pair = force->newton_pair; double qqrd2e = force->qqrd2e; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // loop over neighbors of my atoms for (ii = 0; ii < inum; ii++) { i = ilist[ii]; qtmp = q[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; factor_lj = special_lj[sbmask(j)]; factor_coul = special_coul[sbmask(j)]; j &= NEIGHMASK; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; jtype = type[j]; if (rsq < cutsq[itype][jtype]) { r2inv = 1.0/rsq; r = sqrt(rsq); if (rsq < cut_coulsq) { grij = g_ewald * r; expm2 = exp(-grij*grij); t = 1.0 / (1.0 + EWALD_P*grij); erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2; prefactor = qqrd2e * qtmp*q[j]/r; forcecoul = prefactor * (erfc + EWALD_F*grij*expm2); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor; } else forcecoul = 0.0; if (rsq < cut_ljsq[itype][jtype]) { r6inv = r2inv*r2inv*r2inv; rexp = exp(-r*rhoinv[itype][jtype]); forcebuck = buck1[itype][jtype]*r*rexp - buck2[itype][jtype]*r6inv; } else forcebuck = 0.0; fpair = (forcecoul + factor_lj*forcebuck) * r2inv; f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; if (newton_pair || j < nlocal) { f[j][0] -= delx*fpair; f[j][1] -= dely*fpair; f[j][2] -= delz*fpair; } if (eflag) { if (rsq < cut_coulsq) { ecoul = prefactor*erfc; if (factor_coul < 1.0) ecoul -= (1.0-factor_coul)*prefactor; } else ecoul = 0.0; if (rsq < cut_ljsq[itype][jtype]) { evdwl = a[itype][jtype]*rexp - c[itype][jtype]*r6inv - offset[itype][jtype]; evdwl *= factor_lj; } else evdwl = 0.0; } if (evflag) ev_tally(i,j,nlocal,newton_pair, evdwl,ecoul,fpair,delx,dely,delz); } } } if (vflag_fdotr) virial_fdotr_compute(); } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairBuckCoulLong::allocate() { allocated = 1; int n = atom->ntypes; memory->create(setflag,n+1,n+1,"pair:setflag"); for (int i = 1; i <= n; i++) for (int j = i; j <= n; j++) setflag[i][j] = 0; memory->create(cutsq,n+1,n+1,"pair:cutsq"); memory->create(cut_lj,n+1,n+1,"pair:cut_lj"); memory->create(cut_ljsq,n+1,n+1,"pair:cut_ljsq"); memory->create(a,n+1,n+1,"pair:a"); memory->create(rho,n+1,n+1,"pair:rho"); memory->create(c,n+1,n+1,"pair:c"); memory->create(rhoinv,n+1,n+1,"pair:rhoinv"); memory->create(buck1,n+1,n+1,"pair:buck1"); memory->create(buck2,n+1,n+1,"pair:buck2"); memory->create(offset,n+1,n+1,"pair:offset"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairBuckCoulLong::settings(int narg, char **arg) { if (narg < 1 || narg > 2) error->all(FLERR,"Illegal pair_style command"); cut_lj_global = force->numeric(arg[0]); if (narg == 1) cut_coul = cut_lj_global; else cut_coul = force->numeric(arg[1]); // reset cutoffs that have been explicitly set if (allocated) { int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i+1; j <= atom->ntypes; j++) if (setflag[i][j]) cut_lj[i][j] = cut_lj_global; } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairBuckCoulLong::coeff(int narg, char **arg) { if (narg < 5 || narg > 6) error->all(FLERR,"Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); double a_one = force->numeric(arg[2]); double rho_one = force->numeric(arg[3]); if (rho_one <= 0) error->all(FLERR,"Incorrect args for pair coefficients"); double c_one = force->numeric(arg[4]); double cut_lj_one = cut_lj_global; if (narg == 6) cut_lj_one = force->numeric(arg[5]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { a[i][j] = a_one; rho[i][j] = rho_one; c[i][j] = c_one; cut_lj[i][j] = cut_lj_one; setflag[i][j] = 1; count++; } } if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairBuckCoulLong::init_one(int i, int j) { if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set"); double cut = MAX(cut_lj[i][j],cut_coul); cut_ljsq[i][j] = cut_lj[i][j] * cut_lj[i][j]; rhoinv[i][j] = 1.0/rho[i][j]; buck1[i][j] = a[i][j]/rho[i][j]; buck2[i][j] = 6.0*c[i][j]; if (offset_flag) { double rexp = exp(-cut_lj[i][j]/rho[i][j]); offset[i][j] = a[i][j]*rexp - c[i][j]/pow(cut_lj[i][j],6.0); } else offset[i][j] = 0.0; cut_ljsq[j][i] = cut_ljsq[i][j]; a[j][i] = a[i][j]; c[j][i] = c[i][j]; rhoinv[j][i] = rhoinv[i][j]; buck1[j][i] = buck1[i][j]; buck2[j][i] = buck2[i][j]; offset[j][i] = offset[i][j]; // compute I,J contribution to long-range tail correction // count total # of atoms of type I and J via Allreduce if (tail_flag) { int *type = atom->type; int nlocal = atom->nlocal; double count[2],all[2]; count[0] = count[1] = 0.0; for (int k = 0; k < nlocal; k++) { if (type[k] == i) count[0] += 1.0; if (type[k] == j) count[1] += 1.0; } MPI_Allreduce(count,all,2,MPI_DOUBLE,MPI_SUM,world); double rho1 = rho[i][j]; double rho2 = rho1*rho1; double rho3 = rho2*rho1; double rc = cut_lj[i][j]; double rc2 = rc*rc; double rc3 = rc2*rc; etail_ij = 2.0*MY_PI*all[0]*all[1]* (a[i][j]*exp(-rc/rho1)*rho1*(rc2 + 2.0*rho1*rc + 2.0*rho2) - c[i][j]/(3.0*rc3)); ptail_ij = (-1/3.0)*2.0*MY_PI*all[0]*all[1]* (-a[i][j]*exp(-rc/rho1)* (rc3 + 3.0*rho1*rc2 + 6.0*rho2*rc + 6.0*rho3) + 2.0*c[i][j]/rc3); } return cut; } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairBuckCoulLong::init_style() { if (!atom->q_flag) error->all(FLERR,"Pair style buck/coul/long requires atom attribute q"); cut_coulsq = cut_coul * cut_coul; // insure use of KSpace long-range solver, set g_ewald if (force->kspace == NULL) error->all(FLERR,"Pair style is incompatible with KSpace style"); g_ewald = force->kspace->g_ewald; neighbor->request(this); } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairBuckCoulLong::write_restart(FILE *fp) { write_restart_settings(fp); int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { fwrite(&setflag[i][j],sizeof(int),1,fp); if (setflag[i][j]) { fwrite(&a[i][j],sizeof(double),1,fp); fwrite(&rho[i][j],sizeof(double),1,fp); fwrite(&c[i][j],sizeof(double),1,fp); fwrite(&cut_lj[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairBuckCoulLong::read_restart(FILE *fp) { read_restart_settings(fp); allocate(); int i,j; int me = comm->me; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp); MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world); if (setflag[i][j]) { if (me == 0) { fread(&a[i][j],sizeof(double),1,fp); fread(&rho[i][j],sizeof(double),1,fp); fread(&c[i][j],sizeof(double),1,fp); fread(&cut_lj[i][j],sizeof(double),1,fp); } MPI_Bcast(&a[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&rho[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&c[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_lj[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairBuckCoulLong::write_restart_settings(FILE *fp) { fwrite(&cut_lj_global,sizeof(double),1,fp); fwrite(&cut_coul,sizeof(double),1,fp); fwrite(&offset_flag,sizeof(int),1,fp); fwrite(&mix_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairBuckCoulLong::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&cut_lj_global,sizeof(double),1,fp); fread(&cut_coul,sizeof(double),1,fp); fread(&offset_flag,sizeof(int),1,fp); fread(&mix_flag,sizeof(int),1,fp); } MPI_Bcast(&cut_lj_global,1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_coul,1,MPI_DOUBLE,0,world); MPI_Bcast(&offset_flag,1,MPI_INT,0,world); MPI_Bcast(&mix_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- */ double PairBuckCoulLong::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r2inv,r6inv,r,rexp,grij,expm2,t,erfc,prefactor; double forcecoul,forcebuck,phicoul,phibuck; r2inv = 1.0/rsq; if (rsq < cut_coulsq) { r = sqrt(rsq); grij = g_ewald * r; expm2 = exp(-grij*grij); t = 1.0 / (1.0 + EWALD_P*grij); erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2; prefactor = force->qqrd2e * atom->q[i]*atom->q[j]/r; forcecoul = prefactor * (erfc + EWALD_F*grij*expm2); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor; } else forcecoul = 0.0; if (rsq < cut_ljsq[itype][jtype]) { r6inv = r2inv*r2inv*r2inv; r = sqrt(rsq); rexp = exp(-r*rhoinv[itype][jtype]); forcebuck = buck1[itype][jtype]*r*rexp - buck2[itype][jtype]*r6inv; } else forcebuck = 0.0; fforce = (forcecoul + factor_lj*forcebuck) * r2inv; double eng = 0.0; if (rsq < cut_coulsq) { phicoul = prefactor*erfc; if (factor_coul < 1.0) phicoul -= (1.0-factor_coul)*prefactor; eng += phicoul; } if (rsq < cut_ljsq[itype][jtype]) { phibuck = a[itype][jtype]*rexp - c[itype][jtype]*r6inv - offset[itype][jtype]; eng += factor_lj*phibuck; } return eng; } /* ---------------------------------------------------------------------- */ -void *PairBuckCoulLong::extract(char *str, int &dim) +void *PairBuckCoulLong::extract(const char *str, int &dim) { dim = 0; if (strcmp(str,"cut_coul") == 0) return (void *) &cut_coul; return NULL; } diff --git a/src/KSPACE/pair_buck_coul_long.h b/src/KSPACE/pair_buck_coul_long.h index 01bf65889..96de53c26 100644 --- a/src/KSPACE/pair_buck_coul_long.h +++ b/src/KSPACE/pair_buck_coul_long.h @@ -1,85 +1,85 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ #ifdef PAIR_CLASS PairStyle(buck/coul/long,PairBuckCoulLong) #else #ifndef LMP_PAIR_BUCK_COUL_LONG_H #define LMP_PAIR_BUCK_COUL_LONG_H #include "pair.h" namespace LAMMPS_NS { class PairBuckCoulLong : public Pair { public: PairBuckCoulLong(class LAMMPS *); virtual ~PairBuckCoulLong(); void compute(int, int); void settings(int, char **); void coeff(int, char **); void init_style(); double init_one(int, int); void write_restart(FILE *); void read_restart(FILE *); void write_restart_settings(FILE *); void read_restart_settings(FILE *); double single(int, int, int, int, double, double, double, double &); - void *extract(char *, int &); + void *extract(const char *, int &); protected: double cut_lj_global; double **cut_lj,**cut_ljsq; double cut_coul,cut_coulsq; double **a,**rho,**c; double **rhoinv,**buck1,**buck2,**offset; double g_ewald; void allocate(); }; } #endif #endif /* ERROR/WARNING messages: E: Illegal ... command Self-explanatory. Check the input script syntax and compare to the documentation for the command. You can use -echo screen as a command-line option when running LAMMPS to see the offending line. E: Incorrect args for pair coefficients Self-explanatory. Check the input script or data file. E: All pair coeffs are not set All pair coefficients must be set in the data file or by the pair_coeff command before running a simulation. E: Pair style buck/coul/long requires atom attribute q The atom style defined does not have these attributes. E: Pair style is incompatible with KSpace style If a pair style with a long-range Coulombic component is selected, then a kspace style must also be used. */ diff --git a/src/KSPACE/pair_coul_long.cpp b/src/KSPACE/pair_coul_long.cpp index 6a3f70b35..0ec33fb71 100644 --- a/src/KSPACE/pair_coul_long.cpp +++ b/src/KSPACE/pair_coul_long.cpp @@ -1,570 +1,570 @@ /* ---------------------------------------------------------------------- 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 author: Paul Crozier (SNL) ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "pair_coul_long.h" #include "atom.h" #include "comm.h" #include "force.h" #include "kspace.h" #include "neighbor.h" #include "neigh_list.h" #include "update.h" #include "integrate.h" #include "respa.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define EWALD_F 1.12837917 #define EWALD_P 0.3275911 #define A1 0.254829592 #define A2 -0.284496736 #define A3 1.421413741 #define A4 -1.453152027 #define A5 1.061405429 /* ---------------------------------------------------------------------- */ PairCoulLong::PairCoulLong(LAMMPS *lmp) : Pair(lmp) { ftable = NULL; } /* ---------------------------------------------------------------------- */ PairCoulLong::~PairCoulLong() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(scale); } if (ftable) free_tables(); } /* ---------------------------------------------------------------------- */ void PairCoulLong::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itable,itype,jtype; double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,ecoul,fpair; double fraction,table; double r,r2inv,forcecoul,factor_coul; double grij,expm2,prefactor,t,erfc; int *ilist,*jlist,*numneigh,**firstneigh; double rsq; ecoul = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; double **x = atom->x; double **f = atom->f; double *q = atom->q; int *type = atom->type; int nlocal = atom->nlocal; double *special_coul = force->special_coul; int newton_pair = force->newton_pair; double qqrd2e = force->qqrd2e; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // loop over neighbors of my atoms for (ii = 0; ii < inum; ii++) { i = ilist[ii]; qtmp = q[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; factor_coul = special_coul[sbmask(j)]; j &= NEIGHMASK; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; jtype = type[j]; if (rsq < cut_coulsq) { r2inv = 1.0/rsq; if (!ncoultablebits || rsq <= tabinnersq) { r = sqrt(rsq); grij = g_ewald * r; expm2 = exp(-grij*grij); t = 1.0 / (1.0 + EWALD_P*grij); erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2; prefactor = qqrd2e * scale[itype][jtype] * qtmp*q[j]/r; forcecoul = prefactor * (erfc + EWALD_F*grij*expm2); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor; } else { union_int_float_t rsq_lookup; rsq_lookup.f = rsq; itable = rsq_lookup.i & ncoulmask; itable >>= ncoulshiftbits; fraction = (rsq_lookup.f - rtable[itable]) * drtable[itable]; table = ftable[itable] + fraction*dftable[itable]; forcecoul = scale[itype][jtype] * qtmp*q[j] * table; if (factor_coul < 1.0) { table = ctable[itable] + fraction*dctable[itable]; prefactor = scale[itype][jtype] * qtmp*q[j] * table; forcecoul -= (1.0-factor_coul)*prefactor; } } fpair = forcecoul * r2inv; f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; if (newton_pair || j < nlocal) { f[j][0] -= delx*fpair; f[j][1] -= dely*fpair; f[j][2] -= delz*fpair; } if (eflag) { if (!ncoultablebits || rsq <= tabinnersq) ecoul = prefactor*erfc; else { table = etable[itable] + fraction*detable[itable]; ecoul = scale[itype][jtype] * qtmp*q[j] * table; } if (factor_coul < 1.0) ecoul -= (1.0-factor_coul)*prefactor; } if (evflag) ev_tally(i,j,nlocal,newton_pair, 0.0,ecoul,fpair,delx,dely,delz); } } } if (vflag_fdotr) virial_fdotr_compute(); } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairCoulLong::allocate() { allocated = 1; int n = atom->ntypes; memory->create(setflag,n+1,n+1,"pair:setflag"); for (int i = 1; i <= n; i++) for (int j = i; j <= n; j++) setflag[i][j] = 0; memory->create(cutsq,n+1,n+1,"pair:cutsq"); memory->create(scale,n+1,n+1,"pair:scale"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairCoulLong::settings(int narg, char **arg) { if (narg != 1) error->all(FLERR,"Illegal pair_style command"); cut_coul = force->numeric(arg[0]); } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairCoulLong::coeff(int narg, char **arg) { if (narg != 2) error->all(FLERR,"Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { scale[i][j] = 1.0; setflag[i][j] = 1; count++; } } if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairCoulLong::init_style() { if (!atom->q_flag) error->all(FLERR,"Pair style lj/cut/coul/long requires atom attribute q"); neighbor->request(this); cut_coulsq = cut_coul * cut_coul; // set & error check interior rRESPA cutoffs if (strstr(update->integrate_style,"respa") && ((Respa *) update->integrate)->level_inner >= 0) { cut_respa = ((Respa *) update->integrate)->cutoff; if (cut_coul < cut_respa[3]) error->all(FLERR,"Pair cutoff < Respa interior cutoff"); } else cut_respa = NULL; // insure use of KSpace long-range solver, set g_ewald if (force->kspace == NULL) error->all(FLERR,"Pair style is incompatible with KSpace style"); g_ewald = force->kspace->g_ewald; // setup force tables if (ncoultablebits) init_tables(); } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairCoulLong::init_one(int i, int j) { scale[j][i] = scale[i][j]; return cut_coul; } /* ---------------------------------------------------------------------- setup force tables used in compute routines ------------------------------------------------------------------------- */ void PairCoulLong::init_tables() { int masklo,maskhi; double r,grij,expm2,derfc,rsw; double qqrd2e = force->qqrd2e; tabinnersq = tabinner*tabinner; init_bitmap(tabinner,cut_coul,ncoultablebits, masklo,maskhi,ncoulmask,ncoulshiftbits); int ntable = 1; for (int i = 0; i < ncoultablebits; i++) ntable *= 2; // linear lookup tables of length N = 2^ncoultablebits // stored value = value at lower edge of bin // d values = delta from lower edge to upper edge of bin if (ftable) free_tables(); memory->create(rtable,ntable,"pair:rtable"); memory->create(ftable,ntable,"pair:ftable"); memory->create(ctable,ntable,"pair:ctable"); memory->create(etable,ntable,"pair:etable"); memory->create(drtable,ntable,"pair:drtable"); memory->create(dftable,ntable,"pair:dftable"); memory->create(dctable,ntable,"pair:dctable"); memory->create(detable,ntable,"pair:detable"); if (cut_respa == NULL) { vtable = ptable = dvtable = dptable = NULL; } else { memory->create(vtable,ntable,"pair:vtable"); memory->create(ptable,ntable,"pair:ptable"); memory->create(dvtable,ntable,"pair:dvtable"); memory->create(dptable,ntable,"pair:dptable"); } union_int_float_t rsq_lookup; union_int_float_t minrsq_lookup; int itablemin; minrsq_lookup.i = 0 << ncoulshiftbits; minrsq_lookup.i |= maskhi; for (int i = 0; i < ntable; i++) { rsq_lookup.i = i << ncoulshiftbits; rsq_lookup.i |= masklo; if (rsq_lookup.f < tabinnersq) { rsq_lookup.i = i << ncoulshiftbits; rsq_lookup.i |= maskhi; } r = sqrtf(rsq_lookup.f); grij = g_ewald * r; expm2 = exp(-grij*grij); derfc = erfc(grij); if (cut_respa == NULL) { rtable[i] = rsq_lookup.f; ftable[i] = qqrd2e/r * (derfc + EWALD_F*grij*expm2); ctable[i] = qqrd2e/r; etable[i] = qqrd2e/r * derfc; } else { rtable[i] = rsq_lookup.f; ftable[i] = qqrd2e/r * (derfc + EWALD_F*grij*expm2 - 1.0); ctable[i] = 0.0; etable[i] = qqrd2e/r * derfc; ptable[i] = qqrd2e/r; vtable[i] = qqrd2e/r * (derfc + EWALD_F*grij*expm2); if (rsq_lookup.f > cut_respa[2]*cut_respa[2]) { if (rsq_lookup.f < cut_respa[3]*cut_respa[3]) { rsw = (r - cut_respa[2])/(cut_respa[3] - cut_respa[2]); ftable[i] += qqrd2e/r * rsw*rsw*(3.0 - 2.0*rsw); ctable[i] = qqrd2e/r * rsw*rsw*(3.0 - 2.0*rsw); } else { ftable[i] = qqrd2e/r * (derfc + EWALD_F*grij*expm2); ctable[i] = qqrd2e/r; } } } minrsq_lookup.f = MIN(minrsq_lookup.f,rsq_lookup.f); } tabinnersq = minrsq_lookup.f; int ntablem1 = ntable - 1; for (int i = 0; i < ntablem1; i++) { drtable[i] = 1.0/(rtable[i+1] - rtable[i]); dftable[i] = ftable[i+1] - ftable[i]; dctable[i] = ctable[i+1] - ctable[i]; detable[i] = etable[i+1] - etable[i]; } if (cut_respa) { for (int i = 0; i < ntablem1; i++) { dvtable[i] = vtable[i+1] - vtable[i]; dptable[i] = ptable[i+1] - ptable[i]; } } // get the delta values for the last table entries // tables are connected periodically between 0 and ntablem1 drtable[ntablem1] = 1.0/(rtable[0] - rtable[ntablem1]); dftable[ntablem1] = ftable[0] - ftable[ntablem1]; dctable[ntablem1] = ctable[0] - ctable[ntablem1]; detable[ntablem1] = etable[0] - etable[ntablem1]; if (cut_respa) { dvtable[ntablem1] = vtable[0] - vtable[ntablem1]; dptable[ntablem1] = ptable[0] - ptable[ntablem1]; } // get the correct delta values at itablemax // smallest r is in bin itablemin // largest r is in bin itablemax, which is itablemin-1, // or ntablem1 if itablemin=0 // deltas at itablemax only needed if corresponding rsq < cut*cut // if so, compute deltas between rsq and cut*cut double f_tmp,c_tmp,e_tmp,p_tmp,v_tmp; itablemin = minrsq_lookup.i & ncoulmask; itablemin >>= ncoulshiftbits; int itablemax = itablemin - 1; if (itablemin == 0) itablemax = ntablem1; rsq_lookup.i = itablemax << ncoulshiftbits; rsq_lookup.i |= maskhi; if (rsq_lookup.f < cut_coulsq) { rsq_lookup.f = cut_coulsq; r = sqrtf(rsq_lookup.f); grij = g_ewald * r; expm2 = exp(-grij*grij); derfc = erfc(grij); if (cut_respa == NULL) { f_tmp = qqrd2e/r * (derfc + EWALD_F*grij*expm2); c_tmp = qqrd2e/r; e_tmp = qqrd2e/r * derfc; } else { f_tmp = qqrd2e/r * (derfc + EWALD_F*grij*expm2 - 1.0); c_tmp = 0.0; e_tmp = qqrd2e/r * derfc; p_tmp = qqrd2e/r; v_tmp = qqrd2e/r * (derfc + EWALD_F*grij*expm2); if (rsq_lookup.f > cut_respa[2]*cut_respa[2]) { if (rsq_lookup.f < cut_respa[3]*cut_respa[3]) { rsw = (r - cut_respa[2])/(cut_respa[3] - cut_respa[2]); f_tmp += qqrd2e/r * rsw*rsw*(3.0 - 2.0*rsw); c_tmp = qqrd2e/r * rsw*rsw*(3.0 - 2.0*rsw); } else { f_tmp = qqrd2e/r * (derfc + EWALD_F*grij*expm2); c_tmp = qqrd2e/r; } } } drtable[itablemax] = 1.0/(rsq_lookup.f - rtable[itablemax]); dftable[itablemax] = f_tmp - ftable[itablemax]; dctable[itablemax] = c_tmp - ctable[itablemax]; detable[itablemax] = e_tmp - etable[itablemax]; if (cut_respa) { dvtable[itablemax] = v_tmp - vtable[itablemax]; dptable[itablemax] = p_tmp - ptable[itablemax]; } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairCoulLong::write_restart(FILE *fp) { write_restart_settings(fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairCoulLong::read_restart(FILE *fp) { read_restart_settings(fp); allocate(); } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairCoulLong::write_restart_settings(FILE *fp) { fwrite(&cut_coul,sizeof(double),1,fp); fwrite(&offset_flag,sizeof(int),1,fp); fwrite(&mix_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairCoulLong::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&cut_coul,sizeof(double),1,fp); fread(&offset_flag,sizeof(int),1,fp); fread(&mix_flag,sizeof(int),1,fp); } MPI_Bcast(&cut_coul,1,MPI_DOUBLE,0,world); MPI_Bcast(&offset_flag,1,MPI_INT,0,world); MPI_Bcast(&mix_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- free memory for tables used in pair computations ------------------------------------------------------------------------- */ void PairCoulLong::free_tables() { memory->destroy(rtable); memory->destroy(drtable); memory->destroy(ftable); memory->destroy(dftable); memory->destroy(ctable); memory->destroy(dctable); memory->destroy(etable); memory->destroy(detable); memory->destroy(vtable); memory->destroy(dvtable); memory->destroy(ptable); memory->destroy(dptable); } /* ---------------------------------------------------------------------- */ double PairCoulLong::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r2inv,r,grij,expm2,t,erfc,prefactor; double fraction,table,forcecoul,phicoul; int itable; r2inv = 1.0/rsq; if (!ncoultablebits || rsq <= tabinnersq) { r = sqrt(rsq); grij = g_ewald * r; expm2 = exp(-grij*grij); t = 1.0 / (1.0 + EWALD_P*grij); erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2; prefactor = force->qqrd2e * atom->q[i]*atom->q[j]/r; forcecoul = prefactor * (erfc + EWALD_F*grij*expm2); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor; } else { union_int_float_t rsq_lookup; rsq_lookup.f = rsq; itable = rsq_lookup.i & ncoulmask; itable >>= ncoulshiftbits; fraction = (rsq_lookup.f - rtable[itable]) * drtable[itable]; table = ftable[itable] + fraction*dftable[itable]; forcecoul = atom->q[i]*atom->q[j] * table; if (factor_coul < 1.0) { table = ctable[itable] + fraction*dctable[itable]; prefactor = atom->q[i]*atom->q[j] * table; forcecoul -= (1.0-factor_coul)*prefactor; } } fforce = forcecoul * r2inv; if (!ncoultablebits || rsq <= tabinnersq) phicoul = prefactor*erfc; else { table = etable[itable] + fraction*detable[itable]; phicoul = atom->q[i]*atom->q[j] * table; } if (factor_coul < 1.0) phicoul -= (1.0-factor_coul)*prefactor; return phicoul; } /* ---------------------------------------------------------------------- */ -void *PairCoulLong::extract(char *str, int &dim) +void *PairCoulLong::extract(const char *str, int &dim) { if (strcmp(str,"cut_coul") == 0) { dim = 0; return (void *) &cut_coul; } if (strcmp(str,"scale") == 0) { dim = 2; return (void *) scale; } return NULL; } diff --git a/src/KSPACE/pair_coul_long.h b/src/KSPACE/pair_coul_long.h index d0920fda8..d67aea814 100644 --- a/src/KSPACE/pair_coul_long.h +++ b/src/KSPACE/pair_coul_long.h @@ -1,90 +1,90 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ #ifdef PAIR_CLASS PairStyle(coul/long,PairCoulLong) #else #ifndef LMP_PAIR_COUL_LONG_H #define LMP_PAIR_COUL_LONG_H #include "pair.h" namespace LAMMPS_NS { class PairCoulLong : public Pair { public: PairCoulLong(class LAMMPS *); ~PairCoulLong(); virtual void compute(int, int); virtual void settings(int, char **); void coeff(int, char **); virtual void init_style(); double init_one(int, int); void write_restart(FILE *); void read_restart(FILE *); virtual void write_restart_settings(FILE *); virtual void read_restart_settings(FILE *); virtual double single(int, int, int, int, double, double, double, double &); - void *extract(char *, int &); + void *extract(const char *, int &); protected: double cut_coul,cut_coulsq; double *cut_respa; double g_ewald; double **scale; double tabinnersq; double *rtable,*drtable,*ftable,*dftable,*ctable,*dctable; double *etable,*detable,*ptable,*dptable,*vtable,*dvtable; int ncoulshiftbits,ncoulmask; void allocate(); void init_tables(); void free_tables(); }; } #endif #endif /* ERROR/WARNING messages: E: Illegal ... command Self-explanatory. Check the input script syntax and compare to the documentation for the command. You can use -echo screen as a command-line option when running LAMMPS to see the offending line. E: Incorrect args for pair coefficients Self-explanatory. Check the input script or data file. E: Pair style lj/cut/coul/long requires atom attribute q The atom style defined does not have this attribute. E: Pair cutoff < Respa interior cutoff One or more pairwise cutoffs are too short to use with the specified rRESPA cutoffs. E: Pair style is incompatible with KSpace style If a pair style with a long-range Coulombic component is selected, then a kspace style must also be used. */ diff --git a/src/KSPACE/pair_lj_charmm_coul_long.cpp b/src/KSPACE/pair_lj_charmm_coul_long.cpp index 1ff61a5ec..bee8e33ca 100644 --- a/src/KSPACE/pair_lj_charmm_coul_long.cpp +++ b/src/KSPACE/pair_lj_charmm_coul_long.cpp @@ -1,1197 +1,1197 @@ /* ---------------------------------------------------------------------- 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 author: Paul Crozier (SNL) ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "pair_lj_charmm_coul_long.h" #include "atom.h" #include "comm.h" #include "force.h" #include "kspace.h" #include "update.h" #include "integrate.h" #include "respa.h" #include "neighbor.h" #include "neigh_list.h" #include "neigh_request.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; enum{GEOMETRIC,ARITHMETIC,SIXTHPOWER}; // same as in pair.cpp #define EWALD_F 1.12837917 #define EWALD_P 0.3275911 #define A1 0.254829592 #define A2 -0.284496736 #define A3 1.421413741 #define A4 -1.453152027 #define A5 1.061405429 /* ---------------------------------------------------------------------- */ PairLJCharmmCoulLong::PairLJCharmmCoulLong(LAMMPS *lmp) : Pair(lmp) { respa_enable = 1; ftable = NULL; implicit = 0; mix_flag = ARITHMETIC; } /* ---------------------------------------------------------------------- */ PairLJCharmmCoulLong::~PairLJCharmmCoulLong() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(epsilon); memory->destroy(sigma); memory->destroy(eps14); memory->destroy(sigma14); memory->destroy(lj1); memory->destroy(lj2); memory->destroy(lj3); memory->destroy(lj4); memory->destroy(lj14_1); memory->destroy(lj14_2); memory->destroy(lj14_3); memory->destroy(lj14_4); } if (ftable) free_tables(); } /* ---------------------------------------------------------------------- */ void PairLJCharmmCoulLong::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype,itable; double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair; double fraction,table; double r,r2inv,r6inv,forcecoul,forcelj,factor_coul,factor_lj; double grij,expm2,prefactor,t,erfc; double philj,switch1,switch2; int *ilist,*jlist,*numneigh,**firstneigh; double rsq; evdwl = ecoul = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; double **x = atom->x; double **f = atom->f; double *q = atom->q; int *type = atom->type; int nlocal = atom->nlocal; double *special_coul = force->special_coul; double *special_lj = force->special_lj; int newton_pair = force->newton_pair; double qqrd2e = force->qqrd2e; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // loop over neighbors of my atoms for (ii = 0; ii < inum; ii++) { i = ilist[ii]; qtmp = q[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; factor_lj = special_lj[sbmask(j)]; factor_coul = special_coul[sbmask(j)]; j &= NEIGHMASK; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; if (rsq < cut_bothsq) { r2inv = 1.0/rsq; if (rsq < cut_coulsq) { if (!ncoultablebits || rsq <= tabinnersq) { r = sqrt(rsq); grij = g_ewald * r; expm2 = exp(-grij*grij); t = 1.0 / (1.0 + EWALD_P*grij); erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2; prefactor = qqrd2e * qtmp*q[j]/r; forcecoul = prefactor * (erfc + EWALD_F*grij*expm2); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor; } else { union_int_float_t rsq_lookup; rsq_lookup.f = rsq; itable = rsq_lookup.i & ncoulmask; itable >>= ncoulshiftbits; fraction = (rsq_lookup.f - rtable[itable]) * drtable[itable]; table = ftable[itable] + fraction*dftable[itable]; forcecoul = qtmp*q[j] * table; if (factor_coul < 1.0) { table = ctable[itable] + fraction*dctable[itable]; prefactor = qtmp*q[j] * table; forcecoul -= (1.0-factor_coul)*prefactor; } } } else forcecoul = 0.0; if (rsq < cut_ljsq) { r6inv = r2inv*r2inv*r2inv; jtype = type[j]; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); if (rsq > cut_lj_innersq) { switch1 = (cut_ljsq-rsq) * (cut_ljsq-rsq) * (cut_ljsq + 2.0*rsq - 3.0*cut_lj_innersq) / denom_lj; switch2 = 12.0*rsq * (cut_ljsq-rsq) * (rsq-cut_lj_innersq) / denom_lj; philj = r6inv * (lj3[itype][jtype]*r6inv - lj4[itype][jtype]); forcelj = forcelj*switch1 + philj*switch2; } } else forcelj = 0.0; fpair = (forcecoul + factor_lj*forcelj) * r2inv; f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; if (newton_pair || j < nlocal) { f[j][0] -= delx*fpair; f[j][1] -= dely*fpair; f[j][2] -= delz*fpair; } if (eflag) { if (rsq < cut_coulsq) { if (!ncoultablebits || rsq <= tabinnersq) ecoul = prefactor*erfc; else { table = etable[itable] + fraction*detable[itable]; ecoul = qtmp*q[j] * table; } if (factor_coul < 1.0) ecoul -= (1.0-factor_coul)*prefactor; } else ecoul = 0.0; if (rsq < cut_ljsq) { evdwl = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]); if (rsq > cut_lj_innersq) { switch1 = (cut_ljsq-rsq) * (cut_ljsq-rsq) * (cut_ljsq + 2.0*rsq - 3.0*cut_lj_innersq) / denom_lj; evdwl *= switch1; } evdwl *= factor_lj; } else evdwl = 0.0; } if (evflag) ev_tally(i,j,nlocal,newton_pair, evdwl,ecoul,fpair,delx,dely,delz); } } } if (vflag_fdotr) virial_fdotr_compute(); } /* ---------------------------------------------------------------------- */ void PairLJCharmmCoulLong::compute_inner() { int i,j,ii,jj,inum,jnum,itype,jtype; double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,fpair; double rsq,r2inv,r6inv,forcecoul,forcelj,factor_coul,factor_lj; double rsw; int *ilist,*jlist,*numneigh,**firstneigh; double **x = atom->x; double **f = atom->f; double *q = atom->q; int *type = atom->type; int nlocal = atom->nlocal; double *special_coul = force->special_coul; double *special_lj = force->special_lj; int newton_pair = force->newton_pair; double qqrd2e = force->qqrd2e; inum = listinner->inum; ilist = listinner->ilist; numneigh = listinner->numneigh; firstneigh = listinner->firstneigh; double cut_out_on = cut_respa[0]; double cut_out_off = cut_respa[1]; double cut_out_diff = cut_out_off - cut_out_on; double cut_out_on_sq = cut_out_on*cut_out_on; double cut_out_off_sq = cut_out_off*cut_out_off; // loop over neighbors of my atoms for (ii = 0; ii < inum; ii++) { i = ilist[ii]; qtmp = q[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; factor_lj = special_lj[sbmask(j)]; factor_coul = special_coul[sbmask(j)]; j &= NEIGHMASK; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; if (rsq < cut_out_off_sq) { r2inv = 1.0/rsq; forcecoul = qqrd2e * qtmp*q[j]*sqrt(r2inv); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*forcecoul; r6inv = r2inv*r2inv*r2inv; jtype = type[j]; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); fpair = (forcecoul + factor_lj*forcelj) * r2inv; if (rsq > cut_out_on_sq) { rsw = (sqrt(rsq) - cut_out_on)/cut_out_diff; fpair *= 1.0 + rsw*rsw*(2.0*rsw-3.0); } f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; if (newton_pair || j < nlocal) { f[j][0] -= delx*fpair; f[j][1] -= dely*fpair; f[j][2] -= delz*fpair; } } } } } /* ---------------------------------------------------------------------- */ void PairLJCharmmCoulLong::compute_middle() { int i,j,ii,jj,inum,jnum,itype,jtype; double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,fpair; double rsq,r2inv,r6inv,forcecoul,forcelj,factor_coul,factor_lj; double philj,switch1,switch2; double rsw; int *ilist,*jlist,*numneigh,**firstneigh; double **x = atom->x; double **f = atom->f; double *q = atom->q; int *type = atom->type; int nlocal = atom->nlocal; double *special_coul = force->special_coul; double *special_lj = force->special_lj; int newton_pair = force->newton_pair; double qqrd2e = force->qqrd2e; inum = listmiddle->inum; ilist = listmiddle->ilist; numneigh = listmiddle->numneigh; firstneigh = listmiddle->firstneigh; double cut_in_off = cut_respa[0]; double cut_in_on = cut_respa[1]; double cut_out_on = cut_respa[2]; double cut_out_off = cut_respa[3]; double cut_in_diff = cut_in_on - cut_in_off; double cut_out_diff = cut_out_off - cut_out_on; double cut_in_off_sq = cut_in_off*cut_in_off; double cut_in_on_sq = cut_in_on*cut_in_on; double cut_out_on_sq = cut_out_on*cut_out_on; double cut_out_off_sq = cut_out_off*cut_out_off; // loop over neighbors of my atoms for (ii = 0; ii < inum; ii++) { i = ilist[ii]; qtmp = q[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; factor_lj = special_lj[sbmask(j)]; factor_coul = special_coul[sbmask(j)]; j &= NEIGHMASK; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; if (rsq < cut_out_off_sq && rsq > cut_in_off_sq) { r2inv = 1.0/rsq; forcecoul = qqrd2e * qtmp*q[j]*sqrt(r2inv); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*forcecoul; r6inv = r2inv*r2inv*r2inv; jtype = type[j]; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); if (rsq > cut_lj_innersq) { switch1 = (cut_ljsq-rsq) * (cut_ljsq-rsq) * (cut_ljsq + 2.0*rsq - 3.0*cut_lj_innersq) / denom_lj; switch2 = 12.0*rsq * (cut_ljsq-rsq) * (rsq-cut_lj_innersq) / denom_lj; philj = r6inv * (lj3[itype][jtype]*r6inv - lj4[itype][jtype]); forcelj = forcelj*switch1 + philj*switch2; } fpair = (forcecoul + factor_lj*forcelj) * r2inv; if (rsq < cut_in_on_sq) { rsw = (sqrt(rsq) - cut_in_off)/cut_in_diff; fpair *= rsw*rsw*(3.0 - 2.0*rsw); } if (rsq > cut_out_on_sq) { rsw = (sqrt(rsq) - cut_out_on)/cut_out_diff; fpair *= 1.0 + rsw*rsw*(2.0*rsw - 3.0); } f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; if (newton_pair || j < nlocal) { f[j][0] -= delx*fpair; f[j][1] -= dely*fpair; f[j][2] -= delz*fpair; } } } } } /* ---------------------------------------------------------------------- */ void PairLJCharmmCoulLong::compute_outer(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype,itable; double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair; double fraction,table; double r,r2inv,r6inv,forcecoul,forcelj,factor_coul,factor_lj; double grij,expm2,prefactor,t,erfc; double philj,switch1,switch2; double rsw; int *ilist,*jlist,*numneigh,**firstneigh; double rsq; evdwl = ecoul = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; double *q = atom->q; int *type = atom->type; int nlocal = atom->nlocal; double *special_coul = force->special_coul; double *special_lj = force->special_lj; int newton_pair = force->newton_pair; double qqrd2e = force->qqrd2e; inum = listouter->inum; ilist = listouter->ilist; numneigh = listouter->numneigh; firstneigh = listouter->firstneigh; double cut_in_off = cut_respa[2]; double cut_in_on = cut_respa[3]; double cut_in_diff = cut_in_on - cut_in_off; double cut_in_off_sq = cut_in_off*cut_in_off; double cut_in_on_sq = cut_in_on*cut_in_on; // loop over neighbors of my atoms for (ii = 0; ii < inum; ii++) { i = ilist[ii]; qtmp = q[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; factor_lj = special_lj[sbmask(j)]; factor_coul = special_coul[sbmask(j)]; j &= NEIGHMASK; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; jtype = type[j]; if (rsq < cut_bothsq) { r2inv = 1.0/rsq; if (rsq < cut_coulsq) { if (!ncoultablebits || rsq <= tabinnersq) { r = sqrt(rsq); grij = g_ewald * r; expm2 = exp(-grij*grij); t = 1.0 / (1.0 + EWALD_P*grij); erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2; prefactor = qqrd2e * qtmp*q[j]/r; forcecoul = prefactor * (erfc + EWALD_F*grij*expm2 - 1.0); if (rsq > cut_in_off_sq) { if (rsq < cut_in_on_sq) { rsw = (r - cut_in_off)/cut_in_diff; forcecoul += prefactor*rsw*rsw*(3.0 - 2.0*rsw); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor*rsw*rsw*(3.0 - 2.0*rsw); } else { forcecoul += prefactor; if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor; } } } else { union_int_float_t rsq_lookup; rsq_lookup.f = rsq; itable = rsq_lookup.i & ncoulmask; itable >>= ncoulshiftbits; fraction = (rsq_lookup.f - rtable[itable]) * drtable[itable]; table = ftable[itable] + fraction*dftable[itable]; forcecoul = qtmp*q[j] * table; if (factor_coul < 1.0) { table = ctable[itable] + fraction*dctable[itable]; prefactor = qtmp*q[j] * table; forcecoul -= (1.0-factor_coul)*prefactor; } } } else forcecoul = 0.0; if (rsq < cut_ljsq && rsq > cut_in_off_sq) { r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); if (rsq > cut_lj_innersq) { switch1 = (cut_ljsq-rsq) * (cut_ljsq-rsq) * (cut_ljsq + 2.0*rsq - 3.0*cut_lj_innersq) / denom_lj; switch2 = 12.0*rsq * (cut_ljsq-rsq) * (rsq-cut_lj_innersq) / denom_lj; philj = r6inv * (lj3[itype][jtype]*r6inv - lj4[itype][jtype]); forcelj = forcelj*switch1 + philj*switch2; } if (rsq < cut_in_on_sq) { rsw = (sqrt(rsq) - cut_in_off)/cut_in_diff; forcelj *= rsw*rsw*(3.0 - 2.0*rsw); } } else forcelj = 0.0; fpair = (forcecoul + forcelj) * r2inv; f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; if (newton_pair || j < nlocal) { f[j][0] -= delx*fpair; f[j][1] -= dely*fpair; f[j][2] -= delz*fpair; } if (eflag) { if (rsq < cut_coulsq) { if (!ncoultablebits || rsq <= tabinnersq) { ecoul = prefactor*erfc; if (factor_coul < 1.0) ecoul -= (1.0-factor_coul)*prefactor; } else { table = etable[itable] + fraction*detable[itable]; ecoul = qtmp*q[j] * table; if (factor_coul < 1.0) { table = ptable[itable] + fraction*dptable[itable]; prefactor = qtmp*q[j] * table; ecoul -= (1.0-factor_coul)*prefactor; } } } else ecoul = 0.0; if (rsq < cut_ljsq) { r6inv = r2inv*r2inv*r2inv; evdwl = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]); if (rsq > cut_lj_innersq) { switch1 = (cut_ljsq-rsq) * (cut_ljsq-rsq) * (cut_ljsq + 2.0*rsq - 3.0*cut_lj_innersq) / denom_lj; evdwl *= switch1; } evdwl *= factor_lj; } else evdwl = 0.0; } if (vflag) { if (rsq < cut_coulsq) { if (!ncoultablebits || rsq <= tabinnersq) { forcecoul = prefactor * (erfc + EWALD_F*grij*expm2); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor; } else { table = vtable[itable] + fraction*dvtable[itable]; forcecoul = qtmp*q[j] * table; if (factor_coul < 1.0) { table = ptable[itable] + fraction*dptable[itable]; prefactor = qtmp*q[j] * table; forcecoul -= (1.0-factor_coul)*prefactor; } } } else forcecoul = 0.0; if (rsq <= cut_in_off_sq) { r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); if (rsq > cut_lj_innersq) { switch1 = (cut_ljsq-rsq) * (cut_ljsq-rsq) * (cut_ljsq + 2.0*rsq - 3.0*cut_lj_innersq) / denom_lj; switch2 = 12.0*rsq * (cut_ljsq-rsq) * (rsq-cut_lj_innersq) / denom_lj; philj = r6inv * (lj3[itype][jtype]*r6inv - lj4[itype][jtype]); forcelj = forcelj*switch1 + philj*switch2; } } else if (rsq <= cut_in_on_sq) { forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); if (rsq > cut_lj_innersq) { switch1 = (cut_ljsq-rsq) * (cut_ljsq-rsq) * (cut_ljsq + 2.0*rsq - 3.0*cut_lj_innersq) / denom_lj; switch2 = 12.0*rsq * (cut_ljsq-rsq) * (rsq-cut_lj_innersq) / denom_lj; philj = r6inv * (lj3[itype][jtype]*r6inv - lj4[itype][jtype]); forcelj = forcelj*switch1 + philj*switch2; } } fpair = (forcecoul + factor_lj*forcelj) * r2inv; } if (evflag) ev_tally(i,j,nlocal,newton_pair, evdwl,ecoul,fpair,delx,dely,delz); } } } } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairLJCharmmCoulLong::allocate() { allocated = 1; int n = atom->ntypes; memory->create(setflag,n+1,n+1,"pair:setflag"); for (int i = 1; i <= n; i++) for (int j = i; j <= n; j++) setflag[i][j] = 0; memory->create(cutsq,n+1,n+1,"pair:cutsq"); memory->create(epsilon,n+1,n+1,"pair:epsilon"); memory->create(sigma,n+1,n+1,"pair:sigma"); memory->create(eps14,n+1,n+1,"pair:eps14"); memory->create(sigma14,n+1,n+1,"pair:sigma14"); memory->create(lj1,n+1,n+1,"pair:lj1"); memory->create(lj2,n+1,n+1,"pair:lj2"); memory->create(lj3,n+1,n+1,"pair:lj3"); memory->create(lj4,n+1,n+1,"pair:lj4"); memory->create(lj14_1,n+1,n+1,"pair:lj14_1"); memory->create(lj14_2,n+1,n+1,"pair:lj14_2"); memory->create(lj14_3,n+1,n+1,"pair:lj14_3"); memory->create(lj14_4,n+1,n+1,"pair:lj14_4"); } /* ---------------------------------------------------------------------- global settings unlike other pair styles, there are no individual pair settings that these override ------------------------------------------------------------------------- */ void PairLJCharmmCoulLong::settings(int narg, char **arg) { if (narg != 2 && narg != 3) error->all(FLERR,"Illegal pair_style command"); cut_lj_inner = force->numeric(arg[0]); cut_lj = force->numeric(arg[1]); if (narg == 2) cut_coul = cut_lj; else cut_coul = force->numeric(arg[2]); } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairLJCharmmCoulLong::coeff(int narg, char **arg) { if (narg != 4 && narg != 6) error->all(FLERR,"Illegal pair_coeff command"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(arg[2]); double sigma_one = force->numeric(arg[3]); double eps14_one = epsilon_one; double sigma14_one = sigma_one; if (narg == 6) { eps14_one = force->numeric(arg[4]); sigma14_one = force->numeric(arg[5]); } int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { epsilon[i][j] = epsilon_one; sigma[i][j] = sigma_one; eps14[i][j] = eps14_one; sigma14[i][j] = sigma14_one; setflag[i][j] = 1; count++; } } if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairLJCharmmCoulLong::init_style() { if (!atom->q_flag) error->all(FLERR,"Pair style lj/charmm/coul/long requires atom attribute q"); // request regular or rRESPA neighbor lists int irequest; if (update->whichflag == 1 && strstr(update->integrate_style,"respa")) { int respa = 0; if (((Respa *) update->integrate)->level_inner >= 0) respa = 1; if (((Respa *) update->integrate)->level_middle >= 0) respa = 2; if (respa == 0) irequest = neighbor->request(this); else if (respa == 1) { irequest = neighbor->request(this); neighbor->requests[irequest]->id = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respainner = 1; irequest = neighbor->request(this); neighbor->requests[irequest]->id = 3; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respaouter = 1; } else { irequest = neighbor->request(this); neighbor->requests[irequest]->id = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respainner = 1; irequest = neighbor->request(this); neighbor->requests[irequest]->id = 2; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respamiddle = 1; irequest = neighbor->request(this); neighbor->requests[irequest]->id = 3; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respaouter = 1; } } else irequest = neighbor->request(this); // require cut_lj_inner < cut_lj if (cut_lj_inner >= cut_lj) error->all(FLERR,"Pair inner cutoff >= Pair outer cutoff"); cut_lj_innersq = cut_lj_inner * cut_lj_inner; cut_ljsq = cut_lj * cut_lj; cut_coulsq = cut_coul * cut_coul; cut_bothsq = MAX(cut_ljsq,cut_coulsq); denom_lj = (cut_ljsq-cut_lj_innersq) * (cut_ljsq-cut_lj_innersq) * (cut_ljsq-cut_lj_innersq); // set & error check interior rRESPA cutoffs if (strstr(update->integrate_style,"respa") && ((Respa *) update->integrate)->level_inner >= 0) { cut_respa = ((Respa *) update->integrate)->cutoff; if (MIN(cut_lj,cut_coul) < cut_respa[3]) error->all(FLERR,"Pair cutoff < Respa interior cutoff"); if (cut_lj_inner < cut_respa[1]) error->all(FLERR,"Pair inner cutoff < Respa interior cutoff"); } else cut_respa = NULL; // insure use of KSpace long-range solver, set g_ewald if (force->kspace == NULL) error->all(FLERR,"Pair style is incompatible with KSpace style"); g_ewald = force->kspace->g_ewald; // setup force tables if (ncoultablebits) init_tables(); } /* ---------------------------------------------------------------------- neighbor callback to inform pair style of neighbor list to use regular or rRESPA ------------------------------------------------------------------------- */ void PairLJCharmmCoulLong::init_list(int id, NeighList *ptr) { if (id == 0) list = ptr; else if (id == 1) listinner = ptr; else if (id == 2) listmiddle = ptr; else if (id == 3) listouter = ptr; } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairLJCharmmCoulLong::init_one(int i, int j) { if (setflag[i][j] == 0) { epsilon[i][j] = mix_energy(epsilon[i][i],epsilon[j][j], sigma[i][i],sigma[j][j]); sigma[i][j] = mix_distance(sigma[i][i],sigma[j][j]); eps14[i][j] = mix_energy(eps14[i][i],eps14[j][j], sigma14[i][i],sigma14[j][j]); sigma14[i][j] = mix_distance(sigma14[i][i],sigma14[j][j]); } double cut = MAX(cut_lj,cut_coul); lj1[i][j] = 48.0 * epsilon[i][j] * pow(sigma[i][j],12.0); lj2[i][j] = 24.0 * epsilon[i][j] * pow(sigma[i][j],6.0); lj3[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],12.0); lj4[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],6.0); lj14_1[i][j] = 48.0 * eps14[i][j] * pow(sigma14[i][j],12.0); lj14_2[i][j] = 24.0 * eps14[i][j] * pow(sigma14[i][j],6.0); lj14_3[i][j] = 4.0 * eps14[i][j] * pow(sigma14[i][j],12.0); lj14_4[i][j] = 4.0 * eps14[i][j] * pow(sigma14[i][j],6.0); lj1[j][i] = lj1[i][j]; lj2[j][i] = lj2[i][j]; lj3[j][i] = lj3[i][j]; lj4[j][i] = lj4[i][j]; lj14_1[j][i] = lj14_1[i][j]; lj14_2[j][i] = lj14_2[i][j]; lj14_3[j][i] = lj14_3[i][j]; lj14_4[j][i] = lj14_4[i][j]; return cut; } /* ---------------------------------------------------------------------- setup force tables used in compute routines ------------------------------------------------------------------------- */ void PairLJCharmmCoulLong::init_tables() { int masklo,maskhi; double r,grij,expm2,derfc,rsw; double qqrd2e = force->qqrd2e; tabinnersq = tabinner*tabinner; init_bitmap(tabinner,cut_coul,ncoultablebits, masklo,maskhi,ncoulmask,ncoulshiftbits); int ntable = 1; for (int i = 0; i < ncoultablebits; i++) ntable *= 2; // linear lookup tables of length N = 2^ncoultablebits // stored value = value at lower edge of bin // d values = delta from lower edge to upper edge of bin if (ftable) free_tables(); memory->create(rtable,ntable,"pair:rtable"); memory->create(ftable,ntable,"pair:ftable"); memory->create(ctable,ntable,"pair:ctable"); memory->create(etable,ntable,"pair:etable"); memory->create(drtable,ntable,"pair:drtable"); memory->create(dftable,ntable,"pair:dftable"); memory->create(dctable,ntable,"pair:dctable"); memory->create(detable,ntable,"pair:detable"); if (cut_respa == NULL) { vtable = ptable = dvtable = dptable = NULL; } else { memory->create(vtable,ntable,"pair:vtable"); memory->create(ptable,ntable,"pair:ptable"); memory->create(dvtable,ntable,"pair:dvtable"); memory->create(dptable,ntable,"pair:dptable"); } union_int_float_t rsq_lookup; union_int_float_t minrsq_lookup; int itablemin; minrsq_lookup.i = 0 << ncoulshiftbits; minrsq_lookup.i |= maskhi; for (int i = 0; i < ntable; i++) { rsq_lookup.i = i << ncoulshiftbits; rsq_lookup.i |= masklo; if (rsq_lookup.f < tabinnersq) { rsq_lookup.i = i << ncoulshiftbits; rsq_lookup.i |= maskhi; } r = sqrtf(rsq_lookup.f); grij = g_ewald * r; expm2 = exp(-grij*grij); derfc = erfc(grij); if (cut_respa == NULL) { rtable[i] = rsq_lookup.f; ftable[i] = qqrd2e/r * (derfc + EWALD_F*grij*expm2); ctable[i] = qqrd2e/r; etable[i] = qqrd2e/r * derfc; } else { rtable[i] = rsq_lookup.f; ftable[i] = qqrd2e/r * (derfc + EWALD_F*grij*expm2 - 1.0); ctable[i] = 0.0; etable[i] = qqrd2e/r * derfc; ptable[i] = qqrd2e/r; vtable[i] = qqrd2e/r * (derfc + EWALD_F*grij*expm2); if (rsq_lookup.f > cut_respa[2]*cut_respa[2]) { if (rsq_lookup.f < cut_respa[3]*cut_respa[3]) { rsw = (r - cut_respa[2])/(cut_respa[3] - cut_respa[2]); ftable[i] += qqrd2e/r * rsw*rsw*(3.0 - 2.0*rsw); ctable[i] = qqrd2e/r * rsw*rsw*(3.0 - 2.0*rsw); } else { ftable[i] = qqrd2e/r * (derfc + EWALD_F*grij*expm2); ctable[i] = qqrd2e/r; } } } minrsq_lookup.f = MIN(minrsq_lookup.f,rsq_lookup.f); } tabinnersq = minrsq_lookup.f; int ntablem1 = ntable - 1; for (int i = 0; i < ntablem1; i++) { drtable[i] = 1.0/(rtable[i+1] - rtable[i]); dftable[i] = ftable[i+1] - ftable[i]; dctable[i] = ctable[i+1] - ctable[i]; detable[i] = etable[i+1] - etable[i]; } if (cut_respa) { for (int i = 0; i < ntablem1; i++) { dvtable[i] = vtable[i+1] - vtable[i]; dptable[i] = ptable[i+1] - ptable[i]; } } // get the delta values for the last table entries // tables are connected periodically between 0 and ntablem1 drtable[ntablem1] = 1.0/(rtable[0] - rtable[ntablem1]); dftable[ntablem1] = ftable[0] - ftable[ntablem1]; dctable[ntablem1] = ctable[0] - ctable[ntablem1]; detable[ntablem1] = etable[0] - etable[ntablem1]; if (cut_respa) { dvtable[ntablem1] = vtable[0] - vtable[ntablem1]; dptable[ntablem1] = ptable[0] - ptable[ntablem1]; } // get the correct delta values at itablemax // smallest r is in bin itablemin // largest r is in bin itablemax, which is itablemin-1, // or ntablem1 if itablemin=0 // deltas at itablemax only needed if corresponding rsq < cut*cut // if so, compute deltas between rsq and cut*cut double f_tmp,c_tmp,e_tmp,p_tmp,v_tmp; itablemin = minrsq_lookup.i & ncoulmask; itablemin >>= ncoulshiftbits; int itablemax = itablemin - 1; if (itablemin == 0) itablemax = ntablem1; rsq_lookup.i = itablemax << ncoulshiftbits; rsq_lookup.i |= maskhi; if (rsq_lookup.f < cut_coulsq) { rsq_lookup.f = cut_coulsq; r = sqrtf(rsq_lookup.f); grij = g_ewald * r; expm2 = exp(-grij*grij); derfc = erfc(grij); if (cut_respa == NULL) { f_tmp = qqrd2e/r * (derfc + EWALD_F*grij*expm2); c_tmp = qqrd2e/r; e_tmp = qqrd2e/r * derfc; } else { f_tmp = qqrd2e/r * (derfc + EWALD_F*grij*expm2 - 1.0); c_tmp = 0.0; e_tmp = qqrd2e/r * derfc; p_tmp = qqrd2e/r; v_tmp = qqrd2e/r * (derfc + EWALD_F*grij*expm2); if (rsq_lookup.f > cut_respa[2]*cut_respa[2]) { if (rsq_lookup.f < cut_respa[3]*cut_respa[3]) { rsw = (r - cut_respa[2])/(cut_respa[3] - cut_respa[2]); f_tmp += qqrd2e/r * rsw*rsw*(3.0 - 2.0*rsw); c_tmp = qqrd2e/r * rsw*rsw*(3.0 - 2.0*rsw); } else { f_tmp = qqrd2e/r * (derfc + EWALD_F*grij*expm2); c_tmp = qqrd2e/r; } } } drtable[itablemax] = 1.0/(rsq_lookup.f - rtable[itablemax]); dftable[itablemax] = f_tmp - ftable[itablemax]; dctable[itablemax] = c_tmp - ctable[itablemax]; detable[itablemax] = e_tmp - etable[itablemax]; if (cut_respa) { dvtable[itablemax] = v_tmp - vtable[itablemax]; dptable[itablemax] = p_tmp - ptable[itablemax]; } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJCharmmCoulLong::write_restart(FILE *fp) { write_restart_settings(fp); int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { fwrite(&setflag[i][j],sizeof(int),1,fp); if (setflag[i][j]) { fwrite(&epsilon[i][j],sizeof(double),1,fp); fwrite(&sigma[i][j],sizeof(double),1,fp); fwrite(&eps14[i][j],sizeof(double),1,fp); fwrite(&sigma14[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJCharmmCoulLong::read_restart(FILE *fp) { read_restart_settings(fp); allocate(); int i,j; int me = comm->me; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp); MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world); if (setflag[i][j]) { if (me == 0) { fread(&epsilon[i][j],sizeof(double),1,fp); fread(&sigma[i][j],sizeof(double),1,fp); fread(&eps14[i][j],sizeof(double),1,fp); fread(&sigma14[i][j],sizeof(double),1,fp); } MPI_Bcast(&epsilon[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&eps14[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&sigma14[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJCharmmCoulLong::write_restart_settings(FILE *fp) { fwrite(&cut_lj_inner,sizeof(double),1,fp); fwrite(&cut_lj,sizeof(double),1,fp); fwrite(&cut_coul,sizeof(double),1,fp); fwrite(&offset_flag,sizeof(int),1,fp); fwrite(&mix_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJCharmmCoulLong::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&cut_lj_inner,sizeof(double),1,fp); fread(&cut_lj,sizeof(double),1,fp); fread(&cut_coul,sizeof(double),1,fp); fread(&offset_flag,sizeof(int),1,fp); fread(&mix_flag,sizeof(int),1,fp); } MPI_Bcast(&cut_lj_inner,1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_lj,1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_coul,1,MPI_DOUBLE,0,world); MPI_Bcast(&offset_flag,1,MPI_INT,0,world); MPI_Bcast(&mix_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- free memory for tables used in pair computations ------------------------------------------------------------------------- */ void PairLJCharmmCoulLong::free_tables() { memory->destroy(rtable); memory->destroy(drtable); memory->destroy(ftable); memory->destroy(dftable); memory->destroy(ctable); memory->destroy(dctable); memory->destroy(etable); memory->destroy(detable); memory->destroy(vtable); memory->destroy(dvtable); memory->destroy(ptable); memory->destroy(dptable); } /* ---------------------------------------------------------------------- */ double PairLJCharmmCoulLong::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r2inv,r6inv,r,grij,expm2,t,erfc,prefactor; double switch1,switch2,fraction,table,forcecoul,forcelj,phicoul,philj; int itable; r2inv = 1.0/rsq; if (rsq < cut_coulsq) { if (!ncoultablebits || rsq <= tabinnersq) { r = sqrt(rsq); grij = g_ewald * r; expm2 = exp(-grij*grij); t = 1.0 / (1.0 + EWALD_P*grij); erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2; prefactor = force->qqrd2e * atom->q[i]*atom->q[j]/r; forcecoul = prefactor * (erfc + EWALD_F*grij*expm2); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor; } else { union_int_float_t rsq_lookup; rsq_lookup.f = rsq; itable = rsq_lookup.i & ncoulmask; itable >>= ncoulshiftbits; fraction = (rsq_lookup.f - rtable[itable]) * drtable[itable]; table = ftable[itable] + fraction*dftable[itable]; forcecoul = atom->q[i]*atom->q[j] * table; if (factor_coul < 1.0) { table = ctable[itable] + fraction*dctable[itable]; prefactor = atom->q[i]*atom->q[j] * table; forcecoul -= (1.0-factor_coul)*prefactor; } } } else forcecoul = 0.0; if (rsq < cut_ljsq) { r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); if (rsq > cut_lj_innersq) { switch1 = (cut_ljsq-rsq) * (cut_ljsq-rsq) * (cut_ljsq + 2.0*rsq - 3.0*cut_lj_innersq) / denom_lj; switch2 = 12.0*rsq * (cut_ljsq-rsq) * (rsq-cut_lj_innersq) / denom_lj; philj = r6inv * (lj3[itype][jtype]*r6inv - lj4[itype][jtype]); forcelj = forcelj*switch1 + philj*switch2; } } else forcelj = 0.0; fforce = (forcecoul + factor_lj*forcelj) * r2inv; double eng = 0.0; if (rsq < cut_coulsq) { if (!ncoultablebits || rsq <= tabinnersq) phicoul = prefactor*erfc; else { table = etable[itable] + fraction*detable[itable]; phicoul = atom->q[i]*atom->q[j] * table; } if (factor_coul < 1.0) phicoul -= (1.0-factor_coul)*prefactor; eng += phicoul; } if (rsq < cut_ljsq) { philj = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]); if (rsq > cut_lj_innersq) { switch1 = (cut_ljsq-rsq) * (cut_ljsq-rsq) * (cut_ljsq + 2.0*rsq - 3.0*cut_lj_innersq) / denom_lj; philj *= switch1; } eng += factor_lj*philj; } return eng; } /* ---------------------------------------------------------------------- */ -void *PairLJCharmmCoulLong::extract(char *str, int &dim) +void *PairLJCharmmCoulLong::extract(const char *str, int &dim) { dim = 2; if (strcmp(str,"lj14_1") == 0) return (void *) lj14_1; if (strcmp(str,"lj14_2") == 0) return (void *) lj14_2; if (strcmp(str,"lj14_3") == 0) return (void *) lj14_3; if (strcmp(str,"lj14_4") == 0) return (void *) lj14_4; dim = 0; if (strcmp(str,"implicit") == 0) return (void *) &implicit; if (strcmp(str,"cut_coul") == 0) return (void *) &cut_coul; return NULL; } diff --git a/src/KSPACE/pair_lj_charmm_coul_long.h b/src/KSPACE/pair_lj_charmm_coul_long.h index 09a0e1bc3..47cf005d7 100644 --- a/src/KSPACE/pair_lj_charmm_coul_long.h +++ b/src/KSPACE/pair_lj_charmm_coul_long.h @@ -1,112 +1,112 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ #ifdef PAIR_CLASS PairStyle(lj/charmm/coul/long,PairLJCharmmCoulLong) #else #ifndef LMP_PAIR_LJ_CHARMM_COUL_LONG_H #define LMP_PAIR_LJ_CHARMM_COUL_LONG_H #include "pair.h" namespace LAMMPS_NS { class PairLJCharmmCoulLong : public Pair { public: PairLJCharmmCoulLong(class LAMMPS *); virtual ~PairLJCharmmCoulLong(); virtual void compute(int, int); void settings(int, char **); void coeff(int, char **); void init_style(); void init_list(int, class NeighList *); double init_one(int, int); void write_restart(FILE *); void read_restart(FILE *); void write_restart_settings(FILE *); void read_restart_settings(FILE *); double single(int, int, int, int, double, double, double, double &); void compute_inner(); void compute_middle(); void compute_outer(int, int); - void *extract(char *, int &); + void *extract(const char *, int &); protected: int implicit; double cut_lj_inner,cut_lj; double cut_lj_innersq,cut_ljsq; double cut_coul,cut_coulsq; double cut_bothsq; double denom_lj; double **epsilon,**sigma,**eps14,**sigma14; double **lj1,**lj2,**lj3,**lj4,**offset; double **lj14_1,**lj14_2,**lj14_3,**lj14_4; double *cut_respa; double g_ewald; double tabinnersq; double *rtable,*drtable,*ftable,*dftable,*ctable,*dctable; double *etable,*detable,*ptable,*dptable,*vtable,*dvtable; int ncoulshiftbits,ncoulmask; void allocate(); void init_tables(); void free_tables(); }; } #endif #endif /* ERROR/WARNING messages: E: Illegal ... command Self-explanatory. Check the input script syntax and compare to the documentation for the command. You can use -echo screen as a command-line option when running LAMMPS to see the offending line. E: Incorrect args for pair coefficients Self-explanatory. Check the input script or data file. E: Pair style lj/charmm/coul/long requires atom attribute q The atom style defined does not have these attributes. E: Pair inner cutoff >= Pair outer cutoff The specified cutoffs for the pair style are inconsistent. E: Pair cutoff < Respa interior cutoff One or more pairwise cutoffs are too short to use with the specified rRESPA cutoffs. E: Pair inner cutoff < Respa interior cutoff One or more pairwise cutoffs are too short to use with the specified rRESPA cutoffs. E: Pair style is incompatible with KSpace style If a pair style with a long-range Coulombic component is selected, then a kspace style must also be used. */ diff --git a/src/KSPACE/pair_lj_cut_coul_long.cpp b/src/KSPACE/pair_lj_cut_coul_long.cpp index ff8fb1fd2..1b619974d 100644 --- a/src/KSPACE/pair_lj_cut_coul_long.cpp +++ b/src/KSPACE/pair_lj_cut_coul_long.cpp @@ -1,1130 +1,1130 @@ /* ---------------------------------------------------------------------- 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 author: Paul Crozier (SNL) ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "pair_lj_cut_coul_long.h" #include "atom.h" #include "comm.h" #include "force.h" #include "kspace.h" #include "update.h" #include "integrate.h" #include "respa.h" #include "neighbor.h" #include "neigh_list.h" #include "neigh_request.h" #include "math_const.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace MathConst; #define EWALD_F 1.12837917 #define EWALD_P 0.3275911 #define A1 0.254829592 #define A2 -0.284496736 #define A3 1.421413741 #define A4 -1.453152027 #define A5 1.061405429 /* ---------------------------------------------------------------------- */ PairLJCutCoulLong::PairLJCutCoulLong(LAMMPS *lmp) : Pair(lmp) { respa_enable = 1; ftable = NULL; } /* ---------------------------------------------------------------------- */ PairLJCutCoulLong::~PairLJCutCoulLong() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut_lj); memory->destroy(cut_ljsq); memory->destroy(epsilon); memory->destroy(sigma); memory->destroy(lj1); memory->destroy(lj2); memory->destroy(lj3); memory->destroy(lj4); memory->destroy(offset); } if (ftable) free_tables(); } /* ---------------------------------------------------------------------- */ void PairLJCutCoulLong::compute(int eflag, int vflag) { int i,ii,j,jj,inum,jnum,itype,jtype,itable; double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair; double fraction,table; double r,r2inv,r6inv,forcecoul,forcelj,factor_coul,factor_lj; double grij,expm2,prefactor,t,erfc; int *ilist,*jlist,*numneigh,**firstneigh; double rsq; evdwl = ecoul = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; double **x = atom->x; double **f = atom->f; double *q = atom->q; int *type = atom->type; int nlocal = atom->nlocal; double *special_coul = force->special_coul; double *special_lj = force->special_lj; int newton_pair = force->newton_pair; double qqrd2e = force->qqrd2e; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // loop over neighbors of my atoms for (ii = 0; ii < inum; ii++) { i = ilist[ii]; qtmp = q[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; factor_lj = special_lj[sbmask(j)]; factor_coul = special_coul[sbmask(j)]; j &= NEIGHMASK; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; jtype = type[j]; if (rsq < cutsq[itype][jtype]) { r2inv = 1.0/rsq; if (rsq < cut_coulsq) { if (!ncoultablebits || rsq <= tabinnersq) { r = sqrt(rsq); grij = g_ewald * r; expm2 = exp(-grij*grij); t = 1.0 / (1.0 + EWALD_P*grij); erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2; prefactor = qqrd2e * qtmp*q[j]/r; forcecoul = prefactor * (erfc + EWALD_F*grij*expm2); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor; } else { union_int_float_t rsq_lookup; rsq_lookup.f = rsq; itable = rsq_lookup.i & ncoulmask; itable >>= ncoulshiftbits; fraction = (rsq_lookup.f - rtable[itable]) * drtable[itable]; table = ftable[itable] + fraction*dftable[itable]; forcecoul = qtmp*q[j] * table; if (factor_coul < 1.0) { table = ctable[itable] + fraction*dctable[itable]; prefactor = qtmp*q[j] * table; forcecoul -= (1.0-factor_coul)*prefactor; } } } else forcecoul = 0.0; if (rsq < cut_ljsq[itype][jtype]) { r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); } else forcelj = 0.0; fpair = (forcecoul + factor_lj*forcelj) * r2inv; f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; if (newton_pair || j < nlocal) { f[j][0] -= delx*fpair; f[j][1] -= dely*fpair; f[j][2] -= delz*fpair; } if (eflag) { if (rsq < cut_coulsq) { if (!ncoultablebits || rsq <= tabinnersq) ecoul = prefactor*erfc; else { table = etable[itable] + fraction*detable[itable]; ecoul = qtmp*q[j] * table; } if (factor_coul < 1.0) ecoul -= (1.0-factor_coul)*prefactor; } else ecoul = 0.0; if (rsq < cut_ljsq[itype][jtype]) { evdwl = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]) - offset[itype][jtype]; evdwl *= factor_lj; } else evdwl = 0.0; } if (evflag) ev_tally(i,j,nlocal,newton_pair, evdwl,ecoul,fpair,delx,dely,delz); } } } if (vflag_fdotr) virial_fdotr_compute(); } /* ---------------------------------------------------------------------- */ void PairLJCutCoulLong::compute_inner() { int i,j,ii,jj,inum,jnum,itype,jtype; double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,fpair; double rsq,r2inv,r6inv,forcecoul,forcelj,factor_coul,factor_lj; double rsw; int *ilist,*jlist,*numneigh,**firstneigh; double **x = atom->x; double **f = atom->f; double *q = atom->q; int *type = atom->type; int nlocal = atom->nlocal; double *special_coul = force->special_coul; double *special_lj = force->special_lj; int newton_pair = force->newton_pair; double qqrd2e = force->qqrd2e; inum = listinner->inum; ilist = listinner->ilist; numneigh = listinner->numneigh; firstneigh = listinner->firstneigh; double cut_out_on = cut_respa[0]; double cut_out_off = cut_respa[1]; double cut_out_diff = cut_out_off - cut_out_on; double cut_out_on_sq = cut_out_on*cut_out_on; double cut_out_off_sq = cut_out_off*cut_out_off; // loop over neighbors of my atoms for (ii = 0; ii < inum; ii++) { i = ilist[ii]; qtmp = q[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; factor_lj = special_lj[sbmask(j)]; factor_coul = special_coul[sbmask(j)]; j &= NEIGHMASK; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; if (rsq < cut_out_off_sq) { r2inv = 1.0/rsq; forcecoul = qqrd2e * qtmp*q[j]*sqrt(r2inv); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*forcecoul; jtype = type[j]; if (rsq < cut_ljsq[itype][jtype]) { r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); } else forcelj = 0.0; fpair = (forcecoul + factor_lj*forcelj) * r2inv; if (rsq > cut_out_on_sq) { rsw = (sqrt(rsq) - cut_out_on)/cut_out_diff; fpair *= 1.0 + rsw*rsw*(2.0*rsw-3.0); } f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; if (newton_pair || j < nlocal) { f[j][0] -= delx*fpair; f[j][1] -= dely*fpair; f[j][2] -= delz*fpair; } } } } } /* ---------------------------------------------------------------------- */ void PairLJCutCoulLong::compute_middle() { int i,j,ii,jj,inum,jnum,itype,jtype; double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,fpair; double rsq,r2inv,r6inv,forcecoul,forcelj,factor_coul,factor_lj; double rsw; int *ilist,*jlist,*numneigh,**firstneigh; double **x = atom->x; double **f = atom->f; double *q = atom->q; int *type = atom->type; int nlocal = atom->nlocal; double *special_coul = force->special_coul; double *special_lj = force->special_lj; int newton_pair = force->newton_pair; double qqrd2e = force->qqrd2e; inum = listmiddle->inum; ilist = listmiddle->ilist; numneigh = listmiddle->numneigh; firstneigh = listmiddle->firstneigh; double cut_in_off = cut_respa[0]; double cut_in_on = cut_respa[1]; double cut_out_on = cut_respa[2]; double cut_out_off = cut_respa[3]; double cut_in_diff = cut_in_on - cut_in_off; double cut_out_diff = cut_out_off - cut_out_on; double cut_in_off_sq = cut_in_off*cut_in_off; double cut_in_on_sq = cut_in_on*cut_in_on; double cut_out_on_sq = cut_out_on*cut_out_on; double cut_out_off_sq = cut_out_off*cut_out_off; // loop over neighbors of my atoms for (ii = 0; ii < inum; ii++) { i = ilist[ii]; qtmp = q[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; factor_lj = special_lj[sbmask(j)]; factor_coul = special_coul[sbmask(j)]; j &= NEIGHMASK; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; if (rsq < cut_out_off_sq && rsq > cut_in_off_sq) { r2inv = 1.0/rsq; forcecoul = qqrd2e * qtmp*q[j]*sqrt(r2inv); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*forcecoul; jtype = type[j]; if (rsq < cut_ljsq[itype][jtype]) { r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); } else forcelj = 0.0; fpair = (forcecoul + factor_lj*forcelj) * r2inv; if (rsq < cut_in_on_sq) { rsw = (sqrt(rsq) - cut_in_off)/cut_in_diff; fpair *= rsw*rsw*(3.0 - 2.0*rsw); } if (rsq > cut_out_on_sq) { rsw = (sqrt(rsq) - cut_out_on)/cut_out_diff; fpair *= 1.0 + rsw*rsw*(2.0*rsw - 3.0); } f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; if (newton_pair || j < nlocal) { f[j][0] -= delx*fpair; f[j][1] -= dely*fpair; f[j][2] -= delz*fpair; } } } } } /* ---------------------------------------------------------------------- */ void PairLJCutCoulLong::compute_outer(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype,itable; double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair; double fraction,table; double r,r2inv,r6inv,forcecoul,forcelj,factor_coul,factor_lj; double grij,expm2,prefactor,t,erfc; double rsw; int *ilist,*jlist,*numneigh,**firstneigh; double rsq; evdwl = ecoul = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; double *q = atom->q; int *type = atom->type; int nlocal = atom->nlocal; double *special_coul = force->special_coul; double *special_lj = force->special_lj; int newton_pair = force->newton_pair; double qqrd2e = force->qqrd2e; inum = listouter->inum; ilist = listouter->ilist; numneigh = listouter->numneigh; firstneigh = listouter->firstneigh; double cut_in_off = cut_respa[2]; double cut_in_on = cut_respa[3]; double cut_in_diff = cut_in_on - cut_in_off; double cut_in_off_sq = cut_in_off*cut_in_off; double cut_in_on_sq = cut_in_on*cut_in_on; // loop over neighbors of my atoms for (ii = 0; ii < inum; ii++) { i = ilist[ii]; qtmp = q[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; factor_lj = special_lj[sbmask(j)]; factor_coul = special_coul[sbmask(j)]; j &= NEIGHMASK; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; jtype = type[j]; if (rsq < cutsq[itype][jtype]) { r2inv = 1.0/rsq; if (rsq < cut_coulsq) { if (!ncoultablebits || rsq <= tabinnersq) { r = sqrt(rsq); grij = g_ewald * r; expm2 = exp(-grij*grij); t = 1.0 / (1.0 + EWALD_P*grij); erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2; prefactor = qqrd2e * qtmp*q[j]/r; forcecoul = prefactor * (erfc + EWALD_F*grij*expm2 - 1.0); if (rsq > cut_in_off_sq) { if (rsq < cut_in_on_sq) { rsw = (r - cut_in_off)/cut_in_diff; forcecoul += prefactor*rsw*rsw*(3.0 - 2.0*rsw); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor*rsw*rsw*(3.0 - 2.0*rsw); } else { forcecoul += prefactor; if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor; } } } else { union_int_float_t rsq_lookup; rsq_lookup.f = rsq; itable = rsq_lookup.i & ncoulmask; itable >>= ncoulshiftbits; fraction = (rsq_lookup.f - rtable[itable]) * drtable[itable]; table = ftable[itable] + fraction*dftable[itable]; forcecoul = qtmp*q[j] * table; if (factor_coul < 1.0) { table = ctable[itable] + fraction*dctable[itable]; prefactor = qtmp*q[j] * table; forcecoul -= (1.0-factor_coul)*prefactor; } } } else forcecoul = 0.0; if (rsq < cut_ljsq[itype][jtype] && rsq > cut_in_off_sq) { r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); if (rsq < cut_in_on_sq) { rsw = (sqrt(rsq) - cut_in_off)/cut_in_diff; forcelj *= rsw*rsw*(3.0 - 2.0*rsw); } } else forcelj = 0.0; fpair = (forcecoul + forcelj) * r2inv; f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; if (newton_pair || j < nlocal) { f[j][0] -= delx*fpair; f[j][1] -= dely*fpair; f[j][2] -= delz*fpair; } if (eflag) { if (rsq < cut_coulsq) { if (!ncoultablebits || rsq <= tabinnersq) { ecoul = prefactor*erfc; if (factor_coul < 1.0) ecoul -= (1.0-factor_coul)*prefactor; } else { table = etable[itable] + fraction*detable[itable]; ecoul = qtmp*q[j] * table; if (factor_coul < 1.0) { table = ptable[itable] + fraction*dptable[itable]; prefactor = qtmp*q[j] * table; ecoul -= (1.0-factor_coul)*prefactor; } } } else ecoul = 0.0; if (rsq < cut_ljsq[itype][jtype]) { r6inv = r2inv*r2inv*r2inv; evdwl = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]) - offset[itype][jtype]; evdwl *= factor_lj; } else evdwl = 0.0; } if (vflag) { if (rsq < cut_coulsq) { if (!ncoultablebits || rsq <= tabinnersq) { forcecoul = prefactor * (erfc + EWALD_F*grij*expm2); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor; } else { table = vtable[itable] + fraction*dvtable[itable]; forcecoul = qtmp*q[j] * table; if (factor_coul < 1.0) { table = ptable[itable] + fraction*dptable[itable]; prefactor = qtmp*q[j] * table; forcecoul -= (1.0-factor_coul)*prefactor; } } } else forcecoul = 0.0; if (rsq <= cut_in_off_sq) { r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); } else if (rsq <= cut_in_on_sq) forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); fpair = (forcecoul + factor_lj*forcelj) * r2inv; } if (evflag) ev_tally(i,j,nlocal,newton_pair, evdwl,ecoul,fpair,delx,dely,delz); } } } } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairLJCutCoulLong::allocate() { allocated = 1; int n = atom->ntypes; memory->create(setflag,n+1,n+1,"pair:setflag"); for (int i = 1; i <= n; i++) for (int j = i; j <= n; j++) setflag[i][j] = 0; memory->create(cutsq,n+1,n+1,"pair:cutsq"); memory->create(cut_lj,n+1,n+1,"pair:cut_lj"); memory->create(cut_ljsq,n+1,n+1,"pair:cut_ljsq"); memory->create(epsilon,n+1,n+1,"pair:epsilon"); memory->create(sigma,n+1,n+1,"pair:sigma"); memory->create(lj1,n+1,n+1,"pair:lj1"); memory->create(lj2,n+1,n+1,"pair:lj2"); memory->create(lj3,n+1,n+1,"pair:lj3"); memory->create(lj4,n+1,n+1,"pair:lj4"); memory->create(offset,n+1,n+1,"pair:offset"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairLJCutCoulLong::settings(int narg, char **arg) { if (narg < 1 || narg > 2) error->all(FLERR,"Illegal pair_style command"); cut_lj_global = force->numeric(arg[0]); if (narg == 1) cut_coul = cut_lj_global; else cut_coul = force->numeric(arg[1]); // reset cutoffs that have been explicitly set if (allocated) { int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i+1; j <= atom->ntypes; j++) if (setflag[i][j]) cut_lj[i][j] = cut_lj_global; } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairLJCutCoulLong::coeff(int narg, char **arg) { if (narg < 4 || narg > 5) error->all(FLERR,"Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(arg[2]); double sigma_one = force->numeric(arg[3]); double cut_lj_one = cut_lj_global; if (narg == 5) cut_lj_one = force->numeric(arg[4]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { epsilon[i][j] = epsilon_one; sigma[i][j] = sigma_one; cut_lj[i][j] = cut_lj_one; setflag[i][j] = 1; count++; } } if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairLJCutCoulLong::init_style() { if (!atom->q_flag) error->all(FLERR,"Pair style lj/cut/coul/long requires atom attribute q"); // request regular or rRESPA neighbor lists int irequest; if (update->whichflag == 1 && strstr(update->integrate_style,"respa")) { int respa = 0; if (((Respa *) update->integrate)->level_inner >= 0) respa = 1; if (((Respa *) update->integrate)->level_middle >= 0) respa = 2; if (respa == 0) irequest = neighbor->request(this); else if (respa == 1) { irequest = neighbor->request(this); neighbor->requests[irequest]->id = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respainner = 1; irequest = neighbor->request(this); neighbor->requests[irequest]->id = 3; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respaouter = 1; } else { irequest = neighbor->request(this); neighbor->requests[irequest]->id = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respainner = 1; irequest = neighbor->request(this); neighbor->requests[irequest]->id = 2; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respamiddle = 1; irequest = neighbor->request(this); neighbor->requests[irequest]->id = 3; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respaouter = 1; } } else irequest = neighbor->request(this); cut_coulsq = cut_coul * cut_coul; // set rRESPA cutoffs if (strstr(update->integrate_style,"respa") && ((Respa *) update->integrate)->level_inner >= 0) cut_respa = ((Respa *) update->integrate)->cutoff; else cut_respa = NULL; // insure use of KSpace long-range solver, set g_ewald if (force->kspace == NULL) error->all(FLERR,"Pair style is incompatible with KSpace style"); g_ewald = force->kspace->g_ewald; // setup force tables if (ncoultablebits) init_tables(); } /* ---------------------------------------------------------------------- neighbor callback to inform pair style of neighbor list to use regular or rRESPA ------------------------------------------------------------------------- */ void PairLJCutCoulLong::init_list(int id, NeighList *ptr) { if (id == 0) list = ptr; else if (id == 1) listinner = ptr; else if (id == 2) listmiddle = ptr; else if (id == 3) listouter = ptr; } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairLJCutCoulLong::init_one(int i, int j) { if (setflag[i][j] == 0) { epsilon[i][j] = mix_energy(epsilon[i][i],epsilon[j][j], sigma[i][i],sigma[j][j]); sigma[i][j] = mix_distance(sigma[i][i],sigma[j][j]); cut_lj[i][j] = mix_distance(cut_lj[i][i],cut_lj[j][j]); } double cut = MAX(cut_lj[i][j],cut_coul); cut_ljsq[i][j] = cut_lj[i][j] * cut_lj[i][j]; lj1[i][j] = 48.0 * epsilon[i][j] * pow(sigma[i][j],12.0); lj2[i][j] = 24.0 * epsilon[i][j] * pow(sigma[i][j],6.0); lj3[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],12.0); lj4[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],6.0); if (offset_flag) { double ratio = sigma[i][j] / cut_lj[i][j]; offset[i][j] = 4.0 * epsilon[i][j] * (pow(ratio,12.0) - pow(ratio,6.0)); } else offset[i][j] = 0.0; cut_ljsq[j][i] = cut_ljsq[i][j]; lj1[j][i] = lj1[i][j]; lj2[j][i] = lj2[i][j]; lj3[j][i] = lj3[i][j]; lj4[j][i] = lj4[i][j]; offset[j][i] = offset[i][j]; // check interior rRESPA cutoff if (cut_respa && MIN(cut_lj[i][j],cut_coul) < cut_respa[3]) error->all(FLERR,"Pair cutoff < Respa interior cutoff"); // compute I,J contribution to long-range tail correction // count total # of atoms of type I and J via Allreduce if (tail_flag) { int *type = atom->type; int nlocal = atom->nlocal; double count[2],all[2]; count[0] = count[1] = 0.0; for (int k = 0; k < nlocal; k++) { if (type[k] == i) count[0] += 1.0; if (type[k] == j) count[1] += 1.0; } MPI_Allreduce(count,all,2,MPI_DOUBLE,MPI_SUM,world); double sig2 = sigma[i][j]*sigma[i][j]; double sig6 = sig2*sig2*sig2; double rc3 = cut_lj[i][j]*cut_lj[i][j]*cut_lj[i][j]; double rc6 = rc3*rc3; double rc9 = rc3*rc6; etail_ij = 8.0*MY_PI*all[0]*all[1]*epsilon[i][j] * sig6 * (sig6 - 3.0*rc6) / (9.0*rc9); ptail_ij = 16.0*MY_PI*all[0]*all[1]*epsilon[i][j] * sig6 * (2.0*sig6 - 3.0*rc6) / (9.0*rc9); } return cut; } /* ---------------------------------------------------------------------- setup force tables used in compute routines ------------------------------------------------------------------------- */ void PairLJCutCoulLong::init_tables() { int masklo,maskhi; double r,grij,expm2,derfc,rsw; double qqrd2e = force->qqrd2e; tabinnersq = tabinner*tabinner; init_bitmap(tabinner,cut_coul,ncoultablebits, masklo,maskhi,ncoulmask,ncoulshiftbits); int ntable = 1; for (int i = 0; i < ncoultablebits; i++) ntable *= 2; // linear lookup tables of length N = 2^ncoultablebits // stored value = value at lower edge of bin // d values = delta from lower edge to upper edge of bin if (ftable) free_tables(); memory->create(rtable,ntable,"pair:rtable"); memory->create(ftable,ntable,"pair:ftable"); memory->create(ctable,ntable,"pair:ctable"); memory->create(etable,ntable,"pair:etable"); memory->create(drtable,ntable,"pair:drtable"); memory->create(dftable,ntable,"pair:dftable"); memory->create(dctable,ntable,"pair:dctable"); memory->create(detable,ntable,"pair:detable"); if (cut_respa == NULL) { vtable = ptable = dvtable = dptable = NULL; } else { memory->create(vtable,ntable*sizeof(double),"pair:vtable"); memory->create(ptable,ntable*sizeof(double),"pair:ptable"); memory->create(dvtable,ntable*sizeof(double),"pair:dvtable"); memory->create(dptable,ntable*sizeof(double),"pair:dptable"); } union_int_float_t rsq_lookup; union_int_float_t minrsq_lookup; int itablemin; minrsq_lookup.i = 0 << ncoulshiftbits; minrsq_lookup.i |= maskhi; for (int i = 0; i < ntable; i++) { rsq_lookup.i = i << ncoulshiftbits; rsq_lookup.i |= masklo; if (rsq_lookup.f < tabinnersq) { rsq_lookup.i = i << ncoulshiftbits; rsq_lookup.i |= maskhi; } r = sqrtf(rsq_lookup.f); grij = g_ewald * r; expm2 = exp(-grij*grij); derfc = erfc(grij); if (cut_respa == NULL) { rtable[i] = rsq_lookup.f; ftable[i] = qqrd2e/r * (derfc + EWALD_F*grij*expm2); ctable[i] = qqrd2e/r; etable[i] = qqrd2e/r * derfc; } else { rtable[i] = rsq_lookup.f; ftable[i] = qqrd2e/r * (derfc + EWALD_F*grij*expm2 - 1.0); ctable[i] = 0.0; etable[i] = qqrd2e/r * derfc; ptable[i] = qqrd2e/r; vtable[i] = qqrd2e/r * (derfc + EWALD_F*grij*expm2); if (rsq_lookup.f > cut_respa[2]*cut_respa[2]) { if (rsq_lookup.f < cut_respa[3]*cut_respa[3]) { rsw = (r - cut_respa[2])/(cut_respa[3] - cut_respa[2]); ftable[i] += qqrd2e/r * rsw*rsw*(3.0 - 2.0*rsw); ctable[i] = qqrd2e/r * rsw*rsw*(3.0 - 2.0*rsw); } else { ftable[i] = qqrd2e/r * (derfc + EWALD_F*grij*expm2); ctable[i] = qqrd2e/r; } } } minrsq_lookup.f = MIN(minrsq_lookup.f,rsq_lookup.f); } tabinnersq = minrsq_lookup.f; int ntablem1 = ntable - 1; for (int i = 0; i < ntablem1; i++) { drtable[i] = 1.0/(rtable[i+1] - rtable[i]); dftable[i] = ftable[i+1] - ftable[i]; dctable[i] = ctable[i+1] - ctable[i]; detable[i] = etable[i+1] - etable[i]; } if (cut_respa) { for (int i = 0; i < ntablem1; i++) { dvtable[i] = vtable[i+1] - vtable[i]; dptable[i] = ptable[i+1] - ptable[i]; } } // get the delta values for the last table entries // tables are connected periodically between 0 and ntablem1 drtable[ntablem1] = 1.0/(rtable[0] - rtable[ntablem1]); dftable[ntablem1] = ftable[0] - ftable[ntablem1]; dctable[ntablem1] = ctable[0] - ctable[ntablem1]; detable[ntablem1] = etable[0] - etable[ntablem1]; if (cut_respa) { dvtable[ntablem1] = vtable[0] - vtable[ntablem1]; dptable[ntablem1] = ptable[0] - ptable[ntablem1]; } // get the correct delta values at itablemax // smallest r is in bin itablemin // largest r is in bin itablemax, which is itablemin-1, // or ntablem1 if itablemin=0 // deltas at itablemax only needed if corresponding rsq < cut*cut // if so, compute deltas between rsq and cut*cut double f_tmp,c_tmp,e_tmp,p_tmp,v_tmp; itablemin = minrsq_lookup.i & ncoulmask; itablemin >>= ncoulshiftbits; int itablemax = itablemin - 1; if (itablemin == 0) itablemax = ntablem1; rsq_lookup.i = itablemax << ncoulshiftbits; rsq_lookup.i |= maskhi; if (rsq_lookup.f < cut_coulsq) { rsq_lookup.f = cut_coulsq; r = sqrtf(rsq_lookup.f); grij = g_ewald * r; expm2 = exp(-grij*grij); derfc = erfc(grij); if (cut_respa == NULL) { f_tmp = qqrd2e/r * (derfc + EWALD_F*grij*expm2); c_tmp = qqrd2e/r; e_tmp = qqrd2e/r * derfc; } else { f_tmp = qqrd2e/r * (derfc + EWALD_F*grij*expm2 - 1.0); c_tmp = 0.0; e_tmp = qqrd2e/r * derfc; p_tmp = qqrd2e/r; v_tmp = qqrd2e/r * (derfc + EWALD_F*grij*expm2); if (rsq_lookup.f > cut_respa[2]*cut_respa[2]) { if (rsq_lookup.f < cut_respa[3]*cut_respa[3]) { rsw = (r - cut_respa[2])/(cut_respa[3] - cut_respa[2]); f_tmp += qqrd2e/r * rsw*rsw*(3.0 - 2.0*rsw); c_tmp = qqrd2e/r * rsw*rsw*(3.0 - 2.0*rsw); } else { f_tmp = qqrd2e/r * (derfc + EWALD_F*grij*expm2); c_tmp = qqrd2e/r; } } } drtable[itablemax] = 1.0/(rsq_lookup.f - rtable[itablemax]); dftable[itablemax] = f_tmp - ftable[itablemax]; dctable[itablemax] = c_tmp - ctable[itablemax]; detable[itablemax] = e_tmp - etable[itablemax]; if (cut_respa) { dvtable[itablemax] = v_tmp - vtable[itablemax]; dptable[itablemax] = p_tmp - ptable[itablemax]; } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJCutCoulLong::write_restart(FILE *fp) { write_restart_settings(fp); int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { fwrite(&setflag[i][j],sizeof(int),1,fp); if (setflag[i][j]) { fwrite(&epsilon[i][j],sizeof(double),1,fp); fwrite(&sigma[i][j],sizeof(double),1,fp); fwrite(&cut_lj[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJCutCoulLong::read_restart(FILE *fp) { read_restart_settings(fp); allocate(); int i,j; int me = comm->me; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp); MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world); if (setflag[i][j]) { if (me == 0) { fread(&epsilon[i][j],sizeof(double),1,fp); fread(&sigma[i][j],sizeof(double),1,fp); fread(&cut_lj[i][j],sizeof(double),1,fp); } MPI_Bcast(&epsilon[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_lj[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJCutCoulLong::write_restart_settings(FILE *fp) { fwrite(&cut_lj_global,sizeof(double),1,fp); fwrite(&cut_coul,sizeof(double),1,fp); fwrite(&offset_flag,sizeof(int),1,fp); fwrite(&mix_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJCutCoulLong::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&cut_lj_global,sizeof(double),1,fp); fread(&cut_coul,sizeof(double),1,fp); fread(&offset_flag,sizeof(int),1,fp); fread(&mix_flag,sizeof(int),1,fp); } MPI_Bcast(&cut_lj_global,1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_coul,1,MPI_DOUBLE,0,world); MPI_Bcast(&offset_flag,1,MPI_INT,0,world); MPI_Bcast(&mix_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- free memory for tables used in pair computations ------------------------------------------------------------------------- */ void PairLJCutCoulLong::free_tables() { memory->destroy(rtable); memory->destroy(drtable); memory->destroy(ftable); memory->destroy(dftable); memory->destroy(ctable); memory->destroy(dctable); memory->destroy(etable); memory->destroy(detable); memory->destroy(vtable); memory->destroy(dvtable); memory->destroy(ptable); memory->destroy(dptable); } /* ---------------------------------------------------------------------- */ double PairLJCutCoulLong::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r2inv,r6inv,r,grij,expm2,t,erfc,prefactor; double fraction,table,forcecoul,forcelj,phicoul,philj; int itable; r2inv = 1.0/rsq; if (rsq < cut_coulsq) { if (!ncoultablebits || rsq <= tabinnersq) { r = sqrt(rsq); grij = g_ewald * r; expm2 = exp(-grij*grij); t = 1.0 / (1.0 + EWALD_P*grij); erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2; prefactor = force->qqrd2e * atom->q[i]*atom->q[j]/r; forcecoul = prefactor * (erfc + EWALD_F*grij*expm2); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor; } else { union_int_float_t rsq_lookup_single; rsq_lookup_single.f = rsq; itable = rsq_lookup_single.i & ncoulmask; itable >>= ncoulshiftbits; fraction = (rsq_lookup_single.f - rtable[itable]) * drtable[itable]; table = ftable[itable] + fraction*dftable[itable]; forcecoul = atom->q[i]*atom->q[j] * table; if (factor_coul < 1.0) { table = ctable[itable] + fraction*dctable[itable]; prefactor = atom->q[i]*atom->q[j] * table; forcecoul -= (1.0-factor_coul)*prefactor; } } } else forcecoul = 0.0; if (rsq < cut_ljsq[itype][jtype]) { r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); } else forcelj = 0.0; fforce = (forcecoul + factor_lj*forcelj) * r2inv; double eng = 0.0; if (rsq < cut_coulsq) { if (!ncoultablebits || rsq <= tabinnersq) phicoul = prefactor*erfc; else { table = etable[itable] + fraction*detable[itable]; phicoul = atom->q[i]*atom->q[j] * table; } if (factor_coul < 1.0) phicoul -= (1.0-factor_coul)*prefactor; eng += phicoul; } if (rsq < cut_ljsq[itype][jtype]) { philj = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]) - offset[itype][jtype]; eng += factor_lj*philj; } return eng; } /* ---------------------------------------------------------------------- */ -void *PairLJCutCoulLong::extract(char *str, int &dim) +void *PairLJCutCoulLong::extract(const char *str, int &dim) { dim = 0; if (strcmp(str,"cut_coul") == 0) return (void *) &cut_coul; return NULL; } diff --git a/src/KSPACE/pair_lj_cut_coul_long.h b/src/KSPACE/pair_lj_cut_coul_long.h index d43becdb8..5ba9c1360 100644 --- a/src/KSPACE/pair_lj_cut_coul_long.h +++ b/src/KSPACE/pair_lj_cut_coul_long.h @@ -1,98 +1,98 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ #ifdef PAIR_CLASS PairStyle(lj/cut/coul/long,PairLJCutCoulLong) #else #ifndef LMP_PAIR_LJ_CUT_COUL_LONG_H #define LMP_PAIR_LJ_CUT_COUL_LONG_H #include "pair.h" namespace LAMMPS_NS { class PairLJCutCoulLong : public Pair { public: PairLJCutCoulLong(class LAMMPS *); virtual ~PairLJCutCoulLong(); virtual void compute(int, int); virtual void settings(int, char **); void coeff(int, char **); virtual void init_style(); void init_list(int, class NeighList *); double init_one(int, int); void write_restart(FILE *); void read_restart(FILE *); virtual void write_restart_settings(FILE *); virtual void read_restart_settings(FILE *); virtual double single(int, int, int, int, double, double, double, double &); void compute_inner(); void compute_middle(); void compute_outer(int, int); - void *extract(char *, int &); + void *extract(const char *, int &); protected: double cut_lj_global; double **cut_lj,**cut_ljsq; double cut_coul,cut_coulsq; double **epsilon,**sigma; double **lj1,**lj2,**lj3,**lj4,**offset; double *cut_respa; double g_ewald; double tabinnersq; double *rtable,*drtable,*ftable,*dftable,*ctable,*dctable; double *etable,*detable,*ptable,*dptable,*vtable,*dvtable; int ncoulshiftbits,ncoulmask; void allocate(); void init_tables(); void free_tables(); }; } #endif #endif /* ERROR/WARNING messages: E: Illegal ... command Self-explanatory. Check the input script syntax and compare to the documentation for the command. You can use -echo screen as a command-line option when running LAMMPS to see the offending line. E: Incorrect args for pair coefficients Self-explanatory. Check the input script or data file. E: Pair style lj/cut/coul/long requires atom attribute q The atom style defined does not have this attribute. E: Pair style is incompatible with KSpace style If a pair style with a long-range Coulombic component is selected, then a kspace style must also be used. E: Pair cutoff < Respa interior cutoff One or more pairwise cutoffs are too short to use with the specified rRESPA cutoffs. */ diff --git a/src/KSPACE/pair_lj_cut_coul_long_tip4p.cpp b/src/KSPACE/pair_lj_cut_coul_long_tip4p.cpp index ece15c683..0ed7d439a 100644 --- a/src/KSPACE/pair_lj_cut_coul_long_tip4p.cpp +++ b/src/KSPACE/pair_lj_cut_coul_long_tip4p.cpp @@ -1,516 +1,516 @@ /* ---------------------------------------------------------------------- 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: Amalie Frischknecht and Ahmed Ismail (SNL) ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "pair_lj_cut_coul_long_tip4p.h" #include "angle.h" #include "atom.h" #include "bond.h" #include "comm.h" #include "domain.h" #include "force.h" #include "kspace.h" #include "update.h" #include "respa.h" #include "neighbor.h" #include "neigh_list.h" #include "neigh_request.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define EWALD_F 1.12837917 #define EWALD_P 0.3275911 #define A1 0.254829592 #define A2 -0.284496736 #define A3 1.421413741 #define A4 -1.453152027 #define A5 1.061405429 /* ---------------------------------------------------------------------- */ PairLJCutCoulLongTIP4P::PairLJCutCoulLongTIP4P(LAMMPS *lmp) : PairLJCutCoulLong(lmp) { single_enable = 0; respa_enable = 0; // TIP4P cannot compute virial as F dot r // due to find_M() finding bonded H atoms which are not near O atom no_virial_fdotr_compute = 1; } /* ---------------------------------------------------------------------- */ void PairLJCutCoulLongTIP4P::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype,itable; int n,vlist[6]; int iH1,iH2,jH1,jH2; double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul; double fraction,table; double delxOM, delyOM, delzOM; double r,r2inv,r6inv,forcecoul,forcelj,cforce; double factor_coul,factor_lj; double grij,expm2,prefactor,t,erfc,ddotf; double xiM[3],xjM[3],fO[3],fH[3],fd[3],f1[3],v[6],xH1[3],xH2[3]; double *x1,*x2; int *ilist,*jlist,*numneigh,**firstneigh; double rsq; evdwl = ecoul = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; double **f = atom->f; double **x = atom->x; double *q = atom->q; int *type = atom->type; int nlocal = atom->nlocal; double *special_coul = force->special_coul; double *special_lj = force->special_lj; int newton_pair = force->newton_pair; double qqrd2e = force->qqrd2e; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // loop over neighbors of my atoms for (ii = 0; ii < inum; ii++) { i = ilist[ii]; qtmp = q[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; if (itype == typeO) { find_M(i,iH1,iH2,xiM); x1 = xiM; } else x1 = x[i]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; factor_lj = special_lj[sbmask(j)]; factor_coul = special_coul[sbmask(j)]; j &= NEIGHMASK; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; jtype = type[j]; if (rsq < cutsq[itype][jtype]) { r2inv = 1.0/rsq; if (rsq < cut_ljsq[itype][jtype]) { r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); forcelj *= factor_lj * r2inv; f[i][0] += delx*forcelj; f[i][1] += dely*forcelj; f[i][2] += delz*forcelj; f[j][0] -= delx*forcelj; f[j][1] -= dely*forcelj; f[j][2] -= delz*forcelj; if (eflag) { evdwl = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]) - offset[itype][jtype]; evdwl *= factor_lj; } else evdwl = 0.0; if (evflag) ev_tally(i,j,nlocal,newton_pair, evdwl,0.0,forcelj,delx,dely,delz); } // adjust rsq and delxyz for off-site O charge(s) if (itype == typeO || jtype == typeO) { if (jtype == typeO) { find_M(j,jH1,jH2,xjM); x2 = xjM; } else x2 = x[j]; delx = x1[0] - x2[0]; dely = x1[1] - x2[1]; delz = x1[2] - x2[2]; rsq = delx*delx + dely*dely + delz*delz; } // test current rsq against cutoff and compute Coulombic force if (rsq < cut_coulsq) { r2inv = 1 / rsq; if (!ncoultablebits || rsq <= tabinnersq) { r = sqrt(rsq); grij = g_ewald * r; expm2 = exp(-grij*grij); t = 1.0 / (1.0 + EWALD_P*grij); erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2; prefactor = qqrd2e * qtmp*q[j]/r; forcecoul = prefactor * (erfc + EWALD_F*grij*expm2); if (factor_coul < 1.0) { forcecoul -= (1.0-factor_coul)*prefactor; } } else { union_int_float_t rsq_lookup; rsq_lookup.f = rsq; itable = rsq_lookup.i & ncoulmask; itable >>= ncoulshiftbits; fraction = (rsq_lookup.f - rtable[itable]) * drtable[itable]; table = ftable[itable] + fraction*dftable[itable]; forcecoul = qtmp*q[j] * table; if (factor_coul < 1.0) { table = ctable[itable] + fraction*dctable[itable]; prefactor = qtmp*q[j] * table; forcecoul -= (1.0-factor_coul)*prefactor; } } cforce = forcecoul * r2inv; // if i,j are not O atoms, force is applied directly // if i or j are O atoms, force is on fictitious atom & partitioned // force partitioning due to Feenstra, J Comp Chem, 20, 786 (1999) // f_f = fictitious force, fO = f_f (1 - 2 alpha), fH = alpha f_f // preserves total force and torque on water molecule // virial = sum(r x F) where each water's atoms are near xi and xj // vlist stores 2,4,6 atoms whose forces contribute to virial n = 0; if (itype != typeO) { f[i][0] += delx * cforce; f[i][1] += dely * cforce; f[i][2] += delz * cforce; if (vflag) { v[0] = x[i][0] * delx * cforce; v[1] = x[i][1] * dely * cforce; v[2] = x[i][2] * delz * cforce; v[3] = x[i][0] * dely * cforce; v[4] = x[i][0] * delz * cforce; v[5] = x[i][1] * delz * cforce; vlist[n++] = i; } } else { fd[0] = delx*cforce; fd[1] = dely*cforce; fd[2] = delz*cforce; delxOM = x[i][0] - x1[0]; delyOM = x[i][1] - x1[1]; delzOM = x[i][2] - x1[2]; ddotf = (delxOM * fd[0] + delyOM * fd[1] + delzOM * fd[2]) / (qdist*qdist); f1[0] = ddotf * delxOM; f1[1] = ddotf * delyOM; f1[2] = ddotf * delzOM; fO[0] = fd[0] - alpha * (fd[0] - f1[0]); fO[1] = fd[1] - alpha * (fd[1] - f1[1]); fO[2] = fd[2] - alpha * (fd[2] - f1[2]); fH[0] = 0.5 * alpha * (fd[0] - f1[0]); fH[1] = 0.5 * alpha * (fd[1] - f1[1]); fH[2] = 0.5 * alpha * (fd[2] - f1[2]); f[i][0] += fO[0]; f[i][1] += fO[1]; f[i][2] += fO[2]; f[iH1][0] += fH[0]; f[iH1][1] += fH[1]; f[iH1][2] += fH[2]; f[iH2][0] += fH[0]; f[iH2][1] += fH[1]; f[iH2][2] += fH[2]; if (vflag) { domain->closest_image(x[i],x[iH1],xH1); domain->closest_image(x[i],x[iH2],xH2); v[0] = x[i][0]*fO[0] + xH1[0]*fH[0] + xH2[0]*fH[0]; v[1] = x[i][1]*fO[1] + xH1[1]*fH[1] + xH2[1]*fH[1]; v[2] = x[i][2]*fO[2] + xH1[2]*fH[2] + xH2[2]*fH[2]; v[3] = x[i][0]*fO[1] + xH1[0]*fH[1] + xH2[0]*fH[1]; v[4] = x[i][0]*fO[2] + xH1[0]*fH[2] + xH2[0]*fH[2]; v[5] = x[i][1]*fO[2] + xH1[1]*fH[2] + xH2[1]*fH[2]; vlist[n++] = i; vlist[n++] = iH1; vlist[n++] = iH2; } } if (jtype != typeO) { f[j][0] -= delx * cforce; f[j][1] -= dely * cforce; f[j][2] -= delz * cforce; if (vflag) { v[0] -= x[j][0] * delx * cforce; v[1] -= x[j][1] * dely * cforce; v[2] -= x[j][2] * delz * cforce; v[3] -= x[j][0] * dely * cforce; v[4] -= x[j][0] * delz * cforce; v[5] -= x[j][1] * delz * cforce; vlist[n++] = j; } } else { fd[0] = -delx*cforce; fd[1] = -dely*cforce; fd[2] = -delz*cforce; delxOM = x[j][0] - x2[0]; delyOM = x[j][1] - x2[1]; delzOM = x[j][2] - x2[2]; ddotf = (delxOM * fd[0] + delyOM * fd[1] + delzOM * fd[2]) / (qdist*qdist); f1[0] = ddotf * delxOM; f1[1] = ddotf * delyOM; f1[2] = ddotf * delzOM; fO[0] = fd[0] - alpha * (fd[0] - f1[0]); fO[1] = fd[1] - alpha * (fd[1] - f1[1]); fO[2] = fd[2] - alpha * (fd[2] - f1[2]); fH[0] = 0.5 * alpha * (fd[0] - f1[0]); fH[1] = 0.5 * alpha * (fd[1] - f1[1]); fH[2] = 0.5 * alpha * (fd[2] - f1[2]); f[j][0] += fO[0]; f[j][1] += fO[1]; f[j][2] += fO[2]; f[jH1][0] += fH[0]; f[jH1][1] += fH[1]; f[jH1][2] += fH[2]; f[jH2][0] += fH[0]; f[jH2][1] += fH[1]; f[jH2][2] += fH[2]; if (vflag) { domain->closest_image(x[j],x[jH1],xH1); domain->closest_image(x[j],x[jH2],xH2); v[0] += x[j][0]*fO[0] + xH1[0]*fH[0] + xH2[0]*fH[0]; v[1] += x[j][1]*fO[1] + xH1[1]*fH[1] + xH2[1]*fH[1]; v[2] += x[j][2]*fO[2] + xH1[2]*fH[2] + xH2[2]*fH[2]; v[3] += x[j][0]*fO[1] + xH1[0]*fH[1] + xH2[0]*fH[1]; v[4] += x[j][0]*fO[2] + xH1[0]*fH[2] + xH2[0]*fH[2]; v[5] += x[j][1]*fO[2] + xH1[1]*fH[2] + xH2[1]*fH[2]; vlist[n++] = j; vlist[n++] = jH1; vlist[n++] = jH2; } } if (eflag) { if (!ncoultablebits || rsq <= tabinnersq) ecoul = prefactor*erfc; else { table = etable[itable] + fraction*detable[itable]; ecoul = qtmp*q[j] * table; } if (factor_coul < 1.0) ecoul -= (1.0-factor_coul)*prefactor; } else ecoul = 0.0; if (evflag) ev_tally_list(n,vlist,ecoul,v); } } } } } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairLJCutCoulLongTIP4P::settings(int narg, char **arg) { if (narg < 6 || narg > 7) error->all(FLERR,"Illegal pair_style command"); typeO = force->inumeric(arg[0]); typeH = force->inumeric(arg[1]); typeB = force->inumeric(arg[2]); typeA = force->inumeric(arg[3]); qdist = force->numeric(arg[4]); cut_lj_global = force->numeric(arg[5]); if (narg == 6) cut_coul = cut_lj_global; else cut_coul = force->numeric(arg[6]); // reset cutoffs that have been explicitly set if (allocated) { int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i+1; j <= atom->ntypes; j++) if (setflag[i][j]) cut_lj[i][j] = cut_lj_global; } } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairLJCutCoulLongTIP4P::init_style() { if (atom->tag_enable == 0) error->all(FLERR,"Pair style lj/cut/coul/long/tip4p requires atom IDs"); if (!force->newton_pair) error->all(FLERR,"Pair style lj/cut/coul/long/tip4p requires newton pair on"); if (!atom->q_flag) error->all(FLERR,"Pair style lj/cut/coul/long/tip4p requires atom attribute q"); if ( (strcmp(force->kspace_style,"pppm/tip4p") != 0) && (strcmp(force->kspace_style,"pppm/tip4p/proxy") != 0) ) error->all(FLERR,"Pair style is incompatible with KSpace style"); if (force->bond == NULL) error->all(FLERR,"Must use a bond style with TIP4P potential"); if (force->angle == NULL) error->all(FLERR,"Must use an angle style with TIP4P potential"); PairLJCutCoulLong::init_style(); // set alpha parameter double theta = force->angle->equilibrium_angle(typeA); double blen = force->bond->equilibrium_distance(typeB); alpha = qdist / (cos(0.5*theta) * blen); } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJCutCoulLongTIP4P::write_restart_settings(FILE *fp) { fwrite(&typeO,sizeof(int),1,fp); fwrite(&typeH,sizeof(int),1,fp); fwrite(&typeB,sizeof(int),1,fp); fwrite(&typeA,sizeof(int),1,fp); fwrite(&qdist,sizeof(double),1,fp); fwrite(&cut_lj_global,sizeof(double),1,fp); fwrite(&cut_coul,sizeof(double),1,fp); fwrite(&offset_flag,sizeof(int),1,fp); fwrite(&mix_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJCutCoulLongTIP4P::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&typeO,sizeof(int),1,fp); fread(&typeH,sizeof(int),1,fp); fread(&typeB,sizeof(int),1,fp); fread(&typeA,sizeof(int),1,fp); fread(&qdist,sizeof(double),1,fp); fread(&cut_lj_global,sizeof(double),1,fp); fread(&cut_coul,sizeof(double),1,fp); fread(&offset_flag,sizeof(int),1,fp); fread(&mix_flag,sizeof(int),1,fp); } MPI_Bcast(&typeO,1,MPI_INT,0,world); MPI_Bcast(&typeH,1,MPI_INT,0,world); MPI_Bcast(&typeB,1,MPI_INT,0,world); MPI_Bcast(&typeA,1,MPI_INT,0,world); MPI_Bcast(&qdist,1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_lj_global,1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_coul,1,MPI_DOUBLE,0,world); MPI_Bcast(&offset_flag,1,MPI_INT,0,world); MPI_Bcast(&mix_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- find 2 H atoms bonded to O atom i compute position xM of fictitious charge site for O atom also return local indices iH1,iH2 of H atoms ------------------------------------------------------------------------- */ void PairLJCutCoulLongTIP4P::find_M(int i, int &iH1, int &iH2, double *xM) { // test that O is correctly bonded to 2 succesive H atoms iH1 = atom->map(atom->tag[i] + 1); iH2 = atom->map(atom->tag[i] + 2); if (iH1 == -1 || iH2 == -1) error->one(FLERR,"TIP4P hydrogen is missing"); if (atom->type[iH1] != typeH || atom->type[iH2] != typeH) error->one(FLERR,"TIP4P hydrogen has incorrect atom type"); double **x = atom->x; double delx1 = x[iH1][0] - x[i][0]; double dely1 = x[iH1][1] - x[i][1]; double delz1 = x[iH1][2] - x[i][2]; domain->minimum_image(delx1,dely1,delz1); double delx2 = x[iH2][0] - x[i][0]; double dely2 = x[iH2][1] - x[i][1]; double delz2 = x[iH2][2] - x[i][2]; domain->minimum_image(delx2,dely2,delz2); xM[0] = x[i][0] + alpha * 0.5 * (delx1 + delx2); xM[1] = x[i][1] + alpha * 0.5 * (dely1 + dely2); xM[2] = x[i][2] + alpha * 0.5 * (delz1 + delz2); } /* ---------------------------------------------------------------------- */ -void *PairLJCutCoulLongTIP4P::extract(char *str, int &dim) +void *PairLJCutCoulLongTIP4P::extract(const char *str, int &dim) { dim = 0; if (strcmp(str,"qdist") == 0) return (void *) &qdist; if (strcmp(str,"typeO") == 0) return (void *) &typeO; if (strcmp(str,"typeH") == 0) return (void *) &typeH; if (strcmp(str,"typeA") == 0) return (void *) &typeA; if (strcmp(str,"typeB") == 0) return (void *) &typeB; if (strcmp(str,"cut_coul") == 0) return (void *) &cut_coul; return NULL; } diff --git a/src/KSPACE/pair_lj_cut_coul_long_tip4p.h b/src/KSPACE/pair_lj_cut_coul_long_tip4p.h index 4fb036484..20060ea0f 100644 --- a/src/KSPACE/pair_lj_cut_coul_long_tip4p.h +++ b/src/KSPACE/pair_lj_cut_coul_long_tip4p.h @@ -1,98 +1,98 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ #ifdef PAIR_CLASS PairStyle(lj/cut/coul/long/tip4p,PairLJCutCoulLongTIP4P) #else #ifndef LMP_PAIR_LJ_CUT_COUL_LONG_TIP4P_H #define LMP_PAIR_LJ_CUT_COUL_LONG_TIP4P_H #include "pair_lj_cut_coul_long.h" namespace LAMMPS_NS { class PairLJCutCoulLongTIP4P : public PairLJCutCoulLong { public: PairLJCutCoulLongTIP4P(class LAMMPS *); virtual void compute(int, int); void settings(int, char **); void init_style(); void write_restart_settings(FILE *fp); void read_restart_settings(FILE *fp); - void *extract(char *, int &); + void *extract(const char *, int &); protected: int typeH,typeO; // atom types of TIP4P water H and O atoms int typeA,typeB; // angle and bond types of TIP4P water double qdist; // distance from O site to negative charge double alpha; // geometric constraint parameter for TIP4P void find_M(int, int &, int &, double *); }; } #endif #endif /* ERROR/WARNING messages: E: Illegal ... command Self-explanatory. Check the input script syntax and compare to the documentation for the command. You can use -echo screen as a command-line option when running LAMMPS to see the offending line. E: Pair style lj/cut/coul/long/tip4p requires atom IDs There are no atom IDs defined in the system and the TIP4P potential requires them to find O,H atoms with a water molecule. E: Pair style lj/cut/coul/long/tip4p requires newton pair on This is because the computation of constraint forces within a water molecule adds forces to atoms owned by other processors. E: Pair style lj/cut/coul/long/tip4p requires atom attribute q The atom style defined does not have these attributes. E: Pair style is incompatible with KSpace style If a pair style with a long-range Coulombic component is selected, then a kspace style must also be used. E: Must use a bond style with TIP4P potential TIP4P potentials assume bond lengths in water are constrained by a fix shake command. E: Must use an angle style with TIP4P potential TIP4P potentials assume angles in water are constrained by a fix shake command. E: TIP4P hydrogen is missing The TIP4P pairwise computation failed to find the correct H atom within a water molecule. E: TIP4P hydrogen has incorrect atom type The TIP4P pairwise computation found an H atom whose type does not agree with the specified H type. */ diff --git a/src/MC/fix_bond_swap.cpp b/src/MC/fix_bond_swap.cpp index 1984f9f40..4003e437f 100644 --- a/src/MC/fix_bond_swap.cpp +++ b/src/MC/fix_bond_swap.cpp @@ -1,689 +1,689 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ #include "math.h" #include "stdlib.h" #include "string.h" #include "fix_bond_swap.h" #include "atom.h" #include "force.h" #include "pair.h" #include "bond.h" #include "angle.h" #include "neighbor.h" #include "neigh_list.h" #include "neigh_request.h" #include "group.h" #include "comm.h" #include "domain.h" #include "modify.h" #include "compute.h" #include "random_mars.h" #include "memory.h" #include "error.h" #include "update.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ FixBondSwap::FixBondSwap(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg) { if (narg != 6) error->all(FLERR,"Illegal fix bond/swap command"); vector_flag = 1; size_vector = 2; global_freq = 1; extvector = 0; fraction = atof(arg[3]); double cutoff = atof(arg[4]); cutsq = cutoff*cutoff; // initialize Marsaglia RNG with processor-unique seed int seed = atoi(arg[5]); random = new RanMars(lmp,seed + comm->me); // create a new compute temp style // id = fix-ID + temp, compute group = fix group int n = strlen(id) + 6; id_temp = new char[n]; strcpy(id_temp,id); strcat(id_temp,"_temp"); char **newarg = new char*[3]; newarg[0] = id_temp; - newarg[1] = "all"; - newarg[2] = "temp"; + newarg[1] = (char *) "all"; + newarg[2] = (char *) "temp"; modify->add_compute(3,newarg); delete [] newarg; tflag = 1; // initialize atom list nmax = 0; alist = NULL; naccept = foursome = 0; } /* ---------------------------------------------------------------------- */ FixBondSwap::~FixBondSwap() { delete random; // delete temperature if fix created it if (tflag) modify->delete_compute(id_temp); delete [] id_temp; memory->destroy(alist); } /* ---------------------------------------------------------------------- */ int FixBondSwap::setmask() { int mask = 0; mask |= PRE_NEIGHBOR; return mask; } /* ---------------------------------------------------------------------- */ void FixBondSwap::init() { // require an atom style with molecule IDs if (atom->molecule == NULL) error->all(FLERR,"Must use atom style with molecule IDs with fix bond/swap"); int icompute = modify->find_compute(id_temp); if (icompute < 0) error->all(FLERR,"Temperature ID for fix bond/swap does not exist"); temperature = modify->compute[icompute]; // pair and bonds must be defined // no dihedral or improper potentials allowed // special bonds must be 0 1 1 if (force->pair == NULL || force->bond == NULL) error->all(FLERR,"Fix bond/swap requires pair and bond styles"); if (force->pair->single_enable == 0) error->all(FLERR,"Pair style does not support fix bond/swap"); if (force->angle == NULL && atom->nangles > 0 && comm->me == 0) error->warning(FLERR,"Fix bond/swap will ignore defined angles"); if (force->dihedral || force->improper) error->all(FLERR,"Fix bond/swap cannot use dihedral or improper styles"); if (force->special_lj[1] != 0.0 || force->special_lj[2] != 1.0 || force->special_lj[3] != 1.0) error->all(FLERR,"Fix bond/swap requires special_bonds = 0,1,1"); // need a half neighbor list, built when ever re-neighboring occurs int irequest = neighbor->request((void *) this); neighbor->requests[irequest]->pair = 0; neighbor->requests[irequest]->fix = 1; // zero out stats naccept = foursome = 0; angleflag = 0; if (force->angle) angleflag = 1; } /* ---------------------------------------------------------------------- */ void FixBondSwap::init_list(int id, NeighList *ptr) { list = ptr; } /* ---------------------------------------------------------------------- */ void FixBondSwap::pre_neighbor() { int i,j,ii,jj,m,inum,jnum; int inext,iprev,ilast,jnext,jprev,jlast,ibond,iangle,jbond,jangle; int itag,inexttag,iprevtag,ilasttag,jtag,jnexttag,jprevtag,jlasttag; int ibondtype,jbondtype,iangletype,inextangletype,jangletype,jnextangletype; int i1,i2,i3,j1,j2,j3,tmp; int *ilist,*jlist,*numneigh,**firstneigh; double delta,factor; // compute current temp for Boltzmann factor test double t_current = temperature->compute_scalar(); // local ptrs to atom arrays int *tag = atom->tag; int *mask = atom->mask; int *molecule = atom->molecule; int *num_bond = atom->num_bond; int **bond_atom = atom->bond_atom; int **bond_type = atom->bond_type; int *num_angle = atom->num_angle; int **angle_atom1 = atom->angle_atom1; int **angle_atom2 = atom->angle_atom2; int **angle_atom3 = atom->angle_atom3; int **angle_type = atom->angle_type; int **nspecial = atom->nspecial; int **special = atom->special; int newton_bond = force->newton_bond; int nlocal = atom->nlocal; type = atom->type; x = atom->x; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // randomize list of my owned atoms that are in fix group // grow atom list if necessary if (nlocal > nmax) { memory->destroy(alist); nmax = atom->nmax; memory->create(alist,nmax,"bondswap:alist"); } int neligible = 0; for (ii = 0; ii < inum; ii++) { i = ilist[ii]; if (mask[i] & groupbit) alist[neligible++] = i; } for (i = 0; i < neligible; i++) { j = static_cast (random->uniform() * neligible); tmp = alist[i]; alist[i] = alist[j]; alist[j] = tmp; } // examine ntest of my eligible atoms for potential swaps // atom i is randomly selected via atom list // look at all j neighbors of atom i // atom j must be on-processor (j < nlocal) // atom j must be in fix group // i and j must be same distance from chain end (mol[i] = mol[j]) // NOTE: must use extra parens in if test on mask[j] & groupbit int ntest = static_cast (fraction * neligible); int accept = 0; for (int itest = 0; itest < ntest; itest++) { i = alist[itest]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; j &= NEIGHMASK; if (j >= nlocal) continue; if ((mask[j] & groupbit) == 0) continue; if (molecule[i] != molecule[j]) continue; // look at all bond partners of atoms i and j // use num_bond for this, not special list, so also find bondtypes // inext,jnext = bonded atoms // inext,jnext must be on-processor (inext,jnext < nlocal) // inext,jnext must be same dist from chain end (mol[inext] = mol[jnext]) // since swaps may occur between two ends of a single chain, insure // the 4 atoms are unique (no duplicates): inext != jnext, inext != j // all 4 old and new bonds must have length < cutoff for (ibond = 0; ibond < num_bond[i]; ibond++) { inext = atom->map(bond_atom[i][ibond]); if (inext >= nlocal || inext < 0) continue; ibondtype = bond_type[i][ibond]; for (jbond = 0; jbond < num_bond[j]; jbond++) { jnext = atom->map(bond_atom[j][jbond]); if (jnext >= nlocal || jnext < 0) continue; jbondtype = bond_type[j][jbond]; if (molecule[inext] != molecule[jnext]) continue; if (inext == jnext || inext == j) continue; if (dist_rsq(i,inext) >= cutsq) continue; if (dist_rsq(j,jnext) >= cutsq) continue; if (dist_rsq(i,jnext) >= cutsq) continue; if (dist_rsq(j,inext) >= cutsq) continue; // if angles are enabled: // find other atoms i,inext,j,jnext are in angles with // and angletypes: i/j angletype, i/j nextangletype // use num_angle for this, not special list, so also find angletypes // 4 atoms consecutively along 1st chain: iprev,i,inext,ilast // 4 atoms consecutively along 2nd chain: jprev,j,jnext,jlast // prev or last atom can be non-existent at end of chain // set prev/last = -1 in this case // if newton bond = 0, then angles are stored by all 4 atoms // so require that iprev,ilast,jprev,jlast be owned by this proc // so all copies of angles can be updated if a swap takes place if (angleflag) { itag = tag[i]; inexttag = tag[inext]; jtag = tag[j]; jnexttag = tag[jnext]; iprev = -1; for (iangle = 0; iangle < num_angle[i]; iangle++) { i1 = angle_atom1[i][iangle]; i2 = angle_atom2[i][iangle]; i3 = angle_atom3[i][iangle]; if (i2 == itag && i3 == inexttag) iprev = atom->map(i1); else if (i1 == inexttag && i2 == itag) iprev = atom->map(i3); if (iprev >= 0) { iangletype = angle_type[i][iangle]; break; } } if (!newton_bond && iprev >= nlocal) continue; ilast = -1; for (iangle = 0; iangle < num_angle[inext]; iangle++) { i1 = angle_atom1[inext][iangle]; i2 = angle_atom2[inext][iangle]; i3 = angle_atom3[inext][iangle]; if (i1 == itag && i2 == inexttag) ilast = atom->map(i3); else if (i2 == inexttag && i3 == itag) ilast = atom->map(i1); if (ilast >= 0) { inextangletype = angle_type[inext][iangle]; break; } } if (!newton_bond && ilast >= nlocal) continue; jprev = -1; for (jangle = 0; jangle < num_angle[j]; jangle++) { j1 = angle_atom1[j][jangle]; j2 = angle_atom2[j][jangle]; j3 = angle_atom3[j][jangle]; if (j2 == jtag && j3 == jnexttag) jprev = atom->map(j1); else if (j1 == jnexttag && j2 == jtag) jprev = atom->map(j3); if (jprev >= 0) { jangletype = angle_type[j][jangle]; break; } } if (!newton_bond && jprev >= nlocal) continue; jlast = -1; for (jangle = 0; jangle < num_angle[jnext]; jangle++) { j1 = angle_atom1[jnext][jangle]; j2 = angle_atom2[jnext][jangle]; j3 = angle_atom3[jnext][jangle]; if (j1 == jtag && j2 == jnexttag) jlast = atom->map(j3); else if (j2 == jnexttag && j3 == jtag) jlast = atom->map(j1); if (jlast >= 0) { jnextangletype = angle_type[jnext][jangle]; break; } } if (!newton_bond && jlast >= nlocal) continue; } // valid foursome found between 2 chains: // chains = iprev-i-inext-ilast and jprev-j-jnext-jlast // prev or last values are -1 if do not exist due to end of chain // OK to call angle_eng with -1 atom, since just return 0.0 // current energy of foursome = // E_nb(i,j) + E_nb(i,jnext) + E_nb(inext,j) + E_nb(inext,jnext) + // E_bond(i,inext) + E_bond(j,jnext) + // E_angle(iprev,i,inext) + E_angle(i,inext,ilast) + // E_angle(jprev,j,jnext) + E_angle(j,jnext,jlast) // new energy of foursome with swapped bonds = // E_nb(i,j) + E_nb(i,inext) + E_nb(j,jnext) + E_nb(inext,jnext) + // E_bond(i,jnext) + E_bond(j,inext) + // E_angle(iprev,i,jnext) + E_angle(i,jnext,jlast) + // E_angle(jprev,j,inext) + E_angle(j,inext,ilast) // energy delta = add/subtract differing terms between 2 formulas foursome++; delta = pair_eng(i,inext) + pair_eng(j,jnext) - pair_eng(i,jnext) - pair_eng(inext,j); delta += bond_eng(ibondtype,i,jnext) + bond_eng(jbondtype,j,inext) - bond_eng(ibondtype,i,inext) - bond_eng(jbondtype,j,jnext); if (angleflag) delta += angle_eng(iangletype,iprev,i,jnext) + angle_eng(jnextangletype,i,jnext,jlast) + angle_eng(jangletype,jprev,j,inext) + angle_eng(inextangletype,j,inext,ilast) - angle_eng(iangletype,iprev,i,inext) - angle_eng(inextangletype,i,inext,ilast) - angle_eng(jangletype,jprev,j,jnext) - angle_eng(jnextangletype,j,jnext,jlast); // if delta <= 0, accept swap // if delta > 0, compute Boltzmann factor with current temperature // only accept if greater than random value // whether accept or not, exit test loop if (delta < 0.0) accept = 1; else { factor = exp(-delta/force->boltz/t_current); if (random->uniform() < factor) accept = 1; } goto done; } } } } done: if (!accept) return; naccept++; // change bond partners of affected atoms // on atom i: bond i-inext changes to i-jnext // on atom j: bond j-jnext changes to j-inext // on atom inext: bond inext-i changes to inext-j // on atom jnext: bond jnext-j changes to jnext-i for (ibond = 0; ibond < num_bond[i]; ibond++) if (bond_atom[i][ibond] == tag[inext]) bond_atom[i][ibond] = tag[jnext]; for (jbond = 0; jbond < num_bond[j]; jbond++) if (bond_atom[j][jbond] == tag[jnext]) bond_atom[j][jbond] = tag[inext]; for (ibond = 0; ibond < num_bond[inext]; ibond++) if (bond_atom[inext][ibond] == tag[i]) bond_atom[inext][ibond] = tag[j]; for (jbond = 0; jbond < num_bond[jnext]; jbond++) if (bond_atom[jnext][jbond] == tag[j]) bond_atom[jnext][jbond] = tag[i]; // set global tags of 4 atoms in bonds itag = tag[i]; inexttag = tag[inext]; jtag = tag[j]; jnexttag = tag[jnext]; // change 1st special neighbors of affected atoms: i,j,inext,jnext // don't need to change 2nd/3rd special neighbors for any atom // since special bonds = 0 1 1 means they are never used for (m = 0; m < nspecial[i][0]; m++) if (special[i][m] == inexttag) special[i][m] = jnexttag; for (m = 0; m < nspecial[j][0]; m++) if (special[j][m] == jnexttag) special[j][m] = inexttag; for (m = 0; m < nspecial[inext][0]; m++) if (special[inext][m] == itag) special[inext][m] = jtag; for (m = 0; m < nspecial[jnext][0]; m++) if (special[jnext][m] == jtag) special[jnext][m] = itag; // done if no angles if (!angleflag) return; // set global tags of 4 additional atoms in angles, 0 if no angle if (iprev >= 0) iprevtag = tag[iprev]; else iprevtag = 0; if (ilast >= 0) ilasttag = tag[ilast]; else ilasttag = 0; if (jprev >= 0) jprevtag = tag[jprev]; else jprevtag = 0; if (jlast >= 0) jlasttag = tag[jlast]; else jlasttag = 0; // change angle partners of affected atoms // must check if each angle is stored as a-b-c or c-b-a // on atom i: // angle iprev-i-inext changes to iprev-i-jnext // angle i-inext-ilast changes to i-jnext-jlast // on atom j: // angle jprev-j-jnext changes to jprev-j-inext // angle j-jnext-jlast changes to j-inext-ilast // on atom inext: // angle iprev-i-inext changes to jprev-j-inext // angle i-inext-ilast changes to j-inext-ilast // on atom jnext: // angle jprev-j-jnext changes to iprev-i-jnext // angle j-jnext-jlast changes to i-jnext-jlast for (iangle = 0; iangle < num_angle[i]; iangle++) { i1 = angle_atom1[i][iangle]; i2 = angle_atom2[i][iangle]; i3 = angle_atom3[i][iangle]; if (i1 == iprevtag && i2 == itag && i3 == inexttag) angle_atom3[i][iangle] = jnexttag; else if (i1 == inexttag && i2 == itag && i3 == iprevtag) angle_atom1[i][iangle] = jnexttag; else if (i1 == itag && i2 == inexttag && i3 == ilasttag) { angle_atom2[i][iangle] = jnexttag; angle_atom3[i][iangle] = jlasttag; } else if (i1 == ilasttag && i2 == inexttag && i3 == itag) { angle_atom1[i][iangle] = jlasttag; angle_atom2[i][iangle] = jnexttag; } } for (jangle = 0; jangle < num_angle[j]; jangle++) { j1 = angle_atom1[j][jangle]; j2 = angle_atom2[j][jangle]; j3 = angle_atom3[j][jangle]; if (j1 == jprevtag && j2 == jtag && j3 == jnexttag) angle_atom3[j][jangle] = inexttag; else if (j1 == jnexttag && j2 == jtag && j3 == jprevtag) angle_atom1[j][jangle] = inexttag; else if (j1 == jtag && j2 == jnexttag && j3 == jlasttag) { angle_atom2[j][jangle] = inexttag; angle_atom3[j][jangle] = ilasttag; } else if (j1 == jlasttag && j2 == jnexttag && j3 == jtag) { angle_atom1[j][jangle] = ilasttag; angle_atom2[j][jangle] = inexttag; } } for (iangle = 0; iangle < num_angle[inext]; iangle++) { i1 = angle_atom1[inext][iangle]; i2 = angle_atom2[inext][iangle]; i3 = angle_atom3[inext][iangle]; if (i1 == iprevtag && i2 == itag && i3 == inexttag) { angle_atom1[inext][iangle] = jprevtag; angle_atom2[inext][iangle] = jtag; } else if (i1 == inexttag && i2 == itag && i3 == iprevtag) { angle_atom2[inext][iangle] = jtag; angle_atom3[inext][iangle] = jprevtag; } else if (i1 == itag && i2 == inexttag && i3 == ilasttag) angle_atom1[inext][iangle] = jtag; else if (i1 == ilasttag && i2 == inexttag && i3 == itag) angle_atom3[inext][iangle] = jtag; } for (jangle = 0; jangle < num_angle[jnext]; jangle++) { j1 = angle_atom1[jnext][jangle]; j2 = angle_atom2[jnext][jangle]; j3 = angle_atom3[jnext][jangle]; if (j1 == jprevtag && j2 == jtag && j3 == jnexttag) { angle_atom1[jnext][jangle] = iprevtag; angle_atom2[jnext][jangle] = itag; } else if (j1 == jnexttag && j2 == jtag && j3 == jprevtag) { angle_atom2[jnext][jangle] = itag; angle_atom3[jnext][jangle] = iprevtag; } else if (j1 == jtag && j2 == jnexttag && j3 == jlasttag) angle_atom1[jnext][jangle] = itag; else if (j1 == jlasttag && j2 == jnexttag && j3 == jtag) angle_atom3[jnext][jangle] = itag; } // done if newton bond set if (newton_bond) return; // change angles stored by iprev,ilast,jprev,jlast // on atom iprev: angle iprev-i-inext changes to iprev-i-jnext // on atom jprev: angle jprev-j-jnext changes to jprev-j-inext // on atom ilast: angle i-inext-ilast changes to j-inext-ilast // on atom jlast: angle j-jnext-jlast changes to i-jnext-jlast for (iangle = 0; iangle < num_angle[iprev]; iangle++) { i1 = angle_atom1[iprev][iangle]; i2 = angle_atom2[iprev][iangle]; i3 = angle_atom3[iprev][iangle]; if (i1 == iprevtag && i2 == itag && i3 == inexttag) angle_atom3[iprev][iangle] = jnexttag; else if (i1 == inexttag && i2 == itag && i3 == iprevtag) angle_atom1[iprev][iangle] = jnexttag; } for (jangle = 0; jangle < num_angle[jprev]; jangle++) { j1 = angle_atom1[jprev][jangle]; j2 = angle_atom2[jprev][jangle]; j3 = angle_atom3[jprev][jangle]; if (j1 == jprevtag && j2 == jtag && j3 == jnexttag) angle_atom3[jprev][jangle] = inexttag; else if (j1 == jnexttag && j2 == jtag && j3 == jprevtag) angle_atom1[jprev][jangle] = inexttag; } for (iangle = 0; iangle < num_angle[ilast]; iangle++) { i1 = angle_atom1[ilast][iangle]; i2 = angle_atom2[ilast][iangle]; i3 = angle_atom3[ilast][iangle]; if (i1 == itag && i2 == inexttag && i3 == ilasttag) angle_atom1[ilast][iangle] = jtag; else if (i1 == ilasttag && i2 == inexttag && i3 == itag) angle_atom3[ilast][iangle] = jtag; } for (jangle = 0; jangle < num_angle[jlast]; jangle++) { j1 = angle_atom1[jlast][jangle]; j2 = angle_atom2[jlast][jangle]; j3 = angle_atom3[jlast][jangle]; if (j1 == jtag && j2 == jnexttag && j3 == jlasttag) angle_atom1[jlast][jangle] = itag; else if (j1 == jlasttag && j2 == jnexttag && j3 == jtag) angle_atom3[jlast][jangle] = itag; } } /* ---------------------------------------------------------------------- */ int FixBondSwap::modify_param(int narg, char **arg) { if (strcmp(arg[0],"temp") == 0) { if (narg < 2) error->all(FLERR,"Illegal fix_modify command"); if (tflag) { modify->delete_compute(id_temp); tflag = 0; } delete [] id_temp; int n = strlen(arg[1]) + 1; id_temp = new char[n]; strcpy(id_temp,arg[1]); int icompute = modify->find_compute(id_temp); if (icompute < 0) error->all(FLERR,"Could not find fix_modify temperature ID"); temperature = modify->compute[icompute]; if (temperature->tempflag == 0) error->all(FLERR,"Fix_modify temperature ID does not compute temperature"); if (temperature->igroup != igroup && comm->me == 0) error->warning(FLERR,"Group for fix_modify temp != fix group"); return 2; } return 0; } /* ---------------------------------------------------------------------- compute squared distance between atoms I,J must use minimum_image since J was found thru atom->map() ------------------------------------------------------------------------- */ double FixBondSwap::dist_rsq(int i, int j) { double delx = x[i][0] - x[j][0]; double dely = x[i][1] - x[j][1]; double delz = x[i][2] - x[j][2]; domain->minimum_image(delx,dely,delz); return (delx*delx + dely*dely + delz*delz); } /* ---------------------------------------------------------------------- return pairwise interaction energy between atoms I,J will always be full non-bond interaction, so factors = 1 in single() call ------------------------------------------------------------------------- */ double FixBondSwap::pair_eng(int i, int j) { double tmp; double rsq = dist_rsq(i,j); return force->pair->single(i,j,type[i],type[j],rsq,1.0,1.0,tmp); } /* ---------------------------------------------------------------------- */ double FixBondSwap::bond_eng(int btype, int i, int j) { double rsq = dist_rsq(i,j); return force->bond->single(btype,rsq,i,j); } /* ---------------------------------------------------------------------- */ double FixBondSwap::angle_eng(int atype, int i, int j, int k) { // test for non-existent angle at end of chain if (i == -1 || k == -1) return 0.0; return force->angle->single(atype,i,j,k); } /* ---------------------------------------------------------------------- return bond swapping stats n = 1 is # of swaps n = 2 is # of attempted swaps ------------------------------------------------------------------------- */ double FixBondSwap::compute_vector(int n) { double one,all; if (n == 0) one = naccept; else one = foursome; MPI_Allreduce(&one,&all,1,MPI_DOUBLE,MPI_SUM,world); return all; } /* ---------------------------------------------------------------------- memory usage of alist ------------------------------------------------------------------------- */ double FixBondSwap::memory_usage() { double bytes = nmax * sizeof(int); return bytes; } diff --git a/src/MEAM/pair_meam.cpp b/src/MEAM/pair_meam.cpp index fda4c6b3c..4afb5e1d0 100644 --- a/src/MEAM/pair_meam.cpp +++ b/src/MEAM/pair_meam.cpp @@ -1,944 +1,945 @@ /* ---------------------------------------------------------------------- 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 author: Greg Wagner (SNL) ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "pair_meam.h" #include "atom.h" #include "force.h" #include "comm.h" #include "memory.h" #include "neighbor.h" #include "neigh_list.h" #include "neigh_request.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define MAXLINE 1024 enum{FCC,BCC,HCP,DIM,DIAMOND,B1,C11,L12,B2}; int nkeywords = 21; -char *keywords[] = {"Ec","alpha","rho0","delta","lattce", - "attrac","repuls","nn2","Cmin","Cmax","rc","delr", - "augt1","gsmooth_factor","re","ialloy","mixture_ref_t", - "erose_form","zbl","emb_lin_neg","bkgd_dyn"}; +const char *keywords[] = {"Ec","alpha","rho0","delta","lattce", + "attrac","repuls","nn2","Cmin","Cmax","rc","delr", + "augt1","gsmooth_factor","re","ialloy", + "mixture_ref_t","erose_form","zbl", + "emb_lin_neg","bkgd_dyn"}; /* ---------------------------------------------------------------------- */ PairMEAM::PairMEAM(LAMMPS *lmp) : Pair(lmp) { single_enable = 0; restartinfo = 0; one_coeff = 1; nmax = 0; rho = rho0 = rho1 = rho2 = rho3 = frhop = NULL; gamma = dgamma1 = dgamma2 = dgamma3 = arho2b = NULL; arho1 = arho2 = arho3 = arho3b = t_ave = tsq_ave = NULL; maxneigh = 0; scrfcn = dscrfcn = fcpair = NULL; nelements = 0; elements = NULL; mass = NULL; // set comm size needed by this Pair comm_forward = 38; comm_reverse = 30; } /* ---------------------------------------------------------------------- free all arrays check if allocated, since class can be destructed when incomplete ------------------------------------------------------------------------- */ PairMEAM::~PairMEAM() { meam_cleanup_(); memory->destroy(rho); memory->destroy(rho0); memory->destroy(rho1); memory->destroy(rho2); memory->destroy(rho3); memory->destroy(frhop); memory->destroy(gamma); memory->destroy(dgamma1); memory->destroy(dgamma2); memory->destroy(dgamma3); memory->destroy(arho2b); memory->destroy(arho1); memory->destroy(arho2); memory->destroy(arho3); memory->destroy(arho3b); memory->destroy(t_ave); memory->destroy(tsq_ave); memory->destroy(scrfcn); memory->destroy(dscrfcn); memory->destroy(fcpair); for (int i = 0; i < nelements; i++) delete [] elements[i]; delete [] elements; delete [] mass; if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); delete [] map; delete [] fmap; } } /* ---------------------------------------------------------------------- */ void PairMEAM::compute(int eflag, int vflag) { int i,j,ii,n,inum_half,errorflag; double evdwl; int *ilist_half,*numneigh_half,**firstneigh_half; int *numneigh_full,**firstneigh_full; evdwl = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = eflag_global = vflag_global = eflag_atom = vflag_atom = 0; // grow local arrays if necessary if (atom->nmax > nmax) { memory->destroy(rho); memory->destroy(rho0); memory->destroy(rho1); memory->destroy(rho2); memory->destroy(rho3); memory->destroy(frhop); memory->destroy(gamma); memory->destroy(dgamma1); memory->destroy(dgamma2); memory->destroy(dgamma3); memory->destroy(arho2b); memory->destroy(arho1); memory->destroy(arho2); memory->destroy(arho3); memory->destroy(arho3b); memory->destroy(t_ave); memory->destroy(tsq_ave); nmax = atom->nmax; memory->create(rho,nmax,"pair:rho"); memory->create(rho0,nmax,"pair:rho0"); memory->create(rho1,nmax,"pair:rho1"); memory->create(rho2,nmax,"pair:rho2"); memory->create(rho3,nmax,"pair:rho3"); memory->create(frhop,nmax,"pair:frhop"); memory->create(gamma,nmax,"pair:gamma"); memory->create(dgamma1,nmax,"pair:dgamma1"); memory->create(dgamma2,nmax,"pair:dgamma2"); memory->create(dgamma3,nmax,"pair:dgamma3"); memory->create(arho2b,nmax,"pair:arho2b"); memory->create(arho1,nmax,3,"pair:arho1"); memory->create(arho2,nmax,6,"pair:arho2"); memory->create(arho3,nmax,10,"pair:arho3"); memory->create(arho3b,nmax,3,"pair:arho3b"); memory->create(t_ave,nmax,3,"pair:t_ave"); memory->create(tsq_ave,nmax,3,"pair:tsq_ave"); } // neighbor list info inum_half = listhalf->inum; ilist_half = listhalf->ilist; numneigh_half = listhalf->numneigh; firstneigh_half = listhalf->firstneigh; numneigh_full = listfull->numneigh; firstneigh_full = listfull->firstneigh; // strip neighbor lists of any special bond flags before using with MEAM // necessary before doing neigh_f2c and neigh_c2f conversions each step if (neighbor->ago == 0) { neigh_strip(inum_half,ilist_half,numneigh_half,firstneigh_half); neigh_strip(inum_half,ilist_half,numneigh_full,firstneigh_full); } // check size of scrfcn based on half neighbor list int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; n = 0; for (ii = 0; ii < inum_half; ii++) n += numneigh_half[ilist_half[ii]]; if (n > maxneigh) { memory->destroy(scrfcn); memory->destroy(dscrfcn); memory->destroy(fcpair); maxneigh = n; memory->create(scrfcn,maxneigh,"pair:scrfcn"); memory->create(dscrfcn,maxneigh,"pair:dscrfcn"); memory->create(fcpair,maxneigh,"pair:fcpair"); } // zero out local arrays for (i = 0; i < nall; i++) { rho0[i] = 0.0; arho2b[i] = 0.0; arho1[i][0] = arho1[i][1] = arho1[i][2] = 0.0; for (j = 0; j < 6; j++) arho2[i][j] = 0.0; for (j = 0; j < 10; j++) arho3[i][j] = 0.0; arho3b[i][0] = arho3b[i][1] = arho3b[i][2] = 0.0; t_ave[i][0] = t_ave[i][1] = t_ave[i][2] = 0.0; tsq_ave[i][0] = tsq_ave[i][1] = tsq_ave[i][2] = 0.0; } double **x = atom->x; double **f = atom->f; int *type = atom->type; int ntype = atom->ntypes; // change neighbor list indices to Fortran indexing neigh_c2f(inum_half,ilist_half,numneigh_half,firstneigh_half); neigh_c2f(inum_half,ilist_half,numneigh_full,firstneigh_full); // 3 stages of MEAM calculation // loop over my atoms followed by communication int ifort; int offset = 0; errorflag = 0; for (ii = 0; ii < inum_half; ii++) { i = ilist_half[ii]; ifort = i+1; meam_dens_init_(&ifort,&nmax,&ntype,type,fmap,&x[0][0], &numneigh_half[i],firstneigh_half[i], &numneigh_full[i],firstneigh_full[i], &scrfcn[offset],&dscrfcn[offset],&fcpair[offset], rho0,&arho1[0][0],&arho2[0][0],arho2b, &arho3[0][0],&arho3b[0][0],&t_ave[0][0],&tsq_ave[0][0], &errorflag); if (errorflag) { char str[128]; sprintf(str,"MEAM library error %d",errorflag); error->one(FLERR,str); } offset += numneigh_half[i]; } comm->reverse_comm_pair(this); meam_dens_final_(&nlocal,&nmax,&eflag_either,&eflag_global,&eflag_atom, &eng_vdwl,eatom,&ntype,type,fmap, &arho1[0][0],&arho2[0][0],arho2b,&arho3[0][0], &arho3b[0][0],&t_ave[0][0],&tsq_ave[0][0],gamma,dgamma1, dgamma2,dgamma3,rho,rho0,rho1,rho2,rho3,frhop,&errorflag); if (errorflag) { char str[128]; sprintf(str,"MEAM library error %d",errorflag); error->one(FLERR,str); } comm->forward_comm_pair(this); offset = 0; // vptr is first value in vatom if it will be used by meam_force() // else vatom may not exist, so pass dummy ptr double *vptr; if (vflag_atom) vptr = &vatom[0][0]; else vptr = &cutmax; for (ii = 0; ii < inum_half; ii++) { i = ilist_half[ii]; ifort = i+1; meam_force_(&ifort,&nmax,&eflag_either,&eflag_global,&eflag_atom, &vflag_atom,&eng_vdwl,eatom,&ntype,type,fmap,&x[0][0], &numneigh_half[i],firstneigh_half[i], &numneigh_full[i],firstneigh_full[i], &scrfcn[offset],&dscrfcn[offset],&fcpair[offset], dgamma1,dgamma2,dgamma3,rho0,rho1,rho2,rho3,frhop, &arho1[0][0],&arho2[0][0],arho2b,&arho3[0][0],&arho3b[0][0], &t_ave[0][0],&tsq_ave[0][0],&f[0][0],vptr,&errorflag); if (errorflag) { char str[128]; sprintf(str,"MEAM library error %d",errorflag); error->one(FLERR,str); } offset += numneigh_half[i]; } // change neighbor list indices back to C indexing neigh_f2c(inum_half,ilist_half,numneigh_half,firstneigh_half); neigh_f2c(inum_half,ilist_half,numneigh_full,firstneigh_full); if (vflag_fdotr) virial_fdotr_compute(); } /* ---------------------------------------------------------------------- */ void PairMEAM::allocate() { allocated = 1; int n = atom->ntypes; memory->create(setflag,n+1,n+1,"pair:setflag"); memory->create(cutsq,n+1,n+1,"pair:cutsq"); map = new int[n+1]; fmap = new int[n]; } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairMEAM::settings(int narg, char **arg) { if (narg != 0) error->all(FLERR,"Illegal pair_style command"); } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairMEAM::coeff(int narg, char **arg) { int i,j,m,n; if (!allocated) allocate(); if (narg < 6) error->all(FLERR,"Incorrect args for pair coefficients"); // insure I,J args are * * if (strcmp(arg[0],"*") != 0 || strcmp(arg[1],"*") != 0) error->all(FLERR,"Incorrect args for pair coefficients"); // read MEAM element names between 2 filenames // nelements = # of MEAM elements // elements = list of unique element names if (nelements) { for (i = 0; i < nelements; i++) delete [] elements[i]; delete [] elements; delete [] mass; } nelements = narg - 4 - atom->ntypes; if (nelements < 1) error->all(FLERR,"Incorrect args for pair coefficients"); elements = new char*[nelements]; mass = new double[nelements]; for (i = 0; i < nelements; i++) { n = strlen(arg[i+3]) + 1; elements[i] = new char[n]; strcpy(elements[i],arg[i+3]); } // read MEAM library and parameter files // pass all parameters to MEAM package // tell MEAM package that setup is done read_files(arg[2],arg[2+nelements+1]); meam_setup_done_(&cutmax); // read args that map atom types to MEAM elements // map[i] = which element the Ith atom type is, -1 if not mapped for (i = 4 + nelements; i < narg; i++) { m = i - (4+nelements) + 1; for (j = 0; j < nelements; j++) if (strcmp(arg[i],elements[j]) == 0) break; if (j < nelements) map[m] = j; else if (strcmp(arg[i],"NULL") == 0) map[m] = -1; else error->all(FLERR,"Incorrect args for pair coefficients"); } // clear setflag since coeff() called once with I,J = * * n = atom->ntypes; for (int i = 1; i <= n; i++) for (int j = i; j <= n; j++) setflag[i][j] = 0; // set setflag i,j for type pairs where both are mapped to elements // set mass for i,i in atom class int count = 0; for (int i = 1; i <= n; i++) for (int j = i; j <= n; j++) if (map[i] >= 0 && map[j] >= 0) { setflag[i][j] = 1; if (i == j) atom->set_mass(i,mass[map[i]]); count++; } if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairMEAM::init_style() { if (force->newton_pair == 0) error->all(FLERR,"Pair style MEAM requires newton pair on"); // need full and half neighbor list int irequest_full = neighbor->request(this); neighbor->requests[irequest_full]->id = 1; neighbor->requests[irequest_full]->half = 0; neighbor->requests[irequest_full]->full = 1; int irequest_half = neighbor->request(this); neighbor->requests[irequest_half]->id = 2; neighbor->requests[irequest_half]->half = 0; neighbor->requests[irequest_half]->half_from_full = 1; neighbor->requests[irequest_half]->otherlist = irequest_full; // setup Fortran-style mapping array needed by MEAM package // fmap is indexed from 1:ntypes by Fortran and stores a Fortran index // if type I is not a MEAM atom, fmap stores a 0 for (int i = 1; i <= atom->ntypes; i++) fmap[i-1] = map[i] + 1; } /* ---------------------------------------------------------------------- neighbor callback to inform pair style of neighbor list to use half or full ------------------------------------------------------------------------- */ void PairMEAM::init_list(int id, NeighList *ptr) { if (id == 1) listfull = ptr; else if (id == 2) listhalf = ptr; } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairMEAM::init_one(int i, int j) { return cutmax; } /* ---------------------------------------------------------------------- */ void PairMEAM::read_files(char *globalfile, char *userfile) { // open global meamf file on proc 0 FILE *fp; if (comm->me == 0) { fp = fopen(globalfile,"r"); if (fp == NULL) { char str[128]; sprintf(str,"Cannot open MEAM potential file %s",globalfile); error->one(FLERR,str); } } // allocate parameter arrays int params_per_line = 19; int *lat = new int[nelements]; int *ielement = new int[nelements]; int *ibar = new int[nelements]; double *z = new double[nelements]; double *atwt = new double[nelements]; double *alpha = new double[nelements]; double *b0 = new double[nelements]; double *b1 = new double[nelements]; double *b2 = new double[nelements]; double *b3 = new double[nelements]; double *alat = new double[nelements]; double *esub = new double[nelements]; double *asub = new double[nelements]; double *t0 = new double[nelements]; double *t1 = new double[nelements]; double *t2 = new double[nelements]; double *t3 = new double[nelements]; double *rozero = new double[nelements]; bool *found = new bool[nelements]; for (int i = 0; i < nelements; i++) found[i] = false; // read each set of params from global MEAM file // one set of params can span multiple lines // store params if element name is in element list // if element name appears multiple times, only store 1st entry int i,n,nwords; char **words = new char*[params_per_line+1]; char line[MAXLINE],*ptr; int eof = 0; int nset = 0; while (1) { if (comm->me == 0) { ptr = fgets(line,MAXLINE,fp); if (ptr == NULL) { eof = 1; fclose(fp); } else n = strlen(line) + 1; } MPI_Bcast(&eof,1,MPI_INT,0,world); if (eof) break; MPI_Bcast(&n,1,MPI_INT,0,world); MPI_Bcast(line,n,MPI_CHAR,0,world); // strip comment, skip line if blank if (ptr = strchr(line,'#')) *ptr = '\0'; nwords = atom->count_words(line); if (nwords == 0) continue; // concatenate additional lines until have params_per_line words while (nwords < params_per_line) { n = strlen(line); if (comm->me == 0) { ptr = fgets(&line[n],MAXLINE-n,fp); if (ptr == NULL) { eof = 1; fclose(fp); } else n = strlen(line) + 1; } MPI_Bcast(&eof,1,MPI_INT,0,world); if (eof) break; MPI_Bcast(&n,1,MPI_INT,0,world); MPI_Bcast(line,n,MPI_CHAR,0,world); if (ptr = strchr(line,'#')) *ptr = '\0'; nwords = atom->count_words(line); } if (nwords != params_per_line) error->all(FLERR,"Incorrect format in MEAM potential file"); // words = ptrs to all words in line // strip single and double quotes from words nwords = 0; words[nwords++] = strtok(line,"' \t\n\r\f"); while (words[nwords++] = strtok(NULL,"' \t\n\r\f")) continue; // skip if element name isn't in element list for (i = 0; i < nelements; i++) if (strcmp(words[0],elements[i]) == 0) break; if (i == nelements) continue; // skip if element already appeared if (found[i] == true) continue; found[i] = true; // map lat string to an integer if (strcmp(words[1],"fcc") == 0) lat[i] = FCC; else if (strcmp(words[1],"bcc") == 0) lat[i] = BCC; else if (strcmp(words[1],"hcp") == 0) lat[i] = HCP; else if (strcmp(words[1],"dim") == 0) lat[i] = DIM; else if (strcmp(words[1],"dia") == 0) lat[i] = DIAMOND; else error->all(FLERR,"Unrecognized lattice type in MEAM file 1"); // store parameters z[i] = atof(words[2]); ielement[i] = atoi(words[3]); atwt[i] = atof(words[4]); alpha[i] = atof(words[5]); b0[i] = atof(words[6]); b1[i] = atof(words[7]); b2[i] = atof(words[8]); b3[i] = atof(words[9]); alat[i] = atof(words[10]); esub[i] = atof(words[11]); asub[i] = atof(words[12]); t0[i] = atof(words[13]); t1[i] = atof(words[14]); t2[i] = atof(words[15]); t3[i] = atof(words[16]); rozero[i] = atof(words[17]); ibar[i] = atoi(words[18]); nset++; } // error if didn't find all elements in file if (nset != nelements) error->all(FLERR,"Did not find all elements in MEAM library file"); // pass element parameters to MEAM package meam_setup_global_(&nelements,lat,z,ielement,atwt,alpha,b0,b1,b2,b3, alat,esub,asub,t0,t1,t2,t3,rozero,ibar); // set element masses for (i = 0; i < nelements; i++) mass[i] = atwt[i]; // clean-up memory delete [] words; delete [] lat; delete [] ielement; delete [] ibar; delete [] z; delete [] atwt; delete [] alpha; delete [] b0; delete [] b1; delete [] b2; delete [] b3; delete [] alat; delete [] esub; delete [] asub; delete [] t0; delete [] t1; delete [] t2; delete [] t3; delete [] rozero; delete [] found; // done if user param file is NULL if (strcmp(userfile,"NULL") == 0) return; // open user param file on proc 0 if (comm->me == 0) { fp = fopen(userfile,"r"); if (fp == NULL) { char str[128]; sprintf(str,"Cannot open MEAM potential file %s",userfile); error->one(FLERR,str); } } // read settings // pass them one at a time to MEAM package // match strings to list of corresponding ints int which; double value; int nindex,index[3]; int maxparams = 6; char **params = new char*[maxparams]; int nparams; eof = 0; while (1) { if (comm->me == 0) { ptr = fgets(line,MAXLINE,fp); if (ptr == NULL) { eof = 1; fclose(fp); } else n = strlen(line) + 1; } MPI_Bcast(&eof,1,MPI_INT,0,world); if (eof) break; MPI_Bcast(&n,1,MPI_INT,0,world); MPI_Bcast(line,n,MPI_CHAR,0,world); // strip comment, skip line if blank if (ptr = strchr(line,'#')) *ptr = '\0'; nparams = atom->count_words(line); if (nparams == 0) continue; // words = ptrs to all words in line nparams = 0; params[nparams++] = strtok(line,"=(), '\t\n\r\f"); while (nparams < maxparams && (params[nparams++] = strtok(NULL,"=(), '\t\n\r\f"))) continue; nparams--; for (which = 0; which < nkeywords; which++) if (strcmp(params[0],keywords[which]) == 0) break; if (which == nkeywords) { char str[128]; sprintf(str,"Keyword %s in MEAM parameter file not recognized", params[0]); error->all(FLERR,str); } nindex = nparams - 2; for (i = 0; i < nindex; i++) index[i] = atoi(params[i+1]); // map lattce_meam value to an integer if (which == 4) { if (strcmp(params[nparams-1],"fcc") == 0) value = FCC; else if (strcmp(params[nparams-1],"bcc") == 0) value = BCC; else if (strcmp(params[nparams-1],"hcp") == 0) value = HCP; else if (strcmp(params[nparams-1],"dim") == 0) value = DIM; else if (strcmp(params[nparams-1],"dia") == 0) value = DIAMOND; else if (strcmp(params[nparams-1],"b1") == 0) value = B1; else if (strcmp(params[nparams-1],"c11") == 0) value = C11; else if (strcmp(params[nparams-1],"l12") == 0) value = L12; else if (strcmp(params[nparams-1],"b2") == 0) value = B2; else error->all(FLERR,"Unrecognized lattice type in MEAM file 2"); } else value = atof(params[nparams-1]); // pass single setting to MEAM package int errorflag = 0; meam_setup_param_(&which,&value,&nindex,index,&errorflag); if (errorflag) { char str[128]; sprintf(str,"MEAM library error %d",errorflag); error->all(FLERR,str); } } delete [] params; } /* ---------------------------------------------------------------------- */ int PairMEAM::pack_comm(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,k,m; m = 0; for (i = 0; i < n; i++) { j = list[i]; buf[m++] = rho0[j]; buf[m++] = rho1[j]; buf[m++] = rho2[j]; buf[m++] = rho3[j]; buf[m++] = frhop[j]; buf[m++] = gamma[j]; buf[m++] = dgamma1[j]; buf[m++] = dgamma2[j]; buf[m++] = dgamma3[j]; buf[m++] = arho2b[j]; buf[m++] = arho1[j][0]; buf[m++] = arho1[j][1]; buf[m++] = arho1[j][2]; buf[m++] = arho2[j][0]; buf[m++] = arho2[j][1]; buf[m++] = arho2[j][2]; buf[m++] = arho2[j][3]; buf[m++] = arho2[j][4]; buf[m++] = arho2[j][5]; for (k = 0; k < 10; k++) buf[m++] = arho3[j][k]; buf[m++] = arho3b[j][0]; buf[m++] = arho3b[j][1]; buf[m++] = arho3b[j][2]; buf[m++] = t_ave[j][0]; buf[m++] = t_ave[j][1]; buf[m++] = t_ave[j][2]; buf[m++] = tsq_ave[j][0]; buf[m++] = tsq_ave[j][1]; buf[m++] = tsq_ave[j][2]; } return comm_forward; } /* ---------------------------------------------------------------------- */ void PairMEAM::unpack_comm(int n, int first, double *buf) { int i,k,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { rho0[i] = buf[m++]; rho1[i] = buf[m++]; rho2[i] = buf[m++]; rho3[i] = buf[m++]; frhop[i] = buf[m++]; gamma[i] = buf[m++]; dgamma1[i] = buf[m++]; dgamma2[i] = buf[m++]; dgamma3[i] = buf[m++]; arho2b[i] = buf[m++]; arho1[i][0] = buf[m++]; arho1[i][1] = buf[m++]; arho1[i][2] = buf[m++]; arho2[i][0] = buf[m++]; arho2[i][1] = buf[m++]; arho2[i][2] = buf[m++]; arho2[i][3] = buf[m++]; arho2[i][4] = buf[m++]; arho2[i][5] = buf[m++]; for (k = 0; k < 10; k++) arho3[i][k] = buf[m++]; arho3b[i][0] = buf[m++]; arho3b[i][1] = buf[m++]; arho3b[i][2] = buf[m++]; t_ave[i][0] = buf[m++]; t_ave[i][1] = buf[m++]; t_ave[i][2] = buf[m++]; tsq_ave[i][0] = buf[m++]; tsq_ave[i][1] = buf[m++]; tsq_ave[i][2] = buf[m++]; } } /* ---------------------------------------------------------------------- */ int PairMEAM::pack_reverse_comm(int n, int first, double *buf) { int i,k,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { buf[m++] = rho0[i]; buf[m++] = arho2b[i]; buf[m++] = arho1[i][0]; buf[m++] = arho1[i][1]; buf[m++] = arho1[i][2]; buf[m++] = arho2[i][0]; buf[m++] = arho2[i][1]; buf[m++] = arho2[i][2]; buf[m++] = arho2[i][3]; buf[m++] = arho2[i][4]; buf[m++] = arho2[i][5]; for (k = 0; k < 10; k++) buf[m++] = arho3[i][k]; buf[m++] = arho3b[i][0]; buf[m++] = arho3b[i][1]; buf[m++] = arho3b[i][2]; buf[m++] = t_ave[i][0]; buf[m++] = t_ave[i][1]; buf[m++] = t_ave[i][2]; buf[m++] = tsq_ave[i][0]; buf[m++] = tsq_ave[i][1]; buf[m++] = tsq_ave[i][2]; } return comm_reverse; } /* ---------------------------------------------------------------------- */ void PairMEAM::unpack_reverse_comm(int n, int *list, double *buf) { int i,j,k,m; m = 0; for (i = 0; i < n; i++) { j = list[i]; rho0[j] += buf[m++]; arho2b[j] += buf[m++]; arho1[j][0] += buf[m++]; arho1[j][1] += buf[m++]; arho1[j][2] += buf[m++]; arho2[j][0] += buf[m++]; arho2[j][1] += buf[m++]; arho2[j][2] += buf[m++]; arho2[j][3] += buf[m++]; arho2[j][4] += buf[m++]; arho2[j][5] += buf[m++]; for (k = 0; k < 10; k++) arho3[j][k] += buf[m++]; arho3b[j][0] += buf[m++]; arho3b[j][1] += buf[m++]; arho3b[j][2] += buf[m++]; t_ave[j][0] += buf[m++]; t_ave[j][1] += buf[m++]; t_ave[j][2] += buf[m++]; tsq_ave[j][0] += buf[m++]; tsq_ave[j][1] += buf[m++]; tsq_ave[j][2] += buf[m++]; } } /* ---------------------------------------------------------------------- memory usage of local atom-based arrays ------------------------------------------------------------------------- */ double PairMEAM::memory_usage() { double bytes = 11 * nmax * sizeof(double); bytes += (3 + 6 + 10 + 3 + 3 + 3) * nmax * sizeof(double); bytes += 3 * maxneigh * sizeof(double); return bytes; } /* ---------------------------------------------------------------------- strip special bond flags from neighbor list entries are not used with MEAM need to do here so Fortran lib doesn't see them done once per reneighbor so that neigh_f2c and neigh_c2f don't see them ------------------------------------------------------------------------- */ void PairMEAM::neigh_strip(int inum, int *ilist, int *numneigh, int **firstneigh) { int i,j,ii,jnum; int *jlist; for (ii = 0; ii < inum; ii++) { i = ilist[ii]; jlist = firstneigh[i]; jnum = numneigh[i]; for (j = 0; j < jnum; j++) jlist[j] &= NEIGHMASK; } } /* ---------------------------------------------------------------------- toggle neighbor list indices between zero- and one-based values needed for access by MEAM Fortran library ------------------------------------------------------------------------- */ void PairMEAM::neigh_f2c(int inum, int *ilist, int *numneigh, int **firstneigh) { int i,j,ii,jnum; int *jlist; for (ii = 0; ii < inum; ii++) { i = ilist[ii]; jlist = firstneigh[i]; jnum = numneigh[i]; for (j = 0; j < jnum; j++) jlist[j]--; } } void PairMEAM::neigh_c2f(int inum, int *ilist, int *numneigh, int **firstneigh) { int i,j,ii,jnum; int *jlist; for (ii = 0; ii < inum; ii++) { i = ilist[ii]; jlist = firstneigh[i]; jnum = numneigh[i]; for (j = 0; j < jnum; j++) jlist[j]++; } } diff --git a/src/MOLECULE/pair_lj_charmm_coul_charmm.cpp b/src/MOLECULE/pair_lj_charmm_coul_charmm.cpp index 1a4aeed1d..bb67d9ca9 100644 --- a/src/MOLECULE/pair_lj_charmm_coul_charmm.cpp +++ b/src/MOLECULE/pair_lj_charmm_coul_charmm.cpp @@ -1,508 +1,508 @@ /* ---------------------------------------------------------------------- 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 author: Paul Crozier (SNL) ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "pair_lj_charmm_coul_charmm.h" #include "atom.h" #include "comm.h" #include "force.h" #include "neighbor.h" #include "neigh_list.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; enum{GEOMETRIC,ARITHMETIC,SIXTHPOWER}; // same as in pair.cpp /* ---------------------------------------------------------------------- */ PairLJCharmmCoulCharmm::PairLJCharmmCoulCharmm(LAMMPS *lmp) : Pair(lmp) { implicit = 0; mix_flag = ARITHMETIC; } /* ---------------------------------------------------------------------- */ PairLJCharmmCoulCharmm::~PairLJCharmmCoulCharmm() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(epsilon); memory->destroy(sigma); memory->destroy(eps14); memory->destroy(sigma14); memory->destroy(lj1); memory->destroy(lj2); memory->destroy(lj3); memory->destroy(lj4); memory->destroy(lj14_1); memory->destroy(lj14_2); memory->destroy(lj14_3); memory->destroy(lj14_4); } } /* ---------------------------------------------------------------------- */ void PairLJCharmmCoulCharmm::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair; double rsq,r2inv,r6inv,forcecoul,forcelj,factor_coul,factor_lj; double philj,switch1,switch2; int *ilist,*jlist,*numneigh,**firstneigh; evdwl = ecoul = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; double **x = atom->x; double **f = atom->f; double *q = atom->q; int *type = atom->type; int nlocal = atom->nlocal; double *special_coul = force->special_coul; double *special_lj = force->special_lj; int newton_pair = force->newton_pair; double qqrd2e = force->qqrd2e; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // loop over neighbors of my atoms for (ii = 0; ii < inum; ii++) { i = ilist[ii]; qtmp = q[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; factor_lj = special_lj[sbmask(j)]; factor_coul = special_coul[sbmask(j)]; j &= NEIGHMASK; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; if (rsq < cut_bothsq) { r2inv = 1.0/rsq; if (rsq < cut_coulsq) { forcecoul = qqrd2e * qtmp*q[j]*sqrt(r2inv); if (rsq > cut_coul_innersq) { switch1 = (cut_coulsq-rsq) * (cut_coulsq-rsq) * (cut_coulsq + 2.0*rsq - 3.0*cut_coul_innersq) / denom_coul; switch2 = 12.0*rsq * (cut_coulsq-rsq) * (rsq-cut_coul_innersq) / denom_coul; forcecoul *= switch1 + switch2; } } else forcecoul = 0.0; if (rsq < cut_ljsq) { r6inv = r2inv*r2inv*r2inv; jtype = type[j]; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); if (rsq > cut_lj_innersq) { switch1 = (cut_ljsq-rsq) * (cut_ljsq-rsq) * (cut_ljsq + 2.0*rsq - 3.0*cut_lj_innersq) / denom_lj; switch2 = 12.0*rsq * (cut_ljsq-rsq) * (rsq-cut_lj_innersq) / denom_lj; philj = r6inv * (lj3[itype][jtype]*r6inv - lj4[itype][jtype]); forcelj = forcelj*switch1 + philj*switch2; } } else forcelj = 0.0; fpair = (factor_coul*forcecoul + factor_lj*forcelj) * r2inv; f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; if (newton_pair || j < nlocal) { f[j][0] -= delx*fpair; f[j][1] -= dely*fpair; f[j][2] -= delz*fpair; } if (eflag) { if (rsq < cut_coulsq) { ecoul = qqrd2e * qtmp*q[j]*sqrt(r2inv); if (rsq > cut_coul_innersq) { switch1 = (cut_coulsq-rsq) * (cut_coulsq-rsq) * (cut_coulsq + 2.0*rsq - 3.0*cut_coul_innersq) / denom_coul; ecoul *= switch1; } ecoul *= factor_coul; } else ecoul = 0.0; if (rsq < cut_ljsq) { evdwl = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]); if (rsq > cut_lj_innersq) { switch1 = (cut_ljsq-rsq) * (cut_ljsq-rsq) * (cut_ljsq + 2.0*rsq - 3.0*cut_lj_innersq) / denom_lj; evdwl *= switch1; } evdwl *= factor_lj; } else evdwl = 0.0; } if (evflag) ev_tally(i,j,nlocal,newton_pair, evdwl,ecoul,fpair,delx,dely,delz); } } } if (vflag_fdotr) virial_fdotr_compute(); } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairLJCharmmCoulCharmm::allocate() { allocated = 1; int n = atom->ntypes; memory->create(setflag,n+1,n+1,"pair:setflag"); for (int i = 1; i <= n; i++) for (int j = i; j <= n; j++) setflag[i][j] = 0; memory->create(cutsq,n+1,n+1,"pair:cutsq"); memory->create(epsilon,n+1,n+1,"pair:epsilon"); memory->create(sigma,n+1,n+1,"pair:sigma"); memory->create(eps14,n+1,n+1,"pair:eps14"); memory->create(sigma14,n+1,n+1,"pair:sigma14"); memory->create(lj1,n+1,n+1,"pair:lj1"); memory->create(lj2,n+1,n+1,"pair:lj2"); memory->create(lj3,n+1,n+1,"pair:lj3"); memory->create(lj4,n+1,n+1,"pair:lj4"); memory->create(lj14_1,n+1,n+1,"pair:lj14_1"); memory->create(lj14_2,n+1,n+1,"pair:lj14_2"); memory->create(lj14_3,n+1,n+1,"pair:lj14_3"); memory->create(lj14_4,n+1,n+1,"pair:lj14_4"); } /* ---------------------------------------------------------------------- global settings unlike other pair styles, there are no individual pair settings that these override ------------------------------------------------------------------------- */ void PairLJCharmmCoulCharmm::settings(int narg, char **arg) { if (narg != 2 && narg != 4) error->all(FLERR,"Illegal pair_style command"); cut_lj_inner = force->numeric(arg[0]); cut_lj = force->numeric(arg[1]); if (narg == 2) { cut_coul_inner = cut_lj_inner; cut_coul = cut_lj; } else { cut_coul_inner = force->numeric(arg[2]); cut_coul = force->numeric(arg[3]); } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairLJCharmmCoulCharmm::coeff(int narg, char **arg) { if (narg != 4 && narg != 6) error->all(FLERR,"Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(arg[2]); double sigma_one = force->numeric(arg[3]); double eps14_one = epsilon_one; double sigma14_one = sigma_one; if (narg == 6) { eps14_one = force->numeric(arg[4]); sigma14_one = force->numeric(arg[5]); } int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { epsilon[i][j] = epsilon_one; sigma[i][j] = sigma_one; eps14[i][j] = eps14_one; sigma14[i][j] = sigma14_one; setflag[i][j] = 1; count++; } } if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairLJCharmmCoulCharmm::init_style() { if (!atom->q_flag) error->all(FLERR, "Pair style lj/charmm/coul/charmm requires atom attribute q"); neighbor->request(this); // require cut_lj_inner < cut_lj, cut_coul_inner < cut_coul if (cut_lj_inner >= cut_lj || cut_coul_inner >= cut_coul) error->all(FLERR,"Pair inner cutoff >= Pair outer cutoff"); cut_lj_innersq = cut_lj_inner * cut_lj_inner; cut_ljsq = cut_lj * cut_lj; cut_coul_innersq = cut_coul_inner * cut_coul_inner; cut_coulsq = cut_coul * cut_coul; cut_bothsq = MAX(cut_ljsq,cut_coulsq); denom_lj = (cut_ljsq-cut_lj_innersq) * (cut_ljsq-cut_lj_innersq) * (cut_ljsq-cut_lj_innersq); denom_coul = (cut_coulsq-cut_coul_innersq) * (cut_coulsq-cut_coul_innersq) * (cut_coulsq-cut_coul_innersq); } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairLJCharmmCoulCharmm::init_one(int i, int j) { if (setflag[i][j] == 0) { epsilon[i][j] = mix_energy(epsilon[i][i],epsilon[j][j], sigma[i][i],sigma[j][j]); sigma[i][j] = mix_distance(sigma[i][i],sigma[j][j]); eps14[i][j] = mix_energy(eps14[i][i],eps14[j][j], sigma14[i][i],sigma14[j][j]); sigma14[i][j] = mix_distance(sigma14[i][i],sigma14[j][j]); } double cut = MAX(cut_lj,cut_coul); lj1[i][j] = 48.0 * epsilon[i][j] * pow(sigma[i][j],12.0); lj2[i][j] = 24.0 * epsilon[i][j] * pow(sigma[i][j],6.0); lj3[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],12.0); lj4[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],6.0); lj14_1[i][j] = 48.0 * eps14[i][j] * pow(sigma14[i][j],12.0); lj14_2[i][j] = 24.0 * eps14[i][j] * pow(sigma14[i][j],6.0); lj14_3[i][j] = 4.0 * eps14[i][j] * pow(sigma14[i][j],12.0); lj14_4[i][j] = 4.0 * eps14[i][j] * pow(sigma14[i][j],6.0); lj1[j][i] = lj1[i][j]; lj2[j][i] = lj2[i][j]; lj3[j][i] = lj3[i][j]; lj4[j][i] = lj4[i][j]; lj14_1[j][i] = lj14_1[i][j]; lj14_2[j][i] = lj14_2[i][j]; lj14_3[j][i] = lj14_3[i][j]; lj14_4[j][i] = lj14_4[i][j]; return cut; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJCharmmCoulCharmm::write_restart(FILE *fp) { write_restart_settings(fp); int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { fwrite(&setflag[i][j],sizeof(int),1,fp); if (setflag[i][j]) { fwrite(&epsilon[i][j],sizeof(double),1,fp); fwrite(&sigma[i][j],sizeof(double),1,fp); fwrite(&eps14[i][j],sizeof(double),1,fp); fwrite(&sigma14[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJCharmmCoulCharmm::read_restart(FILE *fp) { read_restart_settings(fp); allocate(); int i,j; int me = comm->me; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp); MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world); if (setflag[i][j]) { if (me == 0) { fread(&epsilon[i][j],sizeof(double),1,fp); fread(&sigma[i][j],sizeof(double),1,fp); fread(&eps14[i][j],sizeof(double),1,fp); fread(&sigma14[i][j],sizeof(double),1,fp); } MPI_Bcast(&epsilon[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&eps14[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&sigma14[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJCharmmCoulCharmm::write_restart_settings(FILE *fp) { fwrite(&cut_lj_inner,sizeof(double),1,fp); fwrite(&cut_lj,sizeof(double),1,fp); fwrite(&cut_coul_inner,sizeof(double),1,fp); fwrite(&cut_coul,sizeof(double),1,fp); fwrite(&offset_flag,sizeof(int),1,fp); fwrite(&mix_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJCharmmCoulCharmm::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&cut_lj_inner,sizeof(double),1,fp); fread(&cut_lj,sizeof(double),1,fp); fread(&cut_coul_inner,sizeof(double),1,fp); fread(&cut_coul,sizeof(double),1,fp); fread(&offset_flag,sizeof(int),1,fp); fread(&mix_flag,sizeof(int),1,fp); } MPI_Bcast(&cut_lj_inner,1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_lj,1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_coul_inner,1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_coul,1,MPI_DOUBLE,0,world); MPI_Bcast(&offset_flag,1,MPI_INT,0,world); MPI_Bcast(&mix_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- */ double PairLJCharmmCoulCharmm::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r2inv,r6inv,forcecoul,forcelj,phicoul,philj; double switch1,switch2; r2inv = 1.0/rsq; if (rsq < cut_coulsq) { forcecoul = force->qqrd2e * atom->q[i]*atom->q[j]*sqrt(r2inv); if (rsq > cut_coul_innersq) { switch1 = (cut_coulsq-rsq) * (cut_coulsq-rsq) * (cut_coulsq + 2.0*rsq - 3.0*cut_coul_innersq) / denom_coul; switch2 = 12.0*rsq * (cut_coulsq-rsq) * (rsq-cut_coul_innersq) / denom_coul; forcecoul *= switch1 + switch2; } } else forcecoul = 0.0; if (rsq < cut_ljsq) { r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); if (rsq > cut_lj_innersq) { switch1 = (cut_ljsq-rsq) * (cut_ljsq-rsq) * (cut_ljsq + 2.0*rsq - 3.0*cut_lj_innersq) / denom_lj; switch2 = 12.0*rsq * (cut_ljsq-rsq) * (rsq-cut_lj_innersq) / denom_lj; philj = r6inv * (lj3[itype][jtype]*r6inv - lj4[itype][jtype]); forcelj = forcelj*switch1 + philj*switch2; } } else forcelj = 0.0; fforce = (factor_coul*forcecoul + factor_lj*forcelj) * r2inv; double eng = 0.0; if (rsq < cut_coulsq) { phicoul = force->qqrd2e * atom->q[i]*atom->q[j]*sqrt(r2inv); if (rsq > cut_coul_innersq) { switch1 = (cut_coulsq-rsq) * (cut_coulsq-rsq) * (cut_coulsq + 2.0*rsq - 3.0*cut_coul_innersq) / denom_coul; phicoul *= switch1; } eng += factor_coul*phicoul; } if (rsq < cut_ljsq) { philj = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]); if (rsq > cut_lj_innersq) { switch1 = (cut_ljsq-rsq) * (cut_ljsq-rsq) * (cut_ljsq + 2.0*rsq - 3.0*cut_lj_innersq) / denom_lj; philj *= switch1; } eng += factor_lj*philj; } return eng; } /* ---------------------------------------------------------------------- */ -void *PairLJCharmmCoulCharmm::extract(char *str, int &dim) +void *PairLJCharmmCoulCharmm::extract(const char *str, int &dim) { dim = 2; if (strcmp(str,"lj14_1") == 0) return (void *) lj14_1; if (strcmp(str,"lj14_2") == 0) return (void *) lj14_2; if (strcmp(str,"lj14_3") == 0) return (void *) lj14_3; if (strcmp(str,"lj14_4") == 0) return (void *) lj14_4; dim = 0; if (strcmp(str,"implicit") == 0) return (void *) &implicit; return NULL; } diff --git a/src/MOLECULE/pair_lj_charmm_coul_charmm.h b/src/MOLECULE/pair_lj_charmm_coul_charmm.h index 4e85a54c5..03e453d9e 100644 --- a/src/MOLECULE/pair_lj_charmm_coul_charmm.h +++ b/src/MOLECULE/pair_lj_charmm_coul_charmm.h @@ -1,80 +1,80 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ #ifdef PAIR_CLASS PairStyle(lj/charmm/coul/charmm,PairLJCharmmCoulCharmm) #else #ifndef LMP_PAIR_LJ_CHARMM_COUL_CHARMM_H #define LMP_PAIR_LJ_CHARMM_COUL_CHARMM_H #include "pair.h" namespace LAMMPS_NS { class PairLJCharmmCoulCharmm : public Pair { public: PairLJCharmmCoulCharmm(class LAMMPS *); virtual ~PairLJCharmmCoulCharmm(); virtual void compute(int, int); void settings(int, char **); void coeff(int, char **); void init_style(); double init_one(int, int); void write_restart(FILE *); void read_restart(FILE *); void write_restart_settings(FILE *); void read_restart_settings(FILE *); virtual double single(int, int, int, int, double, double, double, double &); - virtual void *extract(char *, int &); + virtual void *extract(const char *, int &); protected: int implicit; double cut_lj_inner,cut_lj,cut_coul_inner,cut_coul; double cut_lj_innersq,cut_ljsq,cut_coul_innersq,cut_coulsq,cut_bothsq; double denom_lj,denom_coul; double **epsilon,**sigma,**eps14,**sigma14; double **lj1,**lj2,**lj3,**lj4; double **lj14_1,**lj14_2,**lj14_3,**lj14_4; void allocate(); }; } #endif #endif /* ERROR/WARNING messages: E: Illegal ... command Self-explanatory. Check the input script syntax and compare to the documentation for the command. You can use -echo screen as a command-line option when running LAMMPS to see the offending line. E: Incorrect args for pair coefficients Self-explanatory. Check the input script or data file. E: Pair style lj/charmm/coul/charmm requires atom attribute q The atom style defined does not have these attributes. E: Pair inner cutoff >= Pair outer cutoff The specified cutoffs for the pair style are inconsistent. */ diff --git a/src/REPLICA/compute_event_displace.cpp b/src/REPLICA/compute_event_displace.cpp index 3f5f401c4..fb2e13298 100644 --- a/src/REPLICA/compute_event_displace.cpp +++ b/src/REPLICA/compute_event_displace.cpp @@ -1,157 +1,158 @@ /* ---------------------------------------------------------------------- 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 author: Mike Brown (SNL) ------------------------------------------------------------------------- */ #include "mpi.h" #include "math.h" #include "stdlib.h" #include "string.h" #include "compute_event_displace.h" #include "atom.h" #include "domain.h" #include "modify.h" #include "fix_event.h" #include "memory.h" #include "error.h" #include "update.h" using namespace LAMMPS_NS; #define INVOKED_SCALAR 1 /* ---------------------------------------------------------------------- */ ComputeEventDisplace::ComputeEventDisplace(LAMMPS *lmp, int narg, char **arg) : Compute(lmp, narg, arg) { if (narg != 4) error->all(FLERR,"Illegal compute event/displace command"); scalar_flag = 1; extscalar = 0; double displace_dist = atof(arg[3]); if (displace_dist <= 0.0) error->all(FLERR,"Distance must be > 0 for compute event/displace"); displace_distsq = displace_dist * displace_dist; // fix event ID will be set later by PRD id_event = NULL; } /* ---------------------------------------------------------------------- */ ComputeEventDisplace::~ComputeEventDisplace() { delete [] id_event; } /* ---------------------------------------------------------------------- */ void ComputeEventDisplace::init() { // if id_event is not set, this compute is not active // if set by PRD, then find fix which stores original atom coords // check if it is correct style if (id_event != NULL) { int ifix = modify->find_fix(id_event); - if (ifix < 0) error->all(FLERR,"Could not find compute event/displace fix ID"); + if (ifix < 0) error->all(FLERR, + "Could not find compute event/displace fix ID"); fix_event = (FixEvent*) modify->fix[ifix]; if (strcmp(fix_event->style,"EVENT/PRD") != 0 && strcmp(fix_event->style,"EVENT/TAD") != 0) error->all(FLERR,"Compute event/displace has invalid fix event assigned"); } triclinic = domain->triclinic; } /* ---------------------------------------------------------------------- return non-zero if an atom has moved > displace_dist since last event ------------------------------------------------------------------------- */ double ComputeEventDisplace::compute_scalar() { invoked_scalar = update->ntimestep; if (id_event == NULL) return 0.0; double event = 0.0; double **xevent = fix_event->array_atom; double **x = atom->x; int *mask = atom->mask; int *image = atom->image; int nlocal = atom->nlocal; double *h = domain->h; double xprd = domain->xprd; double yprd = domain->yprd; double zprd = domain->zprd; int xbox,ybox,zbox; double dx,dy,dz,rsq; if (triclinic == 0) { for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { xbox = (image[i] & 1023) - 512; ybox = (image[i] >> 10 & 1023) - 512; zbox = (image[i] >> 20) - 512; dx = x[i][0] + xbox*xprd - xevent[i][0]; dy = x[i][1] + ybox*yprd - xevent[i][1]; dz = x[i][2] + zbox*zprd - xevent[i][2]; rsq = dx*dx + dy*dy + dz*dz; if (rsq >= displace_distsq) { event = 1.0; break; } } } else { for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { xbox = (image[i] & 1023) - 512; ybox = (image[i] >> 10 & 1023) - 512; zbox = (image[i] >> 20) - 512; dx = x[i][0] + h[0]*xbox + h[5]*ybox + h[4]*zbox - xevent[i][0]; dy = x[i][1] + h[1]*ybox + h[3]*zbox - xevent[i][1]; dz = x[i][2] + h[2]*zbox - xevent[i][2]; rsq = dx*dx + dy*dy + dz*dz; if (rsq >= displace_distsq) { event = 1.0; break; } } } MPI_Allreduce(&event,&scalar,1,MPI_DOUBLE,MPI_SUM,world); return scalar; } /* ---------------------------------------------------------------------- */ -void ComputeEventDisplace::reset_extra_compute_fix(char *id_new) +void ComputeEventDisplace::reset_extra_compute_fix(const char *id_new) { delete [] id_event; id_event = NULL; if (id_new == NULL) return; int n = strlen(id_new) + 1; id_event = new char[n]; strcpy(id_event,id_new); } diff --git a/src/REPLICA/compute_event_displace.h b/src/REPLICA/compute_event_displace.h index a8b197b84..87135d2be 100644 --- a/src/REPLICA/compute_event_displace.h +++ b/src/REPLICA/compute_event_displace.h @@ -1,68 +1,68 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ #ifdef COMPUTE_CLASS ComputeStyle(event/displace,ComputeEventDisplace) #else #ifndef LMP_COMPUTE_EVENT_DISPLACE_H #define LMP_COMPUTE_EVENT_DISPLACE_H #include "compute.h" namespace LAMMPS_NS { class ComputeEventDisplace : public Compute { public: ComputeEventDisplace(class LAMMPS *, int, char **); ~ComputeEventDisplace(); void init(); double compute_scalar(); - void reset_extra_compute_fix(char *); + void reset_extra_compute_fix(const char *); private: int triclinic; double displace_distsq; char *id_event; class FixEvent *fix_event; }; } #endif #endif /* ERROR/WARNING messages: E: Illegal ... command Self-explanatory. Check the input script syntax and compare to the documentation for the command. You can use -echo screen as a command-line option when running LAMMPS to see the offending line. E: Distance must be > 0 for compute event/displace Self-explanatory. E: Could not find compute event/displace fix ID Self-explanatory. E: Compute event/displace has invalid fix event assigned This is an internal LAMMPS error. Please report it to the developers. */ diff --git a/src/REPLICA/prd.cpp b/src/REPLICA/prd.cpp index ff20afe73..cc0ec9d0c 100644 --- a/src/REPLICA/prd.cpp +++ b/src/REPLICA/prd.cpp @@ -1,822 +1,822 @@ /* ---------------------------------------------------------------------- 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 author: Mike Brown (SNL) ------------------------------------------------------------------------- */ #include "lmptype.h" #include "mpi.h" #include "math.h" #include "stdlib.h" #include "string.h" #include "prd.h" #include "universe.h" #include "update.h" #include "atom.h" #include "domain.h" #include "region.h" #include "comm.h" #include "velocity.h" #include "integrate.h" #include "min.h" #include "neighbor.h" #include "modify.h" #include "compute.h" #include "fix.h" #include "fix_event_prd.h" #include "force.h" #include "pair.h" #include "random_park.h" #include "random_mars.h" #include "output.h" #include "dump.h" #include "finish.h" #include "timer.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ PRD::PRD(LAMMPS *lmp) : Pointers(lmp) {} /* ---------------------------------------------------------------------- perform PRD simulation on one or more replicas ------------------------------------------------------------------------- */ void PRD::command(int narg, char **arg) { int flag,ireplica; // error checks if (domain->box_exist == 0) error->all(FLERR,"PRD command before simulation box is defined"); if (universe->nworlds != universe->nprocs && atom->map_style == 0) error->all(FLERR,"Cannot use PRD with multi-processor replicas " "unless atom map exists"); if (universe->nworlds == 1 && comm->me == 0) error->warning(FLERR,"Running PRD with only one replica"); if (narg < 7) error->universe_all(FLERR,"Illegal prd command"); nsteps = atoi(arg[0]); t_event = atoi(arg[1]); n_dephase = atoi(arg[2]); t_dephase = atoi(arg[3]); t_corr = atoi(arg[4]); char id_compute[strlen(arg[5])+1]; strcpy(id_compute,arg[5]); int seed = atoi(arg[6]); options(narg-7,&arg[7]); // total # of timesteps must be multiple of t_event if (t_event <= 0) error->universe_all(FLERR,"Invalid t_event in prd command"); if (nsteps % t_event) error->universe_all(FLERR,"PRD nsteps must be multiple of t_event"); if (t_corr % t_event) error->universe_all(FLERR,"PRD t_corr must be multiple of t_event"); // local storage int me_universe = universe->me; int nprocs_universe = universe->nprocs; int nreplica = universe->nworlds; int iworld = universe->iworld; MPI_Comm_rank(world,&me); MPI_Comm_size(world,&nprocs); // comm_replica = communicator between same proc across replicas // not used if replicas have unequal number of procs // equal_size_replicas = 1 if all replicas have same # of procs int color = me; MPI_Comm_split(universe->uworld,color,0,&comm_replica); flag = 0; if (nreplica*nprocs == nprocs_universe) flag = 1; MPI_Allreduce(&flag,&equal_size_replicas,1,MPI_INT,MPI_MIN,universe->uworld); // workspace for inter-replica communication via gathers natoms = atom->natoms; displacements = NULL; tagall = NULL; xall = NULL; imageall = NULL; if (nreplica != nprocs_universe) { displacements = new int[nprocs]; memory->create(tagall,natoms,"prd:tagall"); memory->create(xall,natoms,3,"prd:xall"); memory->create(imageall,natoms,"prd:imageall"); } // random_select = same RNG for each replica for multiple event selection // random_dephase = unique RNG for each replica for dephasing random_select = new RanPark(lmp,seed); random_dephase = new RanMars(lmp,seed+iworld); // create ComputeTemp class to monitor temperature char **args = new char*[3]; args[0] = (char *) "prd_temp"; args[1] = (char *) "all"; args[2] = (char *) "temp"; modify->add_compute(3,args); temperature = modify->compute[modify->ncompute-1]; // create Velocity class for velocity creation in dephasing // pass it temperature compute, loop_setting, dist_setting settings atom->check_mass(); velocity = new Velocity(lmp); velocity->init_external("all"); args[0] = (char *) "temp"; args[1] = (char *) "prd_temp"; velocity->options(2,args); args[0] = (char *) "loop"; args[1] = (char *) loop_setting; if (loop_setting) velocity->options(2,args); args[0] = (char *) "dist"; args[1] = (char *) dist_setting; if (dist_setting) velocity->options(2,args); // create FixEventPRD class to store event and pre-quench states args[0] = (char *) "prd_event"; args[1] = (char *) "all"; args[2] = (char *) "EVENT/PRD"; modify->add_fix(3,args); fix_event = (FixEventPRD *) modify->fix[modify->nfix-1]; // create Finish for timing output finish = new Finish(lmp); // string clean-up delete [] args; delete [] loop_setting; delete [] dist_setting; // assign FixEventPRD to event-detection compute // necessary so it will know atom coords at last event int icompute = modify->find_compute(id_compute); if (icompute < 0) error->all(FLERR,"Could not find compute ID for PRD"); compute_event = modify->compute[icompute]; compute_event->reset_extra_compute_fix("prd_event"); // reset reneighboring criteria since will perform minimizations neigh_every = neighbor->every; neigh_delay = neighbor->delay; neigh_dist_check = neighbor->dist_check; if (neigh_every != 1 || neigh_delay != 0 || neigh_dist_check != 1) { if (me == 0) error->warning(FLERR,"Resetting reneighboring criteria during PRD"); } neighbor->every = 1; neighbor->delay = 0; neighbor->dist_check = 1; // initialize PRD as if one long dynamics run update->whichflag = 1; update->nsteps = nsteps; update->beginstep = update->firststep = update->ntimestep; update->endstep = update->laststep = update->firststep + nsteps; update->restrict_output = 1; if (update->laststep < 0 || update->laststep > MAXBIGINT) error->all(FLERR,"Too many timesteps"); lmp->init(); // init minimizer settings and minimizer itself update->etol = etol; update->ftol = ftol; update->max_eval = maxeval; update->minimize->init(); // cannot use PRD with time-dependent fixes or regions or atom sorting for (int i = 0; i < modify->nfix; i++) if (modify->fix[i]->time_depend) error->all(FLERR,"Cannot use PRD with a time-dependent fix defined"); for (int i = 0; i < domain->nregion; i++) if (domain->regions[i]->dynamic_check()) error->all(FLERR,"Cannot use PRD with a time-dependent region defined"); if (atom->sortfreq > 0) error->all(FLERR,"Cannot use PRD with atom_modify sort enabled"); // perform PRD simulation if (me_universe == 0 && universe->uscreen) fprintf(universe->uscreen,"Setting up PRD ...\n"); if (me_universe == 0) { if (universe->uscreen) fprintf(universe->uscreen,"Step CPU Clock Event " "Correlated Coincident Replica\n"); if (universe->ulogfile) fprintf(universe->ulogfile,"Step CPU Clock Event " "Correlated Coincident Replica\n"); } // store hot state and quenched event for replica 0 // use share_event() to copy that info to all replicas // this insures all start from same place // need this line if quench() does only setup_minimal() // update->minimize->setup(); fix_event->store_state(); quench(); ncoincident = 0; share_event(0,0); timer->init(); timer->barrier_start(TIME_LOOP); time_start = timer->array[TIME_LOOP]; log_event(); // do full init/setup since are starting all replicas after event // replica 0 bcasts temp to all replicas if temp_dephase is not set update->whichflag = 1; lmp->init(); update->integrate->setup(); if (temp_flag == 0) { if (universe->iworld == 0) temp_dephase = temperature->compute_scalar(); MPI_Bcast(&temp_dephase,1,MPI_DOUBLE,universe->root_proc[0], universe->uworld); } // main loop: look for events until out of time // (1) dephase independently on each proc after event // (2) loop: dynamics, store state, quench, check event, restore state // (3) share and record event nbuild = ndanger = 0; time_dephase = time_dynamics = time_quench = time_comm = time_output = 0.0; timer->barrier_start(TIME_LOOP); time_start = timer->array[TIME_LOOP]; while (update->ntimestep < update->endstep) { dephase(); ireplica = -1; while (update->ntimestep < update->endstep) { dynamics(); fix_event->store_state(); quench(); ireplica = check_event(); if (ireplica >= 0) break; fix_event->restore_state(); } if (ireplica < 0) break; // potentially more efficient for correlated events if don't // share until correlated check has completed // this will complicate the dump (always on replica 0) share_event(ireplica,1); log_event(); int restart_flag = 0; if (output->restart_every && universe->iworld == 0) if (fix_event->event_number % output->restart_every == 0) restart_flag = 1; // correlated event loop // other procs could be dephasing during this time int corr_endstep = update->ntimestep + t_corr; while (update->ntimestep < corr_endstep) { if (update->ntimestep == update->endstep) { restart_flag = 0; break; } dynamics(); fix_event->store_state(); quench(); int corr_event_check = check_event(ireplica); if (corr_event_check >= 0) { share_event(ireplica,2); log_event(); corr_endstep = update->ntimestep + t_corr; } else fix_event->restore_state(); } // full init/setup since are starting all replicas after event // event replica bcasts temp to all replicas if temp_dephase is not set update->whichflag = 1; lmp->init(); update->integrate->setup(); timer->barrier_start(TIME_LOOP); if (t_corr > 0) replicate(ireplica); if (temp_flag == 0) { if (ireplica == universe->iworld) temp_dephase = temperature->compute_scalar(); MPI_Bcast(&temp_dephase,1,MPI_DOUBLE,universe->root_proc[ireplica], universe->uworld); } timer->barrier_stop(TIME_LOOP); time_comm += timer->array[TIME_LOOP]; // write restart file of hot coords if (restart_flag) { timer->barrier_start(TIME_LOOP); output->write_restart(update->ntimestep); timer->barrier_stop(TIME_LOOP); time_output += timer->array[TIME_LOOP]; } } // set total timers and counters so Finish() will process them timer->array[TIME_LOOP] = time_start; timer->barrier_stop(TIME_LOOP); timer->array[TIME_PAIR] = time_dephase; timer->array[TIME_BOND] = time_dynamics; timer->array[TIME_KSPACE] = time_quench; timer->array[TIME_COMM] = time_comm; timer->array[TIME_OUTPUT] = time_output; neighbor->ncalls = nbuild; neighbor->ndanger = ndanger; if (me_universe == 0) { if (universe->uscreen) fprintf(universe->uscreen, "Loop time of %g on %d procs for %d steps with " BIGINT_FORMAT " atoms\n", timer->array[TIME_LOOP],nprocs_universe,nsteps,atom->natoms); if (universe->ulogfile) fprintf(universe->ulogfile, "Loop time of %g on %d procs for %d steps with " BIGINT_FORMAT " atoms\n", timer->array[TIME_LOOP],nprocs_universe,nsteps,atom->natoms); } finish->end(2); update->whichflag = 0; update->firststep = update->laststep = 0; update->beginstep = update->endstep = 0; update->restrict_output = 0; // reset reneighboring criteria neighbor->every = neigh_every; neighbor->delay = neigh_delay; neighbor->dist_check = neigh_dist_check; // clean up delete [] displacements; memory->destroy(tagall); memory->destroy(xall); memory->destroy(imageall); MPI_Comm_free(&comm_replica); delete random_select; delete random_dephase; delete velocity; delete finish; modify->delete_compute("prd_temp"); modify->delete_fix("prd_event"); compute_event->reset_extra_compute_fix(NULL); } /* ---------------------------------------------------------------------- dephasing = one or more short runs with new random velocities ------------------------------------------------------------------------- */ void PRD::dephase() { bigint ntimestep_hold = update->ntimestep; update->whichflag = 1; update->nsteps = n_dephase*t_dephase; timer->barrier_start(TIME_LOOP); for (int i = 0; i < n_dephase; i++) { int seed = static_cast (random_dephase->uniform() * MAXSMALLINT); if (seed == 0) seed = 1; velocity->create(temp_dephase,seed); update->integrate->run(t_dephase); if (temp_flag == 0) temp_dephase = temperature->compute_scalar(); } timer->barrier_stop(TIME_LOOP); time_dephase += timer->array[TIME_LOOP]; update->integrate->cleanup(); finish->end(0); // reset timestep as if dephase did not occur // clear timestep storage from computes, since now invalid update->ntimestep = ntimestep_hold; for (int i = 0; i < modify->ncompute; i++) if (modify->compute[i]->timeflag) modify->compute[i]->clearstep(); } /* ---------------------------------------------------------------------- single short dynamics run ------------------------------------------------------------------------- */ void PRD::dynamics() { update->whichflag = 1; update->nsteps = t_event; lmp->init(); update->integrate->setup(); // this may be needed if don't do full init //modify->addstep_compute_all(update->ntimestep); int ncalls = neighbor->ncalls; timer->barrier_start(TIME_LOOP); update->integrate->run(t_event); timer->barrier_stop(TIME_LOOP); time_dynamics += timer->array[TIME_LOOP]; nbuild += neighbor->ncalls - ncalls; ndanger += neighbor->ndanger; update->integrate->cleanup(); finish->end(0); } /* ---------------------------------------------------------------------- quench minimization ------------------------------------------------------------------------- */ void PRD::quench() { bigint ntimestep_hold = update->ntimestep; bigint endstep_hold = update->endstep; // need to change whichflag so that minimize->setup() calling // modify->setup() will call fix->min_setup() update->whichflag = 2; update->nsteps = maxiter; update->endstep = update->laststep = update->firststep + maxiter; if (update->laststep < 0 || update->laststep > MAXBIGINT) error->all(FLERR,"Too many iterations"); // full init works lmp->init(); update->minimize->setup(); // partial init does not work //modify->addstep_compute_all(update->ntimestep); //update->minimize->setup_minimal(1); int ncalls = neighbor->ncalls; timer->barrier_start(TIME_LOOP); update->minimize->run(maxiter); timer->barrier_stop(TIME_LOOP); time_quench += timer->array[TIME_LOOP]; if (neighbor->ncalls == ncalls) quench_reneighbor = 0; else quench_reneighbor = 1; update->minimize->cleanup(); finish->end(0); // reset timestep as if dephase did not occur // clear timestep storage from computes, since now invalid update->ntimestep = ntimestep_hold; update->endstep = update->laststep = endstep_hold; for (int i = 0; i < modify->ncompute; i++) if (modify->compute[i]->timeflag) modify->compute[i]->clearstep(); } /* ---------------------------------------------------------------------- check for an event in any replica if replica_num is non-negative only check for event on replica_num if multiple events, choose one at random return -1 if no event else return ireplica = world in which event occured ------------------------------------------------------------------------- */ int PRD::check_event(int replica_num) { int worldflag,universeflag,scanflag,replicaflag,ireplica; worldflag = 0; if (compute_event->compute_scalar() > 0.0) worldflag = 1; if (replica_num >= 0 && replica_num != universe->iworld) worldflag = 0; timer->barrier_start(TIME_LOOP); if (me == 0) MPI_Allreduce(&worldflag,&universeflag,1, MPI_INT,MPI_SUM,comm_replica); MPI_Bcast(&universeflag,1,MPI_INT,0,world); ncoincident = universeflag; if (!universeflag) ireplica = -1; else { if (universeflag > 1) { int iwhich = static_cast (universeflag*random_select->uniform()) + 1; if (me == 0) MPI_Scan(&worldflag,&scanflag,1, MPI_INT,MPI_SUM,comm_replica); MPI_Bcast(&scanflag,1,MPI_INT,0,world); if (scanflag != iwhich) worldflag = 0; } if (worldflag) replicaflag = universe->iworld; else replicaflag = 0; if (me == 0) MPI_Allreduce(&replicaflag,&ireplica,1, MPI_INT,MPI_SUM,comm_replica); MPI_Bcast(&ireplica,1,MPI_INT,0,world); } timer->barrier_stop(TIME_LOOP); time_comm += timer->array[TIME_LOOP]; return ireplica; } /* ---------------------------------------------------------------------- share quenched and hot coords owned by ireplica with all replicas all replicas store event in fix_event replica 0 dumps event snapshot flag = 0 = called before PRD run flag = 1 = called during PRD run = not correlated event flag = 2 = called during PRD run = correlated event ------------------------------------------------------------------------- */ void PRD::share_event(int ireplica, int flag) { timer->barrier_start(TIME_LOOP); // communicate quenched coords to all replicas and store as event // decrement event counter if flag = 0 since not really an event replicate(ireplica); timer->barrier_stop(TIME_LOOP); time_comm += timer->array[TIME_LOOP]; // adjust time for last correlated event check (not on first event) int corr_adjust = t_corr; if (fix_event->event_number < 1 || flag == 2) corr_adjust = 0; // delta = time since last correlated event check int delta = update->ntimestep - fix_event->event_timestep - corr_adjust; // if this is a correlated event, time elapsed only on one partition if (flag != 2) delta *= universe->nworlds; delta += corr_adjust; // don't change the clock or timestep if this is a restart if (flag == 0 && fix_event->event_number != 0) fix_event->store_event_prd(fix_event->event_timestep,0); else { fix_event->store_event_prd(update->ntimestep,delta); fix_event->replica_number = ireplica; fix_event->correlated_event = 0; if (flag == 2) fix_event->correlated_event = 1; fix_event->ncoincident = ncoincident; } if (flag == 0) fix_event->event_number--; // dump snapshot of quenched coords // must reneighbor and compute forces before dumping // since replica 0 possibly has new state from another replica // addstep_compute_all insures eng/virial are calculated if needed if (output->ndump && universe->iworld == 0) { timer->barrier_start(TIME_LOOP); modify->addstep_compute_all(update->ntimestep); update->integrate->setup_minimal(1); output->write_dump(update->ntimestep); timer->barrier_stop(TIME_LOOP); time_output += timer->array[TIME_LOOP]; } // restore and communicate hot coords to all replicas fix_event->restore_state(); timer->barrier_start(TIME_LOOP); replicate(ireplica); timer->barrier_stop(TIME_LOOP); time_comm += timer->array[TIME_LOOP]; } /* ---------------------------------------------------------------------- universe proc 0 prints event info ------------------------------------------------------------------------- */ void PRD::log_event() { timer->array[TIME_LOOP] = time_start; if (universe->me == 0) { if (universe->uscreen) fprintf(universe->uscreen, BIGINT_FORMAT " %.3f %d %d %d %d %d\n", fix_event->event_timestep, timer->elapsed(TIME_LOOP), fix_event->clock, fix_event->event_number,fix_event->correlated_event, fix_event->ncoincident, fix_event->replica_number); if (universe->ulogfile) fprintf(universe->ulogfile, BIGINT_FORMAT " %.3f %d %d %d %d %d\n", fix_event->event_timestep, timer->elapsed(TIME_LOOP), fix_event->clock, fix_event->event_number,fix_event->correlated_event, fix_event->ncoincident, fix_event->replica_number); } } /* ---------------------------------------------------------------------- communicate atom coords and image flags in ireplica to all other replicas one proc per replica: direct overwrite via bcast equal procs per replica and no replica reneighbored: direct overwrite via bcast unequal procs per replica or reneighboring occurred: collect to root proc of event replica bcast to roots of other replicas bcast within each replica each proc extracts info for atoms it owns using atom IDs ------------------------------------------------------------------------- */ void PRD::replicate(int ireplica) { int nreplica = universe->nworlds; int nprocs_universe = universe->nprocs; int i,m,flag,commflag; int counts[nprocs]; if (nreplica == nprocs_universe) commflag = 0; else if (equal_size_replicas) { flag = 0; if (quench_reneighbor) flag = 1; MPI_Allreduce(&flag,&commflag,1,MPI_INT,MPI_MAX,universe->uworld); } else commflag = 1; if (commflag == 0) { MPI_Bcast(atom->image,atom->nlocal,MPI_INT,ireplica,comm_replica); MPI_Bcast(atom->x[0],3*atom->nlocal,MPI_DOUBLE,ireplica,comm_replica); } else { if (universe->iworld == ireplica) { MPI_Gather(&atom->nlocal,1,MPI_INT,counts,1,MPI_INT,0,world); displacements[0] = 0; for (i = 0; i < nprocs-1; i++) displacements[i+1] = displacements[i] + counts[i]; MPI_Gatherv(atom->tag,atom->nlocal,MPI_INT, tagall,counts,displacements,MPI_INT,0,world); MPI_Gatherv(atom->image,atom->nlocal,MPI_INT, imageall,counts,displacements,MPI_INT,0,world); for (i = 0; i < nprocs; i++) counts[i] *= 3; for (i = 0; i < nprocs-1; i++) displacements[i+1] = displacements[i] + counts[i]; MPI_Gatherv(atom->x[0],3*atom->nlocal,MPI_DOUBLE, xall[0],counts,displacements,MPI_DOUBLE,0,world); } if (me == 0) { MPI_Bcast(tagall,natoms,MPI_INT,ireplica,comm_replica); MPI_Bcast(imageall,natoms,MPI_INT,ireplica,comm_replica); MPI_Bcast(xall[0],3*natoms,MPI_DOUBLE,ireplica,comm_replica); } MPI_Bcast(tagall,natoms,MPI_INT,0,world); MPI_Bcast(imageall,natoms,MPI_INT,0,world); MPI_Bcast(xall[0],3*natoms,MPI_DOUBLE,0,world); double **x = atom->x; int nlocal = atom->nlocal; for (i = 0; i < natoms; i++) { m = atom->map(tagall[i]); if (m >= 0 && m < nlocal) { x[m][0] = xall[i][0]; x[m][1] = xall[i][1]; x[m][2] = xall[i][2]; atom->image[m] = imageall[i]; } } } } /* ---------------------------------------------------------------------- parse optional parameters at end of PRD input line ------------------------------------------------------------------------- */ void PRD::options(int narg, char **arg) { if (narg < 0) error->all(FLERR,"Illegal prd command"); // set defaults etol = 0.1; ftol = 0.1; maxiter = 40; maxeval = 50; temp_flag = 0; - char *str = "geom"; + char *str = (char *) "geom"; int n = strlen(str) + 1; loop_setting = new char[n]; strcpy(loop_setting,str); - str = "gaussian"; + str = (char *) "gaussian"; n = strlen(str) + 1; dist_setting = new char[n]; strcpy(dist_setting,str); int iarg = 0; while (iarg < narg) { if (strcmp(arg[iarg],"min") == 0) { if (iarg+5 > narg) error->all(FLERR,"Illegal prd command"); etol = atof(arg[iarg+1]); ftol = atof(arg[iarg+2]); maxiter = atoi(arg[iarg+3]); maxeval = atoi(arg[iarg+4]); if (maxiter < 0) error->all(FLERR,"Illegal prd command"); iarg += 5; } else if (strcmp(arg[iarg],"temp") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal prd command"); temp_flag = 1; temp_dephase = atof(arg[iarg+1]); if (temp_dephase <= 0.0) error->all(FLERR,"Illegal prd command"); iarg += 2; } else if (strcmp(arg[iarg],"vel") == 0) { if (iarg+3 > narg) error->all(FLERR,"Illegal prd command"); delete [] loop_setting; delete [] dist_setting; if (strcmp(arg[iarg+1],"all") == 0) loop_setting = NULL; else if (strcmp(arg[iarg+1],"local") == 0) loop_setting = NULL; else if (strcmp(arg[iarg+1],"geom") == 0) loop_setting = NULL; else error->all(FLERR,"Illegal prd command"); int n = strlen(arg[iarg+1]) + 1; loop_setting = new char[n]; strcpy(loop_setting,arg[iarg+1]); if (strcmp(arg[iarg+2],"uniform") == 0) dist_setting = NULL; else if (strcmp(arg[iarg+2],"gaussian") == 0) dist_setting = NULL; else error->all(FLERR,"Illegal prd command"); n = strlen(arg[iarg+2]) + 1; dist_setting = new char[n]; strcpy(dist_setting,arg[iarg+2]); iarg += 3; } else error->all(FLERR,"Illegal prd command"); } } diff --git a/src/REPLICA/tad.cpp b/src/REPLICA/tad.cpp index 50e352ebd..9bc23ac48 100644 --- a/src/REPLICA/tad.cpp +++ b/src/REPLICA/tad.cpp @@ -1,1014 +1,1014 @@ /* ---------------------------------------------------------------------- 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 author: Aidan Thompson (SNL) ------------------------------------------------------------------------- */ #include "lmptype.h" #include "mpi.h" #include "math.h" #include "stdlib.h" #include "string.h" #include "tad.h" #include "universe.h" #include "update.h" #include "atom.h" #include "domain.h" #include "region.h" #include "comm.h" #include "velocity.h" #include "integrate.h" #include "min.h" #include "neighbor.h" #include "modify.h" #include "neb.h" #include "compute.h" #include "fix.h" #include "fix_event_tad.h" #include "fix_store_state.h" #include "force.h" #include "pair.h" #include "random_park.h" #include "random_mars.h" #include "output.h" #include "dump.h" #include "finish.h" #include "timer.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ TAD::TAD(LAMMPS *lmp) : Pointers(lmp) {} /* ---------------------------------------------------------------------- */ TAD::~TAD() { memory->sfree(fix_event_list); if (neb_logfilename != NULL) delete [] neb_logfilename; delete [] min_style; delete [] min_style_neb; } /* ---------------------------------------------------------------------- perform TAD simulation on root proc other procs only used for NEB calcs ------------------------------------------------------------------------- */ void TAD::command(int narg, char **arg) { fix_event_list = NULL; n_event_list = 0; nmax_event_list = 0; nmin_event_list = 10; // error checks if (domain->box_exist == 0) error->all(FLERR,"Tad command before simulation box is defined"); if (universe->nworlds == 1) error->all(FLERR,"Cannot use TAD with a single replica for NEB"); if (universe->nworlds != universe->nprocs) error->all(FLERR,"Can only use TAD with 1-processor replicas for NEB"); if (atom->sortfreq > 0) error->all(FLERR,"Cannot use TAD with atom_modify sort enabled for NEB"); if (atom->map_style == 0) error->all(FLERR,"Cannot use TAD unless atom map exists for NEB"); if (narg < 7) error->universe_all(FLERR,"Illegal tad command"); nsteps = atoi(arg[0]); t_event = atoi(arg[1]); templo = atof(arg[2]); temphi = atof(arg[3]); delta_conf = atof(arg[4]); tmax = atof(arg[5]); char id_compute[strlen(arg[6])+1]; strcpy(id_compute,arg[6]); options(narg-7,&arg[7]); // total # of timesteps must be multiple of t_event if (t_event <= 0) error->universe_all(FLERR,"Invalid t_event in tad command"); if (nsteps % t_event) error->universe_all(FLERR,"TAD nsteps must be multiple of t_event"); if (delta_conf <= 0.0 || delta_conf >= 1.0) error->universe_all(FLERR,"Invalid delta_conf in tad command"); if (tmax <= 0.0) error->universe_all(FLERR,"Invalid tmax in tad command"); // deltconf = (ln(1/delta))/freq_min (timestep units) deltconf = -log(delta_conf)*tmax/update->dt; // local storage int me_universe = universe->me; int nprocs_universe = universe->nprocs; MPI_Comm_rank(world,&me); MPI_Comm_size(world,&nprocs); delta_beta = (1.0/templo - 1.0/temphi) / force->boltz; ratio_beta = templo/temphi; // create FixEventTAD object to store last event int narg2 = 3; char **args = new char*[narg2]; args[0] = (char *) "tad_event"; args[1] = (char *) "all"; args[2] = (char *) "EVENT/TAD"; modify->add_fix(narg2,args); fix_event = (FixEventTAD *) modify->fix[modify->nfix-1]; delete [] args; // create FixStoreState object to store revert state narg2 = 13; args = new char*[narg2]; args[0] = (char *) "tad_revert"; args[1] = (char *) "all"; args[2] = (char *) "store/state"; args[3] = (char *) "0"; args[4] = (char *) "x"; args[5] = (char *) "y"; args[6] = (char *) "z"; args[7] = (char *) "ix"; args[8] = (char *) "iy"; args[9] = (char *) "iz"; args[10] = (char *) "vx"; args[11] = (char *) "vy"; args[12] = (char *) "vz"; modify->add_fix(narg2,args); fix_revert = (FixStoreState *) modify->fix[modify->nfix-1]; delete [] args; // create Finish for timing output finish = new Finish(lmp); // assign FixEventTAD to event-detection compute // necessary so it will know atom coords at last event int icompute = modify->find_compute(id_compute); if (icompute < 0) error->all(FLERR,"Could not find compute ID for TAD"); compute_event = modify->compute[icompute]; compute_event->reset_extra_compute_fix("tad_event"); // reset reneighboring criteria since will perform minimizations neigh_every = neighbor->every; neigh_delay = neighbor->delay; neigh_dist_check = neighbor->dist_check; if (neigh_every != 1 || neigh_delay != 0 || neigh_dist_check != 1) { if (me_universe == 0) error->warning(FLERR,"Resetting reneighboring criteria during TAD"); } neighbor->every = 1; neighbor->delay = 0; neighbor->dist_check = 1; // initialize TAD as if one long dynamics run update->whichflag = 1; update->nsteps = nsteps; update->beginstep = update->firststep = update->ntimestep; update->endstep = update->laststep = update->firststep + nsteps; update->restrict_output = 1; if (update->laststep < 0 || update->laststep > MAXBIGINT) error->all(FLERR,"Too many timesteps"); lmp->init(); // set minimize style for quench narg2 = 1; args = new char*[narg2]; args[0] = min_style; update->create_minimize(narg2,args); delete [] args; // init minimizer settings and minimizer itself update->etol = etol; update->ftol = ftol; update->max_eval = maxeval; update->minimize->init(); // perform TAD simulation if (me_universe == 0 && universe->uscreen) fprintf(universe->uscreen,"Setting up TAD ...\n"); if (me_universe == 0) { if (universe->uscreen) fprintf(universe->uscreen, "Step CPU N M Status Barrier Margin t_lo delt_lo\n" ); if (universe->ulogfile) fprintf(universe->ulogfile, "Step CPU N M Status Barrier Margin t_lo delt_lo\n" ); } ulogfile_lammps = universe->ulogfile; uscreen_lammps = universe->uscreen; ulogfile_neb = NULL; uscreen_neb = NULL; if (me_universe == 0 && neb_logfilename) ulogfile_neb = fopen(neb_logfilename,"w"); // store hot state and quenched event, only on replica 0 // need this line if quench() does only setup_minimal() // update->minimize->setup(); // This should work with if uncommented, but does not // if (universe->iworld == 0) { fix_event->store_state(); quench(); timer->init(); timer->barrier_start(TIME_LOOP); time_start = timer->array[TIME_LOOP]; fix_event->store_event_tad(update->ntimestep); log_event(0); fix_event->restore_state(); // do full init/setup update->whichflag = 1; lmp->init(); update->integrate->setup(); // } // main loop: look for events until out of time // (1) dynamics, store state, quench, check event, restore state // (2) if event, perform NEB, record in fix_event_list // (3) if confident, pick earliest event nbuild = ndanger = 0; time_neb = time_dynamics = time_quench = time_comm = time_output = 0.0; timer->barrier_start(TIME_LOOP); time_start = timer->array[TIME_LOOP]; int confident_flag, event_flag; if (universe->iworld == 0) { while (update->ntimestep < update->endstep) { // initialize list of possible events initialize_event_list(); confident_flag = 0; while (update->ntimestep < update->endstep) { event_flag = 0; while (update->ntimestep < update->endstep) { dynamics(); fix_event->store_state(); quench(); event_flag = check_event(); MPI_Bcast(&event_flag,1,MPI_INT,0,universe->uworld); if (event_flag) break; // restore hot state fix_event->restore_state(); // store hot state in revert fix_revert->end_of_step(); } if (!event_flag) break; add_event(); perform_neb(n_event_list-1); compute_tlo(n_event_list-1); confident_flag = check_confidence(); MPI_Bcast(&confident_flag,1,MPI_INT,0,universe->uworld); if (confident_flag) break; if (universe->iworld == 0) revert(); } if (!confident_flag) break; perform_event(event_first); // need to sync timestep with TAD MPI_Bcast(&(update->ntimestep),1,MPI_INT,0,universe->uworld); int restart_flag = 0; if (output->restart_every && universe->iworld == 0) if (fix_event->event_number % output->restart_every == 0) restart_flag = 1; // full init/setup since are starting after event update->whichflag = 1; lmp->init(); update->integrate->setup(); // write restart file of hot coords if (restart_flag) { timer->barrier_start(TIME_LOOP); output->write_restart(update->ntimestep); timer->barrier_stop(TIME_LOOP); time_output += timer->array[TIME_LOOP]; } } } else { while (update->ntimestep < update->endstep) { confident_flag = 0; while (update->ntimestep < update->endstep) { event_flag = 0; while (update->ntimestep < update->endstep) { update->ntimestep += t_event; MPI_Bcast(&event_flag,1,MPI_INT,0,universe->uworld); if (event_flag) break; } if (!event_flag) break; perform_neb(-1); MPI_Bcast(&confident_flag,1,MPI_INT,0,universe->uworld); if (confident_flag) break; } if (!confident_flag) break; // need to sync timestep with TAD MPI_Bcast(&(update->ntimestep),1,MPI_INT,0,universe->uworld); } } // set total timers and counters so Finish() will process them timer->array[TIME_LOOP] = time_start; timer->barrier_stop(TIME_LOOP); timer->array[TIME_PAIR] = time_neb; timer->array[TIME_BOND] = time_dynamics; timer->array[TIME_KSPACE] = time_quench; timer->array[TIME_COMM] = time_comm; timer->array[TIME_OUTPUT] = time_output; neighbor->ncalls = nbuild; neighbor->ndanger = ndanger; if (me_universe == 0) { if (universe->uscreen) fprintf(universe->uscreen, "Loop time of %g on %d procs for %d steps with " BIGINT_FORMAT " atoms\n", timer->array[TIME_LOOP],nprocs_universe,nsteps,atom->natoms); if (universe->ulogfile) fprintf(universe->ulogfile, "Loop time of %g on %d procs for %d steps with " BIGINT_FORMAT " atoms\n", timer->array[TIME_LOOP],nprocs_universe,nsteps,atom->natoms); } if (me_universe == 0) fclose(ulogfile_neb); finish->end(3); update->whichflag = 0; update->firststep = update->laststep = 0; update->beginstep = update->endstep = 0; update->restrict_output = 0; // reset reneighboring criteria neighbor->every = neigh_every; neighbor->delay = neigh_delay; neighbor->dist_check = neigh_dist_check; delete finish; modify->delete_fix("tad_event"); modify->delete_fix("tad_revert"); delete_event_list(); compute_event->reset_extra_compute_fix(NULL); } /* ---------------------------------------------------------------------- single short dynamics run ------------------------------------------------------------------------- */ void TAD::dynamics() { update->whichflag = 1; update->nsteps = t_event; lmp->init(); update->integrate->setup(); // this may be needed if don't do full init //modify->addstep_compute_all(update->ntimestep); int ncalls = neighbor->ncalls; timer->barrier_start(TIME_LOOP); update->integrate->run(t_event); timer->barrier_stop(TIME_LOOP); time_dynamics += timer->array[TIME_LOOP]; nbuild += neighbor->ncalls - ncalls; ndanger += neighbor->ndanger; update->integrate->cleanup(); finish->end(0); } /* ---------------------------------------------------------------------- quench minimization ------------------------------------------------------------------------- */ void TAD::quench() { bigint ntimestep_hold = update->ntimestep; bigint endstep_hold = update->endstep; // need to change whichflag so that minimize->setup() calling // modify->setup() will call fix->min_setup() update->whichflag = 2; update->nsteps = maxiter; update->endstep = update->laststep = update->firststep + maxiter; if (update->laststep < 0 || update->laststep > MAXBIGINT) error->all(FLERR,"Too many iterations"); // full init works lmp->init(); update->minimize->setup(); // partial init does not work //modify->addstep_compute_all(update->ntimestep); //update->minimize->setup_minimal(1); int ncalls = neighbor->ncalls; timer->barrier_start(TIME_LOOP); update->minimize->run(maxiter); timer->barrier_stop(TIME_LOOP); time_quench += timer->array[TIME_LOOP]; if (neighbor->ncalls == ncalls) quench_reneighbor = 0; else quench_reneighbor = 1; update->minimize->cleanup(); finish->end(1); // reset timestep as if quench did not occur // clear timestep storage from computes, since now invalid update->ntimestep = ntimestep_hold; update->endstep = update->laststep = endstep_hold; for (int i = 0; i < modify->ncompute; i++) if (modify->compute[i]->timeflag) modify->compute[i]->clearstep(); } /* ---------------------------------------------------------------------- check for an event return 0 if no event return 1 if event ------------------------------------------------------------------------- */ int TAD::check_event() { int flag; flag = 0; if (compute_event->compute_scalar() > 0.0) flag = 1; return flag; } /* ---------------------------------------------------------------------- universe proc 0 prints event info ------------------------------------------------------------------------- */ void TAD::log_event(int ievent) { timer->array[TIME_LOOP] = time_start; if (universe->me == 0) { double tfrac = 0.0; if (universe->uscreen) fprintf(universe->uscreen, BIGINT_FORMAT " %.3f %d %d %s %.3f %.3f %.3f %.3f\n", fix_event->event_timestep, timer->elapsed(TIME_LOOP), fix_event->event_number,ievent, "E ", fix_event->ebarrier,tfrac, fix_event->tlo,deltfirst); if (universe->ulogfile) fprintf(universe->ulogfile, BIGINT_FORMAT " %.3f %d %d %s %.3f %.3f %.3f %.3f\n", fix_event->event_timestep, timer->elapsed(TIME_LOOP), fix_event->event_number,ievent, "E ", fix_event->ebarrier,tfrac, fix_event->tlo,deltfirst); } // dump snapshot of quenched coords // must reneighbor and compute forces before dumping // addstep_compute_all insures eng/virial are calculated if needed if (output->ndump && universe->iworld == 0) { timer->barrier_start(TIME_LOOP); modify->addstep_compute_all(update->ntimestep); update->integrate->setup_minimal(1); output->write_dump(update->ntimestep); timer->barrier_stop(TIME_LOOP); time_output += timer->array[TIME_LOOP]; } } /* ---------------------------------------------------------------------- parse optional parameters at end of TAD input line ------------------------------------------------------------------------- */ void TAD::options(int narg, char **arg) { if (narg < 0) error->all(FLERR,"Illegal tad command"); // set defaults etol = 0.1; ftol = 0.1; maxiter = 40; maxeval = 50; etol_neb = 0.01; ftol_neb = 0.01; n1steps_neb = 100; n2steps_neb = 100; nevery_neb = 10; min_style = new char[3]; strcpy(min_style,"cg"); min_style_neb = new char[9]; strcpy(min_style_neb,"quickmin"); neb_logfilename = NULL; int iarg = 0; while (iarg < narg) { if (strcmp(arg[iarg],"min") == 0) { if (iarg+5 > narg) error->all(FLERR,"Illegal tad command"); etol = atof(arg[iarg+1]); ftol = atof(arg[iarg+2]); maxiter = atoi(arg[iarg+3]); maxeval = atoi(arg[iarg+4]); if (maxiter < 0 || maxeval < 0 || etol < 0.0 || ftol < 0.0 ) error->all(FLERR,"Illegal tad command"); iarg += 5; } else if (strcmp(arg[iarg],"neb") == 0) { if (iarg+6 > narg) error->all(FLERR,"Illegal tad command"); etol_neb = atof(arg[iarg+1]); ftol_neb = atof(arg[iarg+2]); n1steps_neb = atoi(arg[iarg+3]); n2steps_neb = atoi(arg[iarg+4]); nevery_neb = atoi(arg[iarg+5]); if (etol_neb < 0.0 || ftol_neb < 0.0 || n1steps_neb < 0 || n2steps_neb < 0 || nevery_neb < 0) error->all(FLERR,"Illegal tad command"); iarg += 6; } else if (strcmp(arg[iarg],"min_style") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal tad command"); int n = strlen(arg[iarg+1]) + 1; delete [] min_style; min_style = new char[n]; strcpy(min_style,arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"neb_style") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal tad command"); int n = strlen(arg[iarg+1]) + 1; delete [] min_style_neb; min_style_neb = new char[n]; strcpy(min_style_neb,arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"neb_log") == 0) { delete [] neb_logfilename; if (iarg+2 > narg) error->all(FLERR,"Illegal tad command"); if (strcmp(arg[iarg+1],"none") == 0) neb_logfilename = NULL; else { int n = strlen(arg[iarg+1]) + 1; neb_logfilename = new char[n]; strcpy(neb_logfilename,arg[iarg+1]); } iarg += 2; } else error->all(FLERR,"Illegal tad command"); } } /* ---------------------------------------------------------------------- perform NEB calculation ------------------------------------------------------------------------- */ void TAD::perform_neb(int ievent) { double **x = atom->x; int nlocal = atom->nlocal; double *buf_final; memory->create(buf_final,3*nlocal,"tad:buffinal"); // set system to quenched state of event ievent if (universe->iworld == 0) { fix_event_list[ievent]->restore_event(); int ii = 0; for (int i = 0; i < nlocal; i++) { buf_final[ii++] = x[i][0]; buf_final[ii++] = x[i][1]; buf_final[ii++] = x[i][2]; } } MPI_Bcast(buf_final,3*nlocal,MPI_DOUBLE,universe->root_proc[0], universe->uworld); double *buf_init; memory->create(buf_init,3*nlocal,"tad:bufinit"); // set system to quenched state of fix_event if (universe->iworld == 0) { fix_event->restore_event(); int ii = 0; for (int i = 0; i < nlocal; i++) { buf_init[ii++] = x[i][0]; buf_init[ii++] = x[i][1]; buf_init[ii++] = x[i][2]; } } MPI_Bcast(buf_init,3*nlocal,MPI_DOUBLE,universe->root_proc[0], universe->uworld); // create FixNEB object to support NEB int narg2 = 4; char **args = new char*[narg2]; args[0] = (char *) "neb"; args[1] = (char *) "all"; args[2] = (char *) "neb"; char str[128]; args[3] = str; double kspring = 1.0; sprintf(args[3],"%f",kspring); modify->add_fix(narg2,args); fix_neb = (Fix *) modify->fix[modify->nfix-1]; delete [] args; // switch minimize style to quickmin for NEB narg2 = 1; args = new char*[narg2]; args[0] = min_style_neb; update->create_minimize(narg2,args); delete [] args; // create NEB object neb = new NEB(lmp,etol_neb,ftol_neb,n1steps_neb, n2steps_neb,nevery_neb,buf_init,buf_final); // free up temporary arrays memory->destroy(buf_init); memory->destroy(buf_final); // run NEB int beginstep_hold = update->beginstep; int endstep_hold = update->endstep; int ntimestep_hold = update->ntimestep; int nsteps_hold = update->nsteps; if (universe->me == 0) { universe->ulogfile = ulogfile_neb; universe->uscreen = uscreen_neb; } // Had to bypass timer interface // because timer->array is reset // inside neb->run() // timer->barrier_start(TIME_LOOP); // neb->run(); // timer->barrier_stop(TIME_LOOP); // time_neb += timer->array[TIME_LOOP]; MPI_Barrier(world); double time_tmp = MPI_Wtime(); neb->run(); MPI_Barrier(world); time_neb += MPI_Wtime() - time_tmp; if (universe->me == 0) { universe->ulogfile = ulogfile_lammps; universe->uscreen = uscreen_lammps; } // extract barrier energy from NEB if (universe->iworld == 0) fix_event_list[ievent]->ebarrier = neb->ebf; update->beginstep = update->firststep = beginstep_hold; update->endstep = update->laststep = endstep_hold; update->ntimestep = ntimestep_hold; update->nsteps = nsteps_hold; // switch minimize style back for quench narg2 = 1; args = new char*[narg2]; args[0] = min_style; update->create_minimize(narg2,args); update->etol = etol; update->ftol = ftol; delete [] args; // clean up modify->delete_fix("neb"); delete neb; } /* ---------------------------------------------------------------------- check if confidence criterion for tstop is satisfied return 0 if not satisfied return 1 if satisfied ------------------------------------------------------------------------- */ int TAD::check_confidence() { int flag; // update stopping time deltstop = deltconf*pow(deltfirst/deltconf, ratio_beta); flag = 0; if (deltstop < update->ntimestep - fix_event->event_timestep) flag = 1; return flag; } /* ---------------------------------------------------------------------- reflect back in to starting state ------------------------------------------------------------------------- */ void TAD::revert() { double **x = atom->x; double **v = atom->v; int *image = atom->image; int nlocal = atom->nlocal; double **array_atom = fix_revert->array_atom; for (int i = 0; i < nlocal; i++) { x[i][0] = array_atom[i][0]; x[i][1] = array_atom[i][1]; x[i][2] = array_atom[i][2]; image[i] = ((int(array_atom[i][5]) + 512 & 1023) << 20) | ((int(array_atom[i][4]) + 512 & 1023) << 10) | (int(array_atom[i][3]) + 512 & 1023); v[i][0] = -array_atom[i][6]; v[i][1] = -array_atom[i][7]; v[i][2] = -array_atom[i][8]; } } /* ---------------------------------------------------------------------- Initialize list of possible events ------------------------------------------------------------------------- */ void TAD::initialize_event_list() { // First delete old events, if any delete_event_list(); // Create new list n_event_list = 0; grow_event_list(nmin_event_list); } /* ---------------------------------------------------------------------- Delete list of possible events ------------------------------------------------------------------------- */ void TAD::delete_event_list() { for (int i = 0; i < n_event_list; i++) { char str[128]; sprintf(str,"tad_event_%d",i); modify->delete_fix(str); } memory->sfree(fix_event_list); fix_event_list = NULL; n_event_list = 0; nmax_event_list = 0; } /* ---------------------------------------------------------------------- add event ------------------------------------------------------------------------- */ void TAD::add_event() { // create FixEventTAD object to store possible event int narg = 3; char **args = new char*[narg]; char str[128]; sprintf(str,"tad_event_%d",n_event_list); args[0] = str; args[1] = (char *) "all"; args[2] = (char *) "EVENT/TAD"; modify->add_fix(narg,args); if (n_event_list == nmax_event_list) grow_event_list(nmax_event_list+nmin_event_list); n_event_list += 1; int ievent = n_event_list-1; fix_event_list[ievent] = (FixEventTAD *) modify->fix[modify->nfix-1]; // store quenched state for new event fix_event_list[ievent]->store_event_tad(update->ntimestep); // store hot state for new event fix_event->restore_state(); fix_event_list[ievent]->store_state(); // string clean-up delete [] args; } /* ---------------------------------------------------------------------- compute cold time for event ievent ------------------------------------------------------------------------- */ void TAD::compute_tlo(int ievent) { double deltlo,delthi,ebarrier; ebarrier = fix_event_list[ievent]->ebarrier; delthi = fix_event_list[ievent]->event_timestep - fix_event->event_timestep; deltlo = delthi*exp(ebarrier*delta_beta); fix_event_list[ievent]->tlo = fix_event->tlo + deltlo; // update first event - char* statstr = "D "; + char* statstr = (char *) "D "; if (ievent == 0) { deltfirst = deltlo; event_first = ievent; - statstr = "DF"; + statstr = (char *) "DF"; } else if (deltlo < deltfirst) { deltfirst = deltlo; event_first = ievent; - statstr = "DF"; + statstr = (char *) "DF"; } // first-replica output about each event timer->array[TIME_LOOP] = time_start; if (universe->me == 0) { double tfrac = 0.0; if (ievent > 0) tfrac = delthi/deltstop; if (universe->uscreen) fprintf(universe->uscreen, BIGINT_FORMAT " %.3f %d %d %s %.3f %.3f %.3f %.3f\n", fix_event_list[ievent]->event_timestep, timer->elapsed(TIME_LOOP), fix_event->event_number, ievent,statstr,ebarrier,tfrac, fix_event->tlo,deltlo); if (universe->ulogfile) fprintf(universe->ulogfile, BIGINT_FORMAT " %.3f %d %d %s %.3f %.3f %.3f %.3f\n", fix_event_list[ievent]->event_timestep, timer->elapsed(TIME_LOOP), fix_event->event_number, ievent,statstr,ebarrier,tfrac, fix_event->tlo,deltlo); } } /* ---------------------------------------------------------------------- perform event ------------------------------------------------------------------------- */ void TAD::perform_event(int ievent) { // reset timestep to that of event update->ntimestep = fix_event_list[ievent]->event_timestep; // Copy event to current event // Should really use copy constructor for this fix_event->tlo = fix_event_list[ievent]->tlo; fix_event->ebarrier = fix_event_list[ievent]->ebarrier; fix_event->event_number++; fix_event->event_timestep = update->ntimestep; fix_event_list[ievent]->restore_event(); fix_event->store_event_tad(fix_event_list[ievent]->event_timestep); // output stats and dump for quenched state log_event(ievent); // load and store hot state fix_event_list[ievent]->restore_state(); fix_event->store_state(); } /* ---------------------------------------------------------------------- Allocate list of pointers to events ------------------------------------------------------------------------- */ void TAD::grow_event_list(int nmax) { if (nmax_event_list > nmax) return; fix_event_list = (FixEventTAD **) memory->srealloc(fix_event_list,nmax*sizeof(FixEventTAD *),"tad:eventlist"); nmax_event_list = nmax; } diff --git a/src/SHOCK/fix_msst.cpp b/src/SHOCK/fix_msst.cpp index 1ba47ee14..267989f30 100644 --- a/src/SHOCK/fix_msst.cpp +++ b/src/SHOCK/fix_msst.cpp @@ -1,960 +1,960 @@ /* ---------------------------------------------------------------------- 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: Laurence Fried (LLNL), Evan Reed (LLNL, Stanford) implementation of the Multi-Scale Shock Method See Reed, Fried, Joannopoulos, Phys Rev Lett, 90, 235503 (2003) ------------------------------------------------------------------------- */ #include "string.h" #include "stdlib.h" #include "math.h" #include "fix_msst.h" #include "atom.h" #include "force.h" #include "comm.h" #include "output.h" #include "modify.h" #include "compute.h" #include "kspace.h" #include "update.h" #include "respa.h" #include "domain.h" #include "error.h" #include "thermo.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ FixMSST::FixMSST(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg) { if (narg < 4) error->all(FLERR,"Illegal fix msst command"); restart_global = 1; box_change = 1; time_integrate = 1; scalar_flag = 1; vector_flag = 1; size_vector = 4; global_freq = 1; extscalar = 1; extvector = 0; // set defaults velocity = 0.0; dilation[0] = dilation[1] = dilation[2] = 1.0; p0 = 0.0; v0 = 1.0; e0 = 0.0; qmass = 1.0e1; mu = 0.0; direction = 2; p0_set = 0; v0_set = 0; e0_set = 0; tscale = 0.01; if ( strcmp(arg[3],"x") == 0 ) direction = 0; else if ( strcmp(arg[3],"y") == 0 ) direction = 1; else if ( strcmp(arg[3],"z") == 0 ) direction = 2; else { error->all(FLERR,"Illegal fix msst command"); } velocity = atof(arg[4]); if ( velocity < 0 ) error->all(FLERR,"Illegal fix msst command"); for ( int iarg = 5; iarg < narg; iarg++ ) { if ( strcmp(arg[iarg],"q") == 0 ) { qmass = atof(arg[iarg+1]); iarg++; } else if ( strcmp(arg[iarg],"mu") == 0 ) { mu = atof(arg[iarg+1]); iarg++; } else if ( strcmp(arg[iarg],"p0") == 0 ) { p0 = atof(arg[iarg+1]); iarg++; p0_set = 1; } else if ( strcmp(arg[iarg],"v0") == 0 ) { v0 = atof(arg[iarg+1]); v0_set = 1; iarg++; } else if ( strcmp(arg[iarg],"e0") == 0 ) { e0 = atof(arg[iarg+1]); e0_set = 1; iarg++; } else if ( strcmp(arg[iarg],"tscale") == 0 ) { tscale = atof(arg[iarg+1]); if (tscale < 0.0 || tscale > 1.0) error->all(FLERR,"Fix msst tscale must satisfy 0 <= tscale < 1"); iarg++; } else error->all(FLERR,"Illegal fix msst command"); } if (comm->me == 0) { if (screen) { fprintf(screen,"MSST parameters:\n"); if (direction == 0) fprintf(screen," Shock in x direction\n"); else if (direction == 1) fprintf(screen," Shock in y direction\n"); else if (direction == 2) fprintf(screen," Shock in z direction\n"); fprintf(screen," Cell mass-like parameter qmass " "(units of mass^2/length^4) = %12.5e\n", qmass); fprintf(screen," Shock velocity = %12.5e\n", velocity); fprintf(screen," Artificial viscosity " "(units of mass/length/time) = %12.5e\n", mu); if (p0_set) fprintf(screen," Initial pressure specified to be %12.5e\n", p0); else fprintf(screen," Initial pressure calculated on first step\n"); if (v0_set) fprintf(screen," Initial volume specified to be %12.5e\n", v0); else fprintf(screen," Initial volume calculated on first step\n"); if (e0_set) fprintf(screen," Initial energy specified to be %12.5e\n", e0); else fprintf(screen," Initial energy calculated on first step\n"); } if (logfile) { fprintf(logfile,"MSST parameters:\n"); if (direction == 0) fprintf(logfile," Shock in x direction\n"); else if (direction == 1) fprintf(logfile," Shock in y direction\n"); else if (direction == 2) fprintf(logfile," Shock in z direction\n"); fprintf(logfile," Cell mass-like parameter qmass " "(units of mass^2/length^4) = %12.5e\n", qmass); fprintf(logfile," Shock velocity = %12.5e\n", velocity); fprintf(logfile," Artificial viscosity " "(units of mass/length/time) = %12.5e\n", mu); if (p0_set) fprintf(logfile," Initial pressure specified to be %12.5e\n", p0); else fprintf(logfile," Initial pressure calculated on first step\n"); if (v0_set) fprintf(logfile," Initial volume specified to be %12.5e\n", v0); else fprintf(logfile," Initial volume calculated on first step\n"); if (e0_set) fprintf(logfile," Initial energy specified to be %12.5e\n", e0); else fprintf(logfile," Initial energy calculated on first step\n"); } } // check for periodicity in controlled dimensions if (domain->nonperiodic) error->all(FLERR,"Fix msst requires a periodic box"); // create a new compute temp style // id = fix-ID + temp // compute group = all since pressure is always global (group all) // and thus its KE/temperature contribution should use group all int n = strlen(id) + 6; id_temp = new char[n]; strcpy(id_temp,id); strcat(id_temp,"_temp"); char **newarg = new char*[3]; newarg[0] = id_temp; - newarg[1] = "all"; - newarg[2] = "temp"; + newarg[1] = (char *) "all"; + newarg[2] = (char *) "temp"; modify->add_compute(3,newarg); delete [] newarg; tflag = 1; // create a new compute pressure style // id = fix-ID + press, compute group = all // pass id_temp as 4th arg to pressure constructor n = strlen(id) + 7; id_press = new char[n]; strcpy(id_press,id); strcat(id_press,"_press"); newarg = new char*[4]; newarg[0] = id_press; - newarg[1] = "all"; - newarg[2] = "pressure"; + newarg[1] = (char *) "all"; + newarg[2] = (char *) "pressure"; newarg[3] = id_temp; modify->add_compute(4,newarg); delete [] newarg; pflag = 1; // create a new compute potential energy compute n = strlen(id) + 3; id_pe = new char[n]; strcpy(id_pe,id); strcat(id_pe,"_pe"); newarg = new char*[3]; newarg[0] = id_pe; newarg[1] = (char*)"all"; newarg[2] = (char*)"pe"; modify->add_compute(3,newarg); delete [] newarg; peflag = 1; // initialize the time derivative of the volume. omega[0] = omega[1] = omega[2] = 0.0; nrigid = 0; rfix = NULL; old_velocity = new double* [atom->nlocal]; for ( int j = 0; j < atom->nlocal; j++ ) { old_velocity[j] = new double [3]; } atoms_allocated = atom->nlocal; } /* ---------------------------------------------------------------------- */ FixMSST::~FixMSST() { delete [] rfix; // delete temperature and pressure if fix created them if (tflag) modify->delete_compute(id_temp); if (pflag) modify->delete_compute(id_press); if (peflag) modify->delete_compute(id_pe); delete [] id_temp; delete [] id_press; delete [] id_pe; for ( int j = 0; j < atoms_allocated; j++ ) { delete [] old_velocity[j]; } delete [] old_velocity; } /* ---------------------------------------------------------------------- */ int FixMSST::setmask() { int mask = 0; mask |= INITIAL_INTEGRATE; mask |= FINAL_INTEGRATE; mask |= THERMO_ENERGY; return mask; } /* ---------------------------------------------------------------------- */ void FixMSST::init() { if (atom->mass == NULL) error->all(FLERR,"Cannot use fix msst without per-type mass defined"); // set compute ptrs int itemp = modify->find_compute(id_temp); int ipress = modify->find_compute(id_press); int ipe = modify->find_compute(id_pe); if (itemp < 0 || ipress < 0|| ipe < 0) error->all(FLERR,"Could not find fix msst compute ID"); if (modify->compute[itemp]->tempflag == 0) error->all(FLERR,"Fix msst compute ID does not compute temperature"); if (modify->compute[ipress]->pressflag == 0) error->all(FLERR,"Fix msst compute ID does not compute pressure"); if (modify->compute[ipe]->peflag == 0) error->all(FLERR,"Fix msst compute ID does not compute potential energy"); temperature = modify->compute[itemp]; pressure = modify->compute[ipress]; pe = modify->compute[ipe]; dtv = update->dt; dtf = 0.5 * update->dt * force->ftm2v; dthalf = 0.5 * update->dt; boltz = force->boltz; nktv2p = force->nktv2p; mvv2e = force->mvv2e; double mass = 0.0; for (int i = 0; i < atom->nlocal; i++) mass += atom->mass[atom->type[i]]; MPI_Allreduce(&mass,&total_mass,1,MPI_DOUBLE,MPI_SUM,world); total_mass = total_mass; if (force->kspace) kspace_flag = 1; else kspace_flag = 0; // detect if any fix rigid exist so rigid bodies move when box is dilated // rfix[] = indices to each fix rigid delete [] rfix; nrigid = 0; rfix = NULL; for (int i = 0; i < modify->nfix; i++) if (strcmp(modify->fix[i]->style,"rigid") == 0 || strcmp(modify->fix[i]->style,"poems") == 0) nrigid++; if (nrigid) { rfix = new int[nrigid]; nrigid = 0; for (int i = 0; i < modify->nfix; i++) if (strcmp(modify->fix[i]->style,"rigid") == 0 || strcmp(modify->fix[i]->style,"poems") == 0) rfix[nrigid++] = i; } } /* ---------------------------------------------------------------------- compute T,P before integrator starts ------------------------------------------------------------------------- */ void FixMSST::setup(int vflag) { lagrangian_position = 0.0; temperature->compute_vector(); pressure->compute_vector(); couple(); velocity_sum = compute_vsum(); if ( v0_set == 0 ) { v0 = compute_vol(); v0_set = 1; if (comm->me == 0) { if ( screen ) fprintf(screen,"Fix MSST v0 = %12.5e\n", v0); if ( logfile ) fprintf(logfile,"Fix MSST v0 = %12.5e\n", v0); } } if ( p0_set == 0 ) { p0 = p_current[direction]; p0_set = 1; if ( comm->me == 0 ) { if ( screen ) fprintf(screen,"Fix MSST p0 = %12.5e\n", p0); if ( logfile ) fprintf(logfile,"Fix MSST p0 = %12.5e\n", p0); } } if ( e0_set == 0 ) { e0 = compute_etotal(); e0_set = 1; if ( comm->me == 0 ) { if ( screen ) fprintf(screen,"Fix MSST e0 = to be %12.5e\n",e0); if ( logfile ) fprintf(logfile,"Fix MSST e0 = to be %12.5e\n",e0); } } temperature->compute_vector(); double *ke_tensor = temperature->vector; double ke_temp = ke_tensor[0]+ke_tensor[1]+ke_tensor[2]; if (ke_temp > 0.0 && tscale > 0.0 ) { // transfer energy from atom velocities to cell volume motion // to bias initial compression double **v = atom->v; int *mask = atom->mask; double sqrt_initial_temperature_scaling = sqrt(1.0-tscale); double fac1 = tscale*total_mass/qmass*ke_temp/force->mvv2e; omega[direction]=-1*sqrt(fac1); double fac2 = omega[direction]/v0; if ( comm->me == 0 && tscale != 1.0) { if ( screen ) fprintf(screen,"Fix MSST initial strain rate of %12.5e established " "by reducing temperature by factor of %12.5e\n", fac2,tscale); if ( logfile ) fprintf(logfile,"Fix MSST initial strain rate of %12.5e established " "by reducing temperature by factor of %12.5e\n", fac2,tscale); } for (int i = 0; i < atom->nlocal; i++) { if (mask[i] & groupbit) { for (int k = 0; k < 3; k++ ) { v[i][k]*=sqrt_initial_temperature_scaling; } } } } // trigger virial computation on next timestep pressure->addstep(update->ntimestep+1); } /* ---------------------------------------------------------------------- 1st half of Verlet update ------------------------------------------------------------------------- */ void FixMSST::initial_integrate(int vflag) { int sd; double p_msst; // MSST driving pressure. int i, k; double vol; int nlocal = atom->nlocal; int *mask = atom->mask; double **v = atom->v; double **f = atom->f; double *mass = atom->mass; int *type = atom->type; double **x = atom->x; // check to see if old_velocity is correctly allocated check_alloc(nlocal); sd = direction; // compute new pressure and volume. temperature->compute_vector(); pressure->compute_vector(); couple(); vol = compute_vol(); // propagate the time derivative of // the volume 1/2 step at fixed vol, r, rdot. p_msst = nktv2p * mvv2e * velocity * velocity * total_mass * ( v0 - vol)/( v0 * v0); double A = total_mass * ( p_current[sd] - p0 - p_msst ) / (qmass * nktv2p * mvv2e); double B = total_mass * mu / ( qmass * vol ); // prevent blow-up of the volume. if ( vol > v0 && A > 0.0 ) { A = -A; } // use taylor expansion to avoid singularity at B == 0. if ( B * dthalf > 1.0e-06 ) { omega[sd] = ( omega[sd] + A * ( exp(B * dthalf) - 1.0 ) / B ) * exp(-B * dthalf); } else { omega[sd] = omega[sd] + (A - B * omega[sd]) * dthalf + 0.5 * (B * B * omega[sd] - A * B ) * dthalf * dthalf; } // propagate velocity sum 1/2 step by // temporarily propagating the velocities. velocity_sum = compute_vsum(); for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { for ( k = 0; k < 3; k++ ) { double C = f[i][k] * force->ftm2v / mass[type[i]]; double D = mu * omega[sd] * omega[sd] / (velocity_sum * mass[type[i]] * vol ); old_velocity[i][k] = v[i][k]; if ( k == direction ) { D = D - 2.0 * omega[sd] / vol; } if ( fabs(dthalf * D) > 1.0e-06 ) { double expd = exp(D * dthalf); v[i][k] = expd * ( C + D * v[i][k] - C / expd ) / D; } else { v[i][k] = v[i][k] + ( C + D * v[i][k] ) * dthalf + 0.5 * (D * D * v[i][k] + C * D ) * dthalf * dthalf; } } } } velocity_sum = compute_vsum(); // reset the velocities. for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { for ( k = 0; k < 3; k++ ) { v[i][k] = old_velocity[i][k]; } } } // propagate velocities 1/2 step using the new velocity sum. for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { for ( k = 0; k < 3; k++ ) { double C = f[i][k] * force->ftm2v / mass[type[i]]; double D = mu * omega[sd] * omega[sd] / (velocity_sum * mass[type[i]] * vol ); if ( k == direction ) { D = D - 2.0 * omega[sd] / vol; } if ( fabs(dthalf * D) > 1.0e-06 ) { double expd = exp(D * dthalf); v[i][k] = expd * ( C + D * v[i][k] - C / expd ) / D; } else { v[i][k] = v[i][k] + ( C + D * v[i][k] ) * dthalf + 0.5 * (D * D * v[i][k] + C * D ) * dthalf * dthalf; } } } } // propagate the volume 1/2 step. double vol1 = vol + omega[sd] * dthalf; // rescale positions and change box size. dilation[sd] = vol1/vol; remap(0); // propagate particle positions 1 time step. for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { x[i][0] += dtv * v[i][0]; x[i][1] += dtv * v[i][1]; x[i][2] += dtv * v[i][2]; } } // propagate the volume 1/2 step. double vol2 = vol1 + omega[sd] * dthalf; // rescale positions and change box size. dilation[sd] = vol2/vol1; remap(0); if (kspace_flag) force->kspace->setup(); } /* ---------------------------------------------------------------------- 2nd half of Verlet update ------------------------------------------------------------------------- */ void FixMSST::final_integrate() { int i; // v update only for atoms in MSST group double **v = atom->v; double **f = atom->f; double *mass = atom->mass; int *type = atom->type; int *mask = atom->mask; int nlocal = atom->nlocal; double vol = compute_vol(); double p_msst; int sd = direction; // propagate particle velocities 1/2 step. for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { for ( int k = 0; k < 3; k++ ) { double C = f[i][k] * force->ftm2v / mass[type[i]]; double D = mu * omega[sd] * omega[sd] / (velocity_sum * mass[type[i]] * vol ); if ( k == direction ) { D = D - 2.0 * omega[sd] / vol; } if ( fabs(dthalf * D) > 1.0e-06 ) { double expd = exp(D * dthalf); v[i][k] = expd * ( C + D * v[i][k] - C / expd ) / D; } else { v[i][k] = v[i][k] + ( C + D * v[i][k] ) * dthalf + 0.5 * (D * D * v[i][k] + C * D ) * dthalf * dthalf; } } } } // compute new pressure and volume. temperature->compute_vector(); pressure->compute_vector(); couple(); velocity_sum = compute_vsum(); vol = compute_vol(); // propagate the time derivative of the volume 1/2 step at fixed V, r, rdot. p_msst = nktv2p * mvv2e * velocity * velocity * total_mass * ( v0 - vol )/( v0 * v0 ); double A = total_mass * ( p_current[sd] - p0 - p_msst ) / ( qmass * nktv2p * mvv2e ); double B = total_mass * mu / ( qmass * vol ); // prevent blow-up of the volume. if ( vol > v0 && A > 0.0 ) { A = -A; } // use taylor expansion to avoid singularity at B == 0. if ( B * dthalf > 1.0e-06 ) { omega[sd] = ( omega[sd] + A * ( exp(B * dthalf) - 1.0 ) / B ) * exp(-B * dthalf); } else { omega[sd] = omega[sd] + (A - B * omega[sd]) * dthalf + 0.5 * (B * B * omega[sd] - A * B ) * dthalf * dthalf; } // calculate Lagrangian position of computational cell lagrangian_position -= velocity*vol/v0*update->dt; // trigger virial computation on next timestep pressure->addstep(update->ntimestep+1); } /* ---------------------------------------------------------------------- */ void FixMSST::couple() { double *tensor = pressure->vector; p_current[0] = tensor[0]; p_current[1] = tensor[1]; p_current[2] = tensor[2]; } /* ---------------------------------------------------------------------- change box size remap owned or owned+ghost atoms depending on flag if rigid bodies exist, scale rigid body centers-of-mass ------------------------------------------------------------------------- */ void FixMSST::remap(int flag) { int i,n; double oldlo,oldhi,ctr; double **v = atom->v; if (flag) n = atom->nlocal + atom->nghost; else n = atom->nlocal; // convert pertinent atoms and rigid bodies to lamda coords domain->x2lamda(n); if (nrigid) for (i = 0; i < nrigid; i++) modify->fix[rfix[i]]->deform(0); // reset global and local box to new size/shape for (i = 0; i < 3; i++) { if ( direction == i ) { oldlo = domain->boxlo[i]; oldhi = domain->boxhi[i]; ctr = 0.5 * (oldlo + oldhi); domain->boxlo[i] = (oldlo-ctr)*dilation[i] + ctr; domain->boxhi[i] = (oldhi-ctr)*dilation[i] + ctr; } } domain->set_global_box(); domain->set_local_box(); // convert pertinent atoms and rigid bodies back to box coords domain->lamda2x(n); if (nrigid) for (i = 0; i < nrigid; i++) modify->fix[rfix[i]]->deform(1); for (i = 0; i < n; i++) { v[i][direction] = v[i][direction] * dilation[direction]; } } /* ---------------------------------------------------------------------- pack entire state of Fix into one write ------------------------------------------------------------------------- */ void FixMSST::write_restart(FILE *fp) { int n = 0; double list[4]; list[n++] = omega[direction]; list[n++] = e0; list[n++] = v0; list[n++] = p0; if (comm->me == 0) { int size = n * sizeof(double); fwrite(&size,sizeof(int),1,fp); fwrite(&list,sizeof(double),n,fp); } } /* ---------------------------------------------------------------------- use state info from restart file to restart the Fix ------------------------------------------------------------------------- */ void FixMSST::restart(char *buf) { int n = 0; double *list = (double *) buf; omega[direction] = list[n++]; e0 = list[n++]; v0 = list[n++]; p0 = list[n++]; p0_set = 1; v0_set = 1; e0_set = 1; } /* ---------------------------------------------------------------------- */ int FixMSST::modify_param(int narg, char **arg) { if (strcmp(arg[0],"temp") == 0) { if (narg < 2) error->all(FLERR,"Illegal fix_modify command"); if (tflag) { modify->delete_compute(id_temp); tflag = 0; } delete [] id_temp; int n = strlen(arg[1]) + 1; id_temp = new char[n]; strcpy(id_temp,arg[1]); int icompute = modify->find_compute(id_temp); if (icompute < 0) error->all(FLERR,"Could not find fix_modify temperature ID"); temperature = modify->compute[icompute]; if (temperature->tempflag == 0) error->all(FLERR,"Fix_modify temperature ID does not compute temperature"); if (temperature->igroup != 0 && comm->me == 0) error->warning(FLERR,"Temperature for MSST is not for group all"); return 2; } else if (strcmp(arg[0],"press") == 0) { if (narg < 2) error->all(FLERR,"Illegal fix_modify command"); if (pflag) { modify->delete_compute(id_press); pflag = 0; } delete [] id_press; int n = strlen(arg[1]) + 1; id_press = new char[n]; strcpy(id_press,arg[1]); int icompute = modify->find_compute(id_press); if (icompute < 0) error->all(FLERR,"Could not find fix_modify pressure ID"); pressure = modify->compute[icompute]; if (pressure->pressflag == 0) error->all(FLERR,"Fix_modify pressure ID does not compute pressure"); return 2; } return 0; } /* ---------------------------------------------------------------------- */ double FixMSST::compute_scalar() { // compute new pressure and volume. temperature->compute_vector(); pressure->compute_vector(); couple(); double volume = compute_vol(); double energy = 0.0; int i; i = direction; energy = qmass * omega[i] * omega[i] / (2.0 * total_mass) * mvv2e; energy -= 0.5 * total_mass * velocity * velocity * (1.0 - volume/ v0) * (1.0 - volume/ v0) * mvv2e; energy -= p0 * ( v0 - volume ) / nktv2p; return energy; } /* ---------------------------------------------------------------------- return a single element from the following vector, [dhug,dray,lgr_vel,lgr_pos] ------------------------------------------------------------------------- */ double FixMSST::compute_vector(int n) { if (n == 0) { return compute_hugoniot(); } else if (n == 1) { return compute_rayleigh(); } else if (n == 2) { return compute_lagrangian_speed(); } else if (n == 3) { return compute_lagrangian_position(); } return 0.0; } /* ---------------------------------------------------------------------- Computes the deviation of the current point from the Hugoniot in Kelvin for the MSST. ------------------------------------------------------------------------- */ double FixMSST::compute_hugoniot() { double v, e, p; double dhugo; e = compute_etotal(); temperature->compute_vector(); pressure->compute_vector(); p = pressure->vector[direction]; v = compute_vol(); dhugo = (0.5 * (p + p0 ) * ( v0 - v)) / force->nktv2p + e0 - e; dhugo /= temperature->dof * force->boltz; return dhugo; } /* ---------------------------------------------------------------------- Computes the deviation of the current point from the Rayleigh in pressure units for the MSST. ------------------------------------------------------------------------- */ double FixMSST::compute_rayleigh() { double v, p; double drayleigh; temperature->compute_vector(); pressure->compute_vector(); p = pressure->vector[direction]; v = compute_vol(); drayleigh = p - p0 - total_mass * velocity * velocity * force->mvv2e * (1.0 - v / v0 ) * force->nktv2p / v0; return drayleigh; } /* ---------------------------------------------------------------------- Computes the speed of the MSST computational cell in the unshocked material rest-frame ------------------------------------------------------------------------- */ double FixMSST::compute_lagrangian_speed() { double v = compute_vol(); return velocity*(1.0-v/v0); } /* ---------------------------------------------------------------------- Computes the distance behind the shock front of the MSST computational cell. ------------------------------------------------------------------------- */ double FixMSST::compute_lagrangian_position() { return lagrangian_position; } /* ---------------------------------------------------------------------- */ double FixMSST::compute_etotal() { double epot,ekin,etot; epot = pe->compute_scalar(); if (thermo_energy) epot -= compute_scalar(); ekin = temperature->compute_scalar(); ekin *= 0.5 * temperature->dof * force->boltz; etot = epot+ekin; return etot; } /* ---------------------------------------------------------------------- */ double FixMSST::compute_vol() { if (domain->dimension == 3) return domain->xprd * domain->yprd * domain->zprd; else return domain->xprd * domain->yprd; } /* ---------------------------------------------------------------------- Checks to see if the allocated size of old_velocity is >= n The number of local atoms can change during a parallel run. ------------------------------------------------------------------------- */ void FixMSST::check_alloc(int n) { if ( atoms_allocated < n ) { for ( int j = 0; j < atoms_allocated; j++ ) { delete [] old_velocity[j]; } delete [] old_velocity; old_velocity = new double* [n]; for ( int j = 0; j < n; j++ ) old_velocity[j] = new double [3]; atoms_allocated = n; } } double FixMSST::compute_vsum() { double vsum; double **v = atom->v; int *mask = atom->mask; int nlocal = atom->nlocal; double t = 0.0; for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { t += (v[i][0]*v[i][0] + v[i][1]*v[i][1] + v[i][2]*v[i][2]) ; } } MPI_Allreduce(&t,&vsum,1,MPI_DOUBLE,MPI_SUM,world); return vsum; } diff --git a/src/compute.cpp b/src/compute.cpp index 5b8dc93f2..b33fe7595 100644 --- a/src/compute.cpp +++ b/src/compute.cpp @@ -1,289 +1,291 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ #include "lmptype.h" #include "mpi.h" #include "stdlib.h" #include "string.h" #include "ctype.h" #include "compute.h" #include "atom.h" #include "domain.h" #include "comm.h" #include "group.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define DELTA 4 #define BIG 2000000000 /* ---------------------------------------------------------------------- */ Compute::Compute(LAMMPS *lmp, int narg, char **arg) : Pointers(lmp) { if (narg < 3) error->all(FLERR,"Illegal compute command"); // compute ID, group, and style // ID must be all alphanumeric chars or underscores int n = strlen(arg[0]) + 1; id = new char[n]; strcpy(id,arg[0]); for (int i = 0; i < n-1; i++) if (!isalnum(id[i]) && id[i] != '_') - error->all(FLERR,"Compute ID must be alphanumeric or underscore characters"); + error->all(FLERR, + "Compute ID must be alphanumeric or underscore characters"); igroup = group->find(arg[1]); if (igroup == -1) error->all(FLERR,"Could not find compute group ID"); groupbit = group->bitmask[igroup]; n = strlen(arg[2]) + 1; style = new char[n]; strcpy(style,arg[2]); // set child class defaults scalar_flag = vector_flag = array_flag = 0; peratom_flag = local_flag = 0; tempflag = pressflag = peflag = 0; pressatomflag = peatomflag = 0; tempbias = 0; timeflag = 0; comm_forward = comm_reverse = 0; cudable = 0; invoked_scalar = invoked_vector = invoked_array = -1; invoked_peratom = invoked_local = -1; // set modify defaults extra_dof = domain->dimension; dynamic = 0; // setup list of timesteps ntime = maxtime = 0; tlist = NULL; // setup map for molecule IDs molmap = NULL; } /* ---------------------------------------------------------------------- */ Compute::~Compute() { delete [] id; delete [] style; memory->destroy(tlist); memory->destroy(molmap); } /* ---------------------------------------------------------------------- */ void Compute::modify_params(int narg, char **arg) { if (narg == 0) error->all(FLERR,"Illegal compute_modify command"); int iarg = 0; while (iarg < narg) { if (strcmp(arg[iarg],"extra") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal compute_modify command"); extra_dof = atoi(arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"dynamic") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal compute_modify command"); if (strcmp(arg[iarg+1],"no") == 0) dynamic = 0; else if (strcmp(arg[iarg+1],"yes") == 0) dynamic = 1; else error->all(FLERR,"Illegal compute_modify command"); iarg += 2; } else if (strcmp(arg[iarg],"thermo") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal compute_modify command"); if (strcmp(arg[iarg+1],"no") == 0) thermoflag = 0; else if (strcmp(arg[iarg+1],"yes") == 0) thermoflag = 1; else error->all(FLERR,"Illegal compute_modify command"); iarg += 2; } else error->all(FLERR,"Illegal compute_modify command"); } } /* ---------------------------------------------------------------------- reset extra_dof to its default value ------------------------------------------------------------------------- */ void Compute::reset_extra_dof() { extra_dof = domain->dimension; } /* ---------------------------------------------------------------------- */ -void Compute::reset_extra_compute_fix(char *) +void Compute::reset_extra_compute_fix(const char *) { - error->all(FLERR,"Compute does not allow an extra compute or fix to be reset"); + error->all(FLERR, + "Compute does not allow an extra compute or fix to be reset"); } /* ---------------------------------------------------------------------- add ntimestep to list of timesteps the compute will be called on do not add if already in list search from top downward, since list of times is in decreasing order ------------------------------------------------------------------------- */ void Compute::addstep(bigint ntimestep) { // i = location in list to insert ntimestep int i; for (i = ntime-1; i >= 0; i--) { if (ntimestep == tlist[i]) return; if (ntimestep < tlist[i]) break; } i++; // extend list as needed if (ntime == maxtime) { maxtime += DELTA; memory->grow(tlist,maxtime,"compute:tlist"); } // move remainder of list upward and insert ntimestep for (int j = ntime-1; j >= i; j--) tlist[j+1] = tlist[j]; tlist[i] = ntimestep; ntime++; } /* ---------------------------------------------------------------------- return 1/0 if ntimestep is or is not in list of calling timesteps if value(s) on top of list are less than ntimestep, delete them search from top downward, since list of times is in decreasing order ------------------------------------------------------------------------- */ int Compute::matchstep(bigint ntimestep) { for (int i = ntime-1; i >= 0; i--) { if (ntimestep < tlist[i]) return 0; if (ntimestep == tlist[i]) return 1; if (ntimestep > tlist[i]) ntime--; } return 0; } /* ---------------------------------------------------------------------- clean out list of timesteps to call the compute on ------------------------------------------------------------------------- */ void Compute::clearstep() { ntime = 0; } /* ---------------------------------------------------------------------- identify molecule IDs with atoms in group warn if any atom in group has molecule ID = 0 warn if any molecule has only some atoms in group return Ncount = # of molecules with atoms in group set molmap to NULL if molecule IDs include all in range from 1 to Ncount else: molecule IDs range from idlo to idhi set molmap to vector of length idhi-idlo+1 molmap[id-idlo] = index from 0 to Ncount-1 return idlo and idhi ------------------------------------------------------------------------- */ int Compute::molecules_in_group(int &idlo, int &idhi) { int i; memory->destroy(molmap); molmap = NULL; // find lo/hi molecule ID for any atom in group // warn if atom in group has ID = 0 int *molecule = atom->molecule; int *mask = atom->mask; int nlocal = atom->nlocal; int lo = BIG; int hi = -BIG; int flag = 0; for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) { if (molecule[i] == 0) flag = 1; lo = MIN(lo,molecule[i]); hi = MAX(hi,molecule[i]); } int flagall; MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,world); if (flagall && comm->me == 0) error->warning(FLERR,"Atom with molecule ID = 0 included in " "compute molecule group"); MPI_Allreduce(&lo,&idlo,1,MPI_INT,MPI_MIN,world); MPI_Allreduce(&hi,&idhi,1,MPI_INT,MPI_MAX,world); if (idlo == BIG) return 0; // molmap = vector of length nlen // set to 1 for IDs that appear in group across all procs, else 0 int nlen = idhi-idlo+1; memory->create(molmap,nlen,"compute:molmap"); for (i = 0; i < nlen; i++) molmap[i] = 0; for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) molmap[molecule[i]-idlo] = 1; int *molmapall; memory->create(molmapall,nlen,"compute:molmapall"); MPI_Allreduce(molmap,molmapall,nlen,MPI_INT,MPI_MAX,world); // nmolecules = # of non-zero IDs in molmap // molmap[i] = index of molecule, skipping molecules not in group with -1 int nmolecules = 0; for (i = 0; i < nlen; i++) if (molmapall[i]) molmap[i] = nmolecules++; else molmap[i] = -1; memory->destroy(molmapall); // warn if any molecule has some atoms in group and some not in group flag = 0; for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) continue; if (molecule[i] < idlo || molecule[i] > idhi) continue; if (molmap[molecule[i]-idlo] >= 0) flag = 1; } MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,world); if (flagall && comm->me == 0) error->warning(FLERR,"One or more compute molecules has atoms not in group"); // if molmap simply stores 1 to Nmolecules, then free it if (idlo == 1 && idhi == nmolecules && nlen == nmolecules) { memory->destroy(molmap); molmap = NULL; } return nmolecules; } diff --git a/src/compute.h b/src/compute.h index 899f8243e..e8f185ee2 100644 --- a/src/compute.h +++ b/src/compute.h @@ -1,169 +1,169 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ #ifndef LMP_COMPUTE_H #define LMP_COMPUTE_H #include "pointers.h" namespace LAMMPS_NS { class Compute : protected Pointers { public: char *id,*style; int igroup,groupbit; double scalar; // computed global scalar double *vector; // computed global vector double **array; // computed global array double *vector_atom; // computed per-atom vector double **array_atom; // computed per-atom array double *vector_local; // computed local vector double **array_local; // computed local array int scalar_flag; // 0/1 if compute_scalar() function exists int vector_flag; // 0/1 if compute_vector() function exists int array_flag; // 0/1 if compute_array() function exists int size_vector; // length of global vector int size_array_rows; // rows in global array int size_array_cols; // columns in global array int peratom_flag; // 0/1 if compute_peratom() function exists int size_peratom_cols; // 0 = vector, N = columns in peratom array int local_flag; // 0/1 if compute_local() function exists int size_local_rows; // rows in local vector or array int size_local_cols; // 0 = vector, N = columns in local array int extscalar; // 0/1 if global scalar is intensive/extensive int extvector; // 0/1/-1 if global vector is all int/ext/extlist int *extlist; // list of 0/1 int/ext for each vec component int extarray; // 0/1 if global array is all intensive/extensive int tempflag; // 1 if Compute can be used as temperature // must have both compute_scalar, compute_vector int pressflag; // 1 if Compute can be used as pressure (uses virial) // must have both compute_scalar, compute_vector int pressatomflag; // 1 if Compute calculates per-atom virial int peflag; // 1 if Compute calculates PE (uses Force energies) int peatomflag; // 1 if Compute calculates per-atom PE int tempbias; // 0/1 if Compute temp includes self/extra bias int timeflag; // 1 if Compute stores list of timesteps it's called on int ntime; // # of entries in time list int maxtime; // max # of entries time list can hold bigint *tlist; // list of timesteps the Compute is called on int invoked_flag; // non-zero if invoked or accessed this step, 0 if not bigint invoked_scalar; // last timestep on which compute_scalar() was invoked bigint invoked_vector; // ditto for compute_vector() bigint invoked_array; // ditto for compute_array() bigint invoked_peratom; // ditto for compute_peratom() bigint invoked_local; // ditto for compute_local() double dof; // degrees-of-freedom for temperature int comm_forward; // size of forward communication (0 if none) int comm_reverse; // size of reverse communication (0 if none) int cudable; // 1 if compute is CUDA-enabled Compute(class LAMMPS *, int, char **); virtual ~Compute(); void modify_params(int, char **); void reset_extra_dof(); virtual void init() = 0; virtual void init_list(int, class NeighList *) {} virtual double compute_scalar() {return 0.0;} virtual void compute_vector() {} virtual void compute_array() {} virtual void compute_peratom() {} virtual void compute_local() {} virtual int pack_comm(int, int *, double *, int, int *) {return 0;} virtual void unpack_comm(int, int, double *) {} virtual int pack_reverse_comm(int, int, double *) {return 0;} virtual void unpack_reverse_comm(int, int *, double *) {} virtual int dof_remove(int) {return 0;} virtual void remove_bias(int, double *) {} virtual void remove_bias_all() {} virtual void restore_bias(int, double *) {} virtual void restore_bias_all() {} - virtual void reset_extra_compute_fix(char *); + virtual void reset_extra_compute_fix(const char *); void addstep(bigint); int matchstep(bigint); void clearstep(); virtual double memory_usage() {return 0.0;} protected: int extra_dof; // extra DOF for temperature computes int dynamic; // recount atoms for temperature computes int thermoflag; // 1 if include fix PE for PE computes double vbias[3]; // stored velocity bias for one atom double **vbiasall; // stored velocity bias for all atoms int maxbias; // size of vbiasall array int *molmap; // convert molecule ID to local index int molecules_in_group(int &, int &); inline int sbmask(int j) { return j >> SBBITS & 3; } }; } #endif /* ERROR/WARNING messages: E: Illegal ... command Self-explanatory. Check the input script syntax and compare to the documentation for the command. You can use -echo screen as a command-line option when running LAMMPS to see the offending line. E: Compute ID must be alphanumeric or underscore characters Self-explanatory. E: Could not find compute group ID Self-explanatory. E: Compute does not allow an extra compute or fix to be reset This is an internal LAMMPS error. Please report it to the developers. W: Atom with molecule ID = 0 included in compute molecule group The group used in a compute command that operates on moleclues includes atoms with no molecule ID. This is probably not what you want. W: One or more compute molecules has atoms not in group The group used in a compute command that operates on moleclues does not include all the atoms in some molecules. This is probably not what you want. */ diff --git a/src/compute_pressure.cpp b/src/compute_pressure.cpp index edd6910cc..5f981db3c 100644 --- a/src/compute_pressure.cpp +++ b/src/compute_pressure.cpp @@ -1,286 +1,286 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ #include "mpi.h" #include "string.h" #include "stdlib.h" #include "compute_pressure.h" #include "atom.h" #include "update.h" #include "domain.h" #include "modify.h" #include "fix.h" #include "force.h" #include "pair.h" #include "bond.h" #include "angle.h" #include "dihedral.h" #include "improper.h" #include "kspace.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ ComputePressure::ComputePressure(LAMMPS *lmp, int narg, char **arg) : Compute(lmp, narg, arg) { if (narg < 4) error->all(FLERR,"Illegal compute pressure command"); if (igroup) error->all(FLERR,"Compute pressure must use group all"); scalar_flag = vector_flag = 1; size_vector = 6; extscalar = 0; extvector = 0; pressflag = 1; timeflag = 1; // store temperature ID used by pressure computation // insure it is valid for temperature computation int n = strlen(arg[3]) + 1; id_temp = new char[n]; strcpy(id_temp,arg[3]); int icompute = modify->find_compute(id_temp); if (icompute < 0) error->all(FLERR,"Could not find compute pressure temperature ID"); if (modify->compute[icompute]->tempflag == 0) error->all(FLERR,"Compute pressure temperature ID does not compute temperature"); // process optional args if (narg == 4) { keflag = 1; pairflag = 1; bondflag = angleflag = dihedralflag = improperflag = 1; kspaceflag = fixflag = 1; } else { keflag = 0; pairflag = 0; bondflag = angleflag = dihedralflag = improperflag = 0; kspaceflag = fixflag = 0; int iarg = 4; while (iarg < narg) { if (strcmp(arg[iarg],"ke") == 0) keflag = 1; else if (strcmp(arg[iarg],"pair") == 0) pairflag = 1; else if (strcmp(arg[iarg],"bond") == 0) bondflag = 1; else if (strcmp(arg[iarg],"angle") == 0) angleflag = 1; else if (strcmp(arg[iarg],"dihedral") == 0) dihedralflag = 1; else if (strcmp(arg[iarg],"improper") == 0) improperflag = 1; else if (strcmp(arg[iarg],"kspace") == 0) kspaceflag = 1; else if (strcmp(arg[iarg],"fix") == 0) fixflag = 1; else if (strcmp(arg[iarg],"virial") == 0) { pairflag = 1; bondflag = angleflag = dihedralflag = improperflag = 1; kspaceflag = fixflag = 1; } else error->all(FLERR,"Illegal compute pressure command"); iarg++; } } vector = new double[6]; nvirial = 0; vptr = NULL; } /* ---------------------------------------------------------------------- */ ComputePressure::~ComputePressure() { delete [] id_temp; delete [] vector; delete [] vptr; } /* ---------------------------------------------------------------------- */ void ComputePressure::init() { boltz = force->boltz; nktv2p = force->nktv2p; dimension = domain->dimension; // set temperature compute, must be done in init() // fixes could have changed or compute_modify could have changed it int icompute = modify->find_compute(id_temp); if (icompute < 0) error->all(FLERR,"Could not find compute pressure temperature ID"); temperature = modify->compute[icompute]; // detect contributions to virial // vptr points to all virial[6] contributions delete [] vptr; nvirial = 0; vptr = NULL; if (pairflag && force->pair) nvirial++; if (bondflag && atom->molecular && force->bond) nvirial++; if (angleflag && atom->molecular && force->angle) nvirial++; if (dihedralflag && atom->molecular && force->dihedral) nvirial++; if (improperflag && atom->molecular && force->improper) nvirial++; if (fixflag) for (int i = 0; i < modify->nfix; i++) if (modify->fix[i]->virial_flag) nvirial++; if (nvirial) { vptr = new double*[nvirial]; nvirial = 0; if (pairflag && force->pair) vptr[nvirial++] = force->pair->virial; if (bondflag && force->bond) vptr[nvirial++] = force->bond->virial; if (angleflag && force->angle) vptr[nvirial++] = force->angle->virial; if (dihedralflag && force->dihedral) vptr[nvirial++] = force->dihedral->virial; if (improperflag && force->improper) vptr[nvirial++] = force->improper->virial; if (fixflag) for (int i = 0; i < modify->nfix; i++) if (modify->fix[i]->virial_flag) vptr[nvirial++] = modify->fix[i]->virial; } // flag Kspace contribution separately, since not summed across procs if (kspaceflag && force->kspace) kspace_virial = force->kspace->virial; else kspace_virial = NULL; } /* ---------------------------------------------------------------------- compute total pressure, averaged over Pxx, Pyy, Pzz ------------------------------------------------------------------------- */ double ComputePressure::compute_scalar() { invoked_scalar = update->ntimestep; if (update->vflag_global != invoked_scalar) error->all(FLERR,"Virial was not tallied on needed timestep"); // invoke temperature it it hasn't been already double t; if (keflag) { if (temperature->invoked_scalar != update->ntimestep) t = temperature->compute_scalar(); else t = temperature->scalar; } if (dimension == 3) { inv_volume = 1.0 / (domain->xprd * domain->yprd * domain->zprd); virial_compute(3,3); if (keflag) scalar = (temperature->dof * boltz * t + virial[0] + virial[1] + virial[2]) / 3.0 * inv_volume * nktv2p; else scalar = (virial[0] + virial[1] + virial[2]) / 3.0 * inv_volume * nktv2p; } else { inv_volume = 1.0 / (domain->xprd * domain->yprd); virial_compute(2,2); if (keflag) scalar = (temperature->dof * boltz * t + virial[0] + virial[1]) / 2.0 * inv_volume * nktv2p; else scalar = (virial[0] + virial[1]) / 2.0 * inv_volume * nktv2p; } return scalar; } /* ---------------------------------------------------------------------- compute pressure tensor assume KE tensor has already been computed ------------------------------------------------------------------------- */ void ComputePressure::compute_vector() { invoked_vector = update->ntimestep; if (update->vflag_global != invoked_vector) error->all(FLERR,"Virial was not tallied on needed timestep"); // invoke temperature if it hasn't been already double *ke_tensor; if (keflag) { if (temperature->invoked_vector != update->ntimestep) temperature->compute_vector(); ke_tensor = temperature->vector; } if (dimension == 3) { inv_volume = 1.0 / (domain->xprd * domain->yprd * domain->zprd); virial_compute(6,3); if (keflag) { for (int i = 0; i < 6; i++) vector[i] = (ke_tensor[i] + virial[i]) * inv_volume * nktv2p; } else for (int i = 0; i < 6; i++) vector[i] = virial[i] * inv_volume * nktv2p; } else { inv_volume = 1.0 / (domain->xprd * domain->yprd); virial_compute(4,2); if (keflag) { vector[0] = (ke_tensor[0] + virial[0]) * inv_volume * nktv2p; vector[1] = (ke_tensor[1] + virial[1]) * inv_volume * nktv2p; vector[3] = (ke_tensor[3] + virial[3]) * inv_volume * nktv2p; vector[2] = vector[4] = vector[5] = 0.0; } else { vector[0] = virial[0] * inv_volume * nktv2p; vector[1] = virial[1] * inv_volume * nktv2p; vector[3] = virial[3] * inv_volume * nktv2p; vector[2] = vector[4] = vector[5] = 0.0; } } } /* ---------------------------------------------------------------------- */ void ComputePressure::virial_compute(int n, int ndiag) { int i,j; double v[6],*vcomponent; for (i = 0; i < n; i++) v[i] = 0.0; // sum contributions to virial from forces and fixes for (j = 0; j < nvirial; j++) { vcomponent = vptr[j]; for (i = 0; i < n; i++) v[i] += vcomponent[i]; } // sum virial across procs MPI_Allreduce(v,virial,n,MPI_DOUBLE,MPI_SUM,world); // KSpace virial contribution is already summed across procs if (kspace_virial) for (i = 0; i < n; i++) virial[i] += kspace_virial[i]; // LJ long-range tail correction if (force->pair && force->pair->tail_flag) for (i = 0; i < ndiag; i++) virial[i] += force->pair->ptail * inv_volume; } /* ---------------------------------------------------------------------- */ -void ComputePressure::reset_extra_compute_fix(char *id_new) +void ComputePressure::reset_extra_compute_fix(const char *id_new) { delete [] id_temp; int n = strlen(id_new) + 1; id_temp = new char[n]; strcpy(id_temp,id_new); } diff --git a/src/compute_pressure.h b/src/compute_pressure.h index 44524228e..ab5948114 100644 --- a/src/compute_pressure.h +++ b/src/compute_pressure.h @@ -1,83 +1,83 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ #ifdef COMPUTE_CLASS ComputeStyle(pressure,ComputePressure) #else #ifndef LMP_COMPUTE_PRESSURE_H #define LMP_COMPUTE_PRESSURE_H #include "compute.h" namespace LAMMPS_NS { class ComputePressure : public Compute { public: ComputePressure(class LAMMPS *, int, char **); virtual ~ComputePressure(); void init(); double compute_scalar(); void compute_vector(); - void reset_extra_compute_fix(char *); + void reset_extra_compute_fix(const char *); protected: double boltz,nktv2p,inv_volume; int nvirial,dimension; double **vptr; double *kspace_virial; Compute *temperature; char *id_temp; double virial[6]; int keflag,pairflag,bondflag,angleflag,dihedralflag,improperflag; int fixflag,kspaceflag; void virial_compute(int, int); }; } #endif #endif /* ERROR/WARNING messages: E: Illegal ... command Self-explanatory. Check the input script syntax and compare to the documentation for the command. You can use -echo screen as a command-line option when running LAMMPS to see the offending line. E: Compute pressure must use group all Virial contributions computed by potentials (pair, bond, etc) are computed on all atoms. E: Could not find compute pressure temperature ID The compute ID for calculating temperature does not exist. E: Compute pressure temperature ID does not compute temperature The compute ID assigned to a pressure computation must compute temperature. E: Virial was not tallied on needed timestep You are using a thermo keyword that requires potentials to have tallied the virial, but they didn't on this timestep. See the variable doc page for ideas on how to make this work. */ diff --git a/src/dump_atom.cpp b/src/dump_atom.cpp index 2365fb3e2..a9dfdcc03 100644 --- a/src/dump_atom.cpp +++ b/src/dump_atom.cpp @@ -1,454 +1,454 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ #include "string.h" #include "dump_atom.h" #include "domain.h" #include "atom.h" #include "update.h" #include "group.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ DumpAtom::DumpAtom(LAMMPS *lmp, int narg, char **arg) : Dump(lmp, narg, arg) { if (narg != 5) error->all(FLERR,"Illegal dump atom command"); scale_flag = 1; image_flag = 0; format_default = NULL; } /* ---------------------------------------------------------------------- */ void DumpAtom::init_style() { if (image_flag == 0) size_one = 5; else size_one = 8; // default format depends on image flags delete [] format; if (format_user) { int n = strlen(format_user) + 2; format = new char[n]; strcpy(format,format_user); strcat(format,"\n"); } else { char *str; if (image_flag == 0) str = (char *) "%d %d %g %g %g"; else str = (char *) "%d %d %g %g %g %d %d %d"; int n = strlen(str) + 2; format = new char[n]; strcpy(format,str); strcat(format,"\n"); } // setup boundary string int m = 0; for (int idim = 0; idim < 3; idim++) { for (int iside = 0; iside < 2; iside++) { if (domain->boundary[idim][iside] == 0) boundstr[m++] = 'p'; else if (domain->boundary[idim][iside] == 1) boundstr[m++] = 'f'; else if (domain->boundary[idim][iside] == 2) boundstr[m++] = 's'; else if (domain->boundary[idim][iside] == 3) boundstr[m++] = 'm'; } boundstr[m++] = ' '; } boundstr[8] = '\0'; // setup column string if (scale_flag == 0 && image_flag == 0) - columns = "id type x y z"; + columns = (char *) "id type x y z"; else if (scale_flag == 0 && image_flag == 1) - columns = "id type x y z ix iy iz"; + columns = (char *) "id type x y z ix iy iz"; else if (scale_flag == 1 && image_flag == 0) - columns = "id type xs ys zs"; + columns = (char *) "id type xs ys zs"; else if (scale_flag == 1 && image_flag == 1) - columns = "id type xs ys zs ix iy iz"; + columns = (char *) "id type xs ys zs ix iy iz"; // setup function ptrs if (binary && domain->triclinic == 0) header_choice = &DumpAtom::header_binary; else if (binary && domain->triclinic == 1) header_choice = &DumpAtom::header_binary_triclinic; else if (!binary && domain->triclinic == 0) header_choice = &DumpAtom::header_item; else if (!binary && domain->triclinic == 1) header_choice = &DumpAtom::header_item_triclinic; if (scale_flag == 1 && image_flag == 0 && domain->triclinic == 0) pack_choice = &DumpAtom::pack_scale_noimage; else if (scale_flag == 1 && image_flag == 1 && domain->triclinic == 0) pack_choice = &DumpAtom::pack_scale_image; else if (scale_flag == 1 && image_flag == 0 && domain->triclinic == 1) pack_choice = &DumpAtom::pack_scale_noimage_triclinic; else if (scale_flag == 1 && image_flag == 1 && domain->triclinic == 1) pack_choice = &DumpAtom::pack_scale_image_triclinic; else if (scale_flag == 0 && image_flag == 0) pack_choice = &DumpAtom::pack_noscale_noimage; else if (scale_flag == 0 && image_flag == 1) pack_choice = &DumpAtom::pack_noscale_image; if (binary) write_choice = &DumpAtom::write_binary; else if (image_flag == 0) write_choice = &DumpAtom::write_noimage; else if (image_flag == 1) write_choice = &DumpAtom::write_image; // open single file, one time only if (multifile == 0) openfile(); } /* ---------------------------------------------------------------------- */ int DumpAtom::modify_param(int narg, char **arg) { if (strcmp(arg[0],"scale") == 0) { if (narg < 2) error->all(FLERR,"Illegal dump_modify command"); if (strcmp(arg[1],"yes") == 0) scale_flag = 1; else if (strcmp(arg[1],"no") == 0) scale_flag = 0; else error->all(FLERR,"Illegal dump_modify command"); return 2; } else if (strcmp(arg[0],"image") == 0) { if (narg < 2) error->all(FLERR,"Illegal dump_modify command"); if (strcmp(arg[1],"yes") == 0) image_flag = 1; else if (strcmp(arg[1],"no") == 0) image_flag = 0; else error->all(FLERR,"Illegal dump_modify command"); return 2; } return 0; } /* ---------------------------------------------------------------------- */ void DumpAtom::write_header(bigint ndump) { if (multiproc) (this->*header_choice)(ndump); else if (me == 0) (this->*header_choice)(ndump); } /* ---------------------------------------------------------------------- */ int DumpAtom::count() { if (igroup == 0) return atom->nlocal; int *mask = atom->mask; int nlocal = atom->nlocal; int m = 0; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) m++; return m; } /* ---------------------------------------------------------------------- */ void DumpAtom::pack(int *ids) { (this->*pack_choice)(ids); } /* ---------------------------------------------------------------------- */ void DumpAtom::write_data(int n, double *mybuf) { (this->*write_choice)(n,mybuf); } /* ---------------------------------------------------------------------- */ void DumpAtom::header_binary(bigint ndump) { fwrite(&update->ntimestep,sizeof(bigint),1,fp); fwrite(&ndump,sizeof(bigint),1,fp); fwrite(&domain->triclinic,sizeof(int),1,fp); fwrite(&domain->boundary[0][0],6*sizeof(int),1,fp); fwrite(&boxxlo,sizeof(double),1,fp); fwrite(&boxxhi,sizeof(double),1,fp); fwrite(&boxylo,sizeof(double),1,fp); fwrite(&boxyhi,sizeof(double),1,fp); fwrite(&boxzlo,sizeof(double),1,fp); fwrite(&boxzhi,sizeof(double),1,fp); fwrite(&size_one,sizeof(int),1,fp); if (multiproc) { int one = 1; fwrite(&one,sizeof(int),1,fp); } else fwrite(&nprocs,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- */ void DumpAtom::header_binary_triclinic(bigint ndump) { fwrite(&update->ntimestep,sizeof(bigint),1,fp); fwrite(&ndump,sizeof(bigint),1,fp); fwrite(&domain->triclinic,sizeof(int),1,fp); fwrite(&domain->boundary[0][0],6*sizeof(int),1,fp); fwrite(&boxxlo,sizeof(double),1,fp); fwrite(&boxxhi,sizeof(double),1,fp); fwrite(&boxylo,sizeof(double),1,fp); fwrite(&boxyhi,sizeof(double),1,fp); fwrite(&boxzlo,sizeof(double),1,fp); fwrite(&boxzhi,sizeof(double),1,fp); fwrite(&boxxy,sizeof(double),1,fp); fwrite(&boxxz,sizeof(double),1,fp); fwrite(&boxyz,sizeof(double),1,fp); fwrite(&size_one,sizeof(int),1,fp); if (multiproc) { int one = 1; fwrite(&one,sizeof(int),1,fp); } else fwrite(&nprocs,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- */ void DumpAtom::header_item(bigint ndump) { fprintf(fp,"ITEM: TIMESTEP\n"); fprintf(fp,BIGINT_FORMAT "\n",update->ntimestep); fprintf(fp,"ITEM: NUMBER OF ATOMS\n"); fprintf(fp,BIGINT_FORMAT "\n",ndump); fprintf(fp,"ITEM: BOX BOUNDS %s\n",boundstr); fprintf(fp,"%g %g\n",boxxlo,boxxhi); fprintf(fp,"%g %g\n",boxylo,boxyhi); fprintf(fp,"%g %g\n",boxzlo,boxzhi); fprintf(fp,"ITEM: ATOMS %s\n",columns); } /* ---------------------------------------------------------------------- */ void DumpAtom::header_item_triclinic(bigint ndump) { fprintf(fp,"ITEM: TIMESTEP\n"); fprintf(fp,BIGINT_FORMAT "\n",update->ntimestep); fprintf(fp,"ITEM: NUMBER OF ATOMS\n"); fprintf(fp,BIGINT_FORMAT "\n",ndump); fprintf(fp,"ITEM: BOX BOUNDS xy xz yz %s\n",boundstr); fprintf(fp,"%g %g %g\n",boxxlo,boxxhi,boxxy); fprintf(fp,"%g %g %g\n",boxylo,boxyhi,boxxz); fprintf(fp,"%g %g %g\n",boxzlo,boxzhi,boxyz); fprintf(fp,"ITEM: ATOMS %s\n",columns); } /* ---------------------------------------------------------------------- */ void DumpAtom::pack_scale_image(int *ids) { int m,n; int *tag = atom->tag; int *type = atom->type; int *image = atom->image; int *mask = atom->mask; double **x = atom->x; int nlocal = atom->nlocal; double invxprd = 1.0/domain->xprd; double invyprd = 1.0/domain->yprd; double invzprd = 1.0/domain->zprd; m = n = 00; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { buf[m++] = tag[i]; buf[m++] = type[i]; buf[m++] = (x[i][0] - boxxlo) * invxprd; buf[m++] = (x[i][1] - boxylo) * invyprd; buf[m++] = (x[i][2] - boxzlo) * invzprd; buf[m++] = (image[i] & 1023) - 512; buf[m++] = (image[i] >> 10 & 1023) - 512; buf[m++] = (image[i] >> 20) - 512; if (ids) ids[n++] = tag[i]; } } /* ---------------------------------------------------------------------- */ void DumpAtom::pack_scale_noimage(int *ids) { int m,n; int *tag = atom->tag; int *type = atom->type; int *mask = atom->mask; double **x = atom->x; int nlocal = atom->nlocal; double invxprd = 1.0/domain->xprd; double invyprd = 1.0/domain->yprd; double invzprd = 1.0/domain->zprd; m = n = 0; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { buf[m++] = tag[i]; buf[m++] = type[i]; buf[m++] = (x[i][0] - boxxlo) * invxprd; buf[m++] = (x[i][1] - boxylo) * invyprd; buf[m++] = (x[i][2] - boxzlo) * invzprd; if (ids) ids[n++] = tag[i]; } } /* ---------------------------------------------------------------------- */ void DumpAtom::pack_scale_image_triclinic(int *ids) { int m,n; int *tag = atom->tag; int *type = atom->type; int *image = atom->image; int *mask = atom->mask; double **x = atom->x; int nlocal = atom->nlocal; double lamda[3]; m = n = 0; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { buf[m++] = tag[i]; buf[m++] = type[i]; domain->x2lamda(x[i],lamda); buf[m++] = lamda[0]; buf[m++] = lamda[1]; buf[m++] = lamda[2]; buf[m++] = (image[i] & 1023) - 512; buf[m++] = (image[i] >> 10 & 1023) - 512; buf[m++] = (image[i] >> 20) - 512; if (ids) ids[n++] = tag[i]; } } /* ---------------------------------------------------------------------- */ void DumpAtom::pack_scale_noimage_triclinic(int *ids) { int m,n; int *tag = atom->tag; int *type = atom->type; int *mask = atom->mask; double **x = atom->x; int nlocal = atom->nlocal; double lamda[3]; m = n = 0; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { buf[m++] = tag[i]; buf[m++] = type[i]; domain->x2lamda(x[i],lamda); buf[m++] = lamda[0]; buf[m++] = lamda[1]; buf[m++] = lamda[2]; if (ids) ids[n++] = tag[i]; } } /* ---------------------------------------------------------------------- */ void DumpAtom::pack_noscale_image(int *ids) { int m,n; int *tag = atom->tag; int *type = atom->type; int *image = atom->image; int *mask = atom->mask; double **x = atom->x; int nlocal = atom->nlocal; m = n = 0; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { buf[m++] = tag[i]; buf[m++] = type[i]; buf[m++] = x[i][0]; buf[m++] = x[i][1]; buf[m++] = x[i][2]; buf[m++] = (image[i] & 1023) - 512; buf[m++] = (image[i] >> 10 & 1023) - 512; buf[m++] = (image[i] >> 20) - 512; if (ids) ids[n++] = tag[i]; } } /* ---------------------------------------------------------------------- */ void DumpAtom::pack_noscale_noimage(int *ids) { int m,n; int *tag = atom->tag; int *type = atom->type; int *mask = atom->mask; double **x = atom->x; int nlocal = atom->nlocal; m = n = 0; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { buf[m++] = tag[i]; buf[m++] = type[i]; buf[m++] = x[i][0]; buf[m++] = x[i][1]; buf[m++] = x[i][2]; if (ids) ids[n++] = tag[i]; } } /* ---------------------------------------------------------------------- */ void DumpAtom::write_binary(int n, double *mybuf) { n *= size_one; fwrite(&n,sizeof(int),1,fp); fwrite(mybuf,sizeof(double),n,fp); } /* ---------------------------------------------------------------------- */ void DumpAtom::write_image(int n, double *mybuf) { int m = 0; for (int i = 0; i < n; i++) { fprintf(fp,format, static_cast (mybuf[m]), static_cast (mybuf[m+1]), mybuf[m+2],mybuf[m+3],mybuf[m+4], static_cast (mybuf[m+5]), static_cast (mybuf[m+6]), static_cast (mybuf[m+7])); m += size_one; } } /* ---------------------------------------------------------------------- */ void DumpAtom::write_noimage(int n, double *mybuf) { int m = 0; for (int i = 0; i < n; i++) { fprintf(fp,format, static_cast (mybuf[m]), static_cast (mybuf[m+1]), mybuf[m+2],mybuf[m+3],mybuf[m+4]); m += size_one; } } diff --git a/src/dump_image.cpp b/src/dump_image.cpp index 16f677327..eeef5adf1 100644 --- a/src/dump_image.cpp +++ b/src/dump_image.cpp @@ -1,2311 +1,2310 @@ /* ---------------------------------------------------------------------- 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 author: Nathan Fabian (Sandia) ------------------------------------------------------------------------- */ #include "mpi.h" #include "math.h" #include "ctype.h" #include "stdlib.h" #include "string.h" #include "dump_image.h" #include "math_extra.h" #include "atom.h" #include "domain.h" #include "group.h" #include "force.h" #include "comm.h" #include "input.h" #include "variable.h" #include "random_mars.h" #include "math_const.h" #include "error.h" #include "memory.h" #ifdef LAMMPS_JPEG #include "jpeglib.h" #endif using namespace LAMMPS_NS; using namespace MathConst; #define NCOLORS 140 #define NELEMENTS 109 #define BIG 1.0e20 enum{PPM,JPG}; enum{NUMERIC,ATOM,TYPE,ELEMENT,ATTRIBUTE,MINVALUE,MAXVALUE}; enum{STATIC,DYNAMIC}; enum{CONTINUOUS,DISCRETE,SEQUENTIAL}; enum{ABSOLUTE,FRACTIONAL}; enum{NO,YES}; /* ---------------------------------------------------------------------- */ DumpImage::DumpImage(LAMMPS *lmp, int narg, char **arg) : DumpCustom(lmp, narg, arg) { if (binary || multiproc) error->all(FLERR,"Invalid dump image filename"); // set filetype based on filename suffix int n = strlen(filename); if (strlen(filename) > 4 && strcmp(&filename[n-4],".jpg") == 0) filetype = JPG; else if (strlen(filename) > 5 && strcmp(&filename[n-5],".jpeg") == 0) filetype = JPG; else filetype = PPM; #ifndef LAMMPS_JPEG if (filetype == JPG) error->all(FLERR,"Cannot dump JPG file"); #endif // atom color,diameter settings if (nfield != 2) error->all(FLERR,"Illegal dump image command"); acolor = ATTRIBUTE; if (strcmp(arg[5],"type") == 0) acolor = TYPE; else if (strcmp(arg[5],"element") == 0) acolor = ELEMENT; adiam = ATTRIBUTE; if (strcmp(arg[6],"type") == 0) adiam = TYPE; else if (strcmp(arg[6],"element") == 0) adiam = ELEMENT; // set defaults for optional args atomflag = YES; if (atom->nbondtypes == 0) bondflag = NO; else { bondflag = YES; bcolor = ATOM; bdiam = NUMERIC; bdiamvalue = 0.5; } width = height = 512; theta = 60.0 * MY_PI/180.0; phi = 30.0 * MY_PI/180.0; thetastr = phistr = NULL; cflag = STATIC; cx = cy = cz = 0.5; cxstr = cystr = czstr = NULL; if (domain->dimension == 3) { up[0] = 0.0; up[1] = 0.0; up[2] = 1.0; } else { up[0] = 0.0; up[1] = 1.0; up[2] = 0.0; } upxstr = upystr = upzstr = NULL; zoom = 1.0; zoomstr = NULL; persp = 0.0; perspstr = NULL; boxflag = YES; boxdiam = 0.02; axesflag = NO; shiny = 1.0; ssao = NO; // parse optional args int iarg = ioptional; while (iarg < narg) { if (strcmp(arg[iarg],"adiam") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal dump image command"); adiam = NUMERIC; adiamvalue = atof(arg[iarg+1]); if (adiamvalue <= 0.0) error->all(FLERR,"Illegal dump image command"); iarg += 2; } else if (strcmp(arg[iarg],"atom") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal dump image command"); if (strcmp(arg[iarg+1],"yes") == 0) atomflag = YES; else if (strcmp(arg[iarg+1],"no") == 0) atomflag = NO; else error->all(FLERR,"Illegal dump image command"); iarg += 2; } else if (strcmp(arg[iarg],"bond") == 0) { if (iarg+3 > narg) error->all(FLERR,"Illegal dump image command"); if (atom->nbondtypes == 0) error->all(FLERR,"Dump image bond not allowed with no bond types"); bondflag = YES; if (strcmp(arg[iarg+1],"none") == 0) bondflag = NO; else if (strcmp(arg[iarg+1],"atom") == 0) bcolor = ATOM; else if (strcmp(arg[iarg+1],"type") == 0) bcolor = TYPE; else error->all(FLERR,"Illegal dump image command"); if (!islower(arg[iarg+2][0])) { bdiam = NUMERIC; bdiamvalue = atof(arg[iarg+2]); if (bdiamvalue <= 0.0) error->all(FLERR,"Illegal dump image command"); } else if (strcmp(arg[iarg+2],"atom") == 0) bdiam = ATOM; else if (strcmp(arg[iarg+2],"type") == 0) bdiam = TYPE; else if (strcmp(arg[iarg+2],"none") == 0) bondflag = NO; else error->all(FLERR,"Illegal dump image command"); iarg += 3; } else if (strcmp(arg[iarg],"size") == 0) { if (iarg+3 > narg) error->all(FLERR,"Illegal dump image command"); width = atoi(arg[iarg+1]); height = atoi(arg[iarg+2]); if (width <= 0 || height <= 0) error->all(FLERR,"Illegal dump image command"); iarg += 3; } else if (strcmp(arg[iarg],"view") == 0) { if (iarg+3 > narg) error->all(FLERR,"Illegal dump image command"); if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) { int n = strlen(&arg[iarg+1][2]) + 1; thetastr = new char[n]; strcpy(thetastr,&arg[iarg+1][2]); } else { theta = atof(arg[iarg+1]); if (theta < 0.0 || theta > 180.0) error->all(FLERR,"Invalid dump image theta value"); theta *= MY_PI/180.0; } if (strstr(arg[iarg+2],"v_") == arg[iarg+2]) { int n = strlen(&arg[iarg+2][2]) + 1; phistr = new char[n]; strcpy(phistr,&arg[iarg+2][2]); } else { phi = atof(arg[iarg+2]); phi *= MY_PI/180.0; } iarg += 3; } else if (strcmp(arg[iarg],"center") == 0) { if (iarg+5 > narg) error->all(FLERR,"Illegal dump image command"); if (strcmp(arg[iarg+1],"s") == 0) cflag = STATIC; else if (strcmp(arg[iarg+1],"d") == 0) cflag = DYNAMIC; else error->all(FLERR,"Illegal dump image command"); if (strstr(arg[iarg+2],"v_") == arg[iarg+2]) { int n = strlen(&arg[iarg+2][2]) + 1; cxstr = new char[n]; strcpy(cxstr,&arg[iarg+2][2]); cflag = DYNAMIC; } else cx = atof(arg[iarg+2]); if (strstr(arg[iarg+3],"v_") == arg[iarg+3]) { int n = strlen(&arg[iarg+3][2]) + 1; cystr = new char[n]; strcpy(cystr,&arg[iarg+3][2]); cflag = DYNAMIC; } else cy = atof(arg[iarg+3]); if (strstr(arg[iarg+4],"v_") == arg[iarg+4]) { int n = strlen(&arg[iarg+4][2]) + 1; czstr = new char[n]; strcpy(czstr,&arg[iarg+4][2]); cflag = DYNAMIC; } else cz = atof(arg[iarg+4]); iarg += 5; } else if (strcmp(arg[iarg],"up") == 0) { if (iarg+4 > narg) error->all(FLERR,"Illegal dump image command"); if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) { int n = strlen(&arg[iarg+1][2]) + 1; upxstr = new char[n]; strcpy(upxstr,&arg[iarg+1][2]); } else up[0] = atof(arg[iarg+1]); if (strstr(arg[iarg+2],"v_") == arg[iarg+2]) { int n = strlen(&arg[iarg+2][2]) + 1; upystr = new char[n]; strcpy(upystr,&arg[iarg+2][2]); } else up[1] = atof(arg[iarg+1]); if (strstr(arg[iarg+3],"v_") == arg[iarg+3]) { int n = strlen(&arg[iarg+3][2]) + 1; upzstr = new char[n]; strcpy(upzstr,&arg[iarg+3][2]); } else up[2] = atof(arg[iarg+3]); iarg += 4; } else if (strcmp(arg[iarg],"zoom") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal dump image command"); if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) { int n = strlen(&arg[iarg+1][2]) + 1; zoomstr = new char[n]; strcpy(zoomstr,&arg[iarg+1][2]); } else { zoom = atof(arg[iarg+1]); if (zoom <= 0.0) error->all(FLERR,"Illegal dump image command"); } iarg += 2; } else if (strcmp(arg[iarg],"persp") == 0) { error->all(FLERR,"Dump image persp option is not yet supported"); if (iarg+2 > narg) error->all(FLERR,"Illegal dump image command"); if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) { int n = strlen(&arg[iarg+1][2]) + 1; perspstr = new char[n]; strcpy(perspstr,&arg[iarg+1][2]); } else { persp = atof(arg[iarg+1]); if (persp < 0.0) error->all(FLERR,"Illegal dump image command"); } iarg += 2; } else if (strcmp(arg[iarg],"box") == 0) { if (iarg+3 > narg) error->all(FLERR,"Illegal dump image command"); if (strcmp(arg[iarg+1],"yes") == 0) boxflag = YES; else if (strcmp(arg[iarg+1],"no") == 0) boxflag = NO; else error->all(FLERR,"Illegal dump image command"); boxdiam = atof(arg[iarg+2]); if (boxdiam < 0.0) error->all(FLERR,"Illegal dump image command"); iarg += 3; } else if (strcmp(arg[iarg],"axes") == 0) { if (iarg+3 > narg) error->all(FLERR,"Illegal dump image command"); if (strcmp(arg[iarg+1],"yes") == 0) axesflag = YES; else if (strcmp(arg[iarg+1],"no") == 0) axesflag = NO; else error->all(FLERR,"Illegal dump image command"); axeslen = atof(arg[iarg+2]); axesdiam = atof(arg[iarg+3]); if (axeslen < 0.0 || axesdiam < 0.0) error->all(FLERR,"Illegal dump image command"); iarg += 4; } else if (strcmp(arg[iarg],"shiny") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal dump image command"); shiny = atof(arg[iarg+1]); if (shiny < 0.0 || shiny > 1.0) error->all(FLERR,"Illegal dump image command"); iarg += 2; } else if (strcmp(arg[iarg],"ssao") == 0) { if (iarg+4 > narg) error->all(FLERR,"Illegal dump image command"); if (strcmp(arg[iarg+1],"yes") == 0) ssao = YES; else if (strcmp(arg[iarg+1],"no") == 0) ssao = NO; else error->all(FLERR,"Illegal dump image command"); seed = atoi(arg[iarg+2]); if (seed <= 0) error->all(FLERR,"Illegal dump image command"); ssaoint = atof(arg[iarg+3]); if (ssaoint < 0.0 || ssaoint > 1.0) error->all(FLERR,"Illegal dump image command"); iarg += 4; } else error->all(FLERR,"Illegal dump image command"); } // params based on args npixels = width * height; if (bondflag) { if (bcolor == ATOM || bdiam == ATOM) comm_forward = 3; else comm_forward = 1; } // additional defaults for dump_modify options ncolors = 0; username = NULL; userrgb = NULL; diamtype = new double[ntypes+1]; diamelement = new double[ntypes+1]; colortype = new double*[ntypes+1]; colorelement = new double*[ntypes+1]; for (int i = 1; i <= ntypes; i++) { diamtype[i] = 1.0; if (i % 6 == 1) colortype[i] = color2rgb("red"); else if (i % 6 == 2) colortype[i] = color2rgb("green"); else if (i % 6 == 3) colortype[i] = color2rgb("blue"); else if (i % 6 == 4) colortype[i] = color2rgb("yellow"); else if (i % 6 == 5) colortype[i] = color2rgb("aqua"); else if (i % 6 == 0) colortype[i] = color2rgb("cyan"); } if (bondflag) { bdiamtype = new double[atom->nbondtypes+1]; bcolortype = new double*[atom->nbondtypes+1]; for (int i = 1; i <= atom->nbondtypes; i++) { bdiamtype[i] = 0.5; if (i % 6 == 1) bcolortype[i] = color2rgb("red"); else if (i % 6 == 2) bcolortype[i] = color2rgb("green"); else if (i % 6 == 3) bcolortype[i] = color2rgb("blue"); else if (i % 6 == 4) bcolortype[i] = color2rgb("yellow"); else if (i % 6 == 5) bcolortype[i] = color2rgb("aqua"); else if (i % 6 == 0) bcolortype[i] = color2rgb("cyan"); } } else { bdiamtype = NULL; bcolortype = NULL; } boxcolor = color2rgb("yellow"); background[0] = background[1] = background[2] = 0; mlo = MINVALUE; mhi = MAXVALUE; mstyle = CONTINUOUS; mrange = FRACTIONAL; nentry = 2; mentry = new MapEntry[nentry]; mentry[0].svalue = 0.0; mentry[0].color = color2rgb("blue"); mentry[1].svalue = 1.0; mentry[1].color = color2rgb("red"); // static parameters FOV = MY_PI/6.0; // 30 degrees ambientColor[0] = 0.0; ambientColor[1] = 0.0; ambientColor[2] = 0.0; keyLightPhi = -MY_PI4; // -45 degrees keyLightTheta = MY_PI/6.0; // 30 degrees keyLightColor[0] = 0.9; keyLightColor[1] = 0.9; keyLightColor[2] = 0.9; fillLightPhi = MY_PI/6.0; // 30 degrees fillLightTheta = 0; fillLightColor[0] = 0.45; fillLightColor[1] = 0.45; fillLightColor[2] = 0.45; backLightPhi = MY_PI; // 180 degrees backLightTheta = MY_PI/12.0; // 15 degrees backLightColor[0] = 0.9; backLightColor[1] = 0.9; backLightColor[2] = 0.9; // viewflag = DYNAMIC if any view parameter is dynamic viewflag = STATIC; if (thetastr || phistr || cflag == DYNAMIC || upxstr || upystr || upzstr || zoomstr || perspstr) viewflag = DYNAMIC; if (cflag == STATIC) box_center(); if (viewflag == STATIC) view_params(); // image and depth buffers depthBuffer = (double *) memory->smalloc(npixels*sizeof(double), "dump:depthBuffer"); surfaceBuffer = (double *) memory->smalloc(2*npixels*sizeof(double), "dump:surfaceBuffer"); imageBuffer = (char *) memory->smalloc(3*npixels*sizeof(char), "dump:imageBuffer"); depthcopy = (double *) memory->smalloc(npixels*sizeof(double), "dump:depthcopy"); surfacecopy = (double *) memory->smalloc(npixels*2*sizeof(double), "dump:surfacecopy"); rgbcopy = (char *) memory->smalloc(3*npixels*sizeof(char), "dump:rgbcopy"); maxbufcopy = 0; bufcopy = NULL; // RNG for SSAO depth shading if (ssao) random = new RanMars(lmp,seed+me); else random = NULL; } /* ---------------------------------------------------------------------- */ DumpImage::~DumpImage() { delete [] diamtype; delete [] diamelement; delete [] colortype; delete [] colorelement; delete [] bdiamtype; delete [] bcolortype; for (int i = 0; i < ncolors; i++) delete [] username[i]; memory->sfree(username); memory->destroy(userrgb); delete [] mentry; memory->sfree(depthBuffer); memory->sfree(surfaceBuffer); memory->sfree(imageBuffer); memory->sfree(depthcopy); memory->sfree(surfacecopy); memory->sfree(rgbcopy); memory->destroy(bufcopy); delete random; } /* ---------------------------------------------------------------------- */ void DumpImage::init_style() { if (multifile == 0) error->all(FLERR,"Dump image requires one snapshot per file"); if (sort_flag) error->all(FLERR,"Dump image cannot perform sorting"); DumpCustom::init_style(); // check variables if (thetastr) { thetavar = input->variable->find(thetastr); if (thetavar < 0) error->all(FLERR,"Variable name for dump image theta does not exist"); if (!input->variable->equalstyle(thetavar)) error->all(FLERR,"Variable for dump image theta is invalid style"); } if (phistr) { phivar = input->variable->find(phistr); if (phivar < 0) error->all(FLERR,"Variable name for dump image phi does not exist"); if (!input->variable->equalstyle(phivar)) error->all(FLERR,"Variable for dump image phi is invalid style"); } if (cxstr) { cxvar = input->variable->find(cxstr); if (cxvar < 0) error->all(FLERR,"Variable name for dump image center does not exist"); if (!input->variable->equalstyle(cxvar)) error->all(FLERR,"Variable for dump image center is invalid style"); } if (cystr) { cyvar = input->variable->find(cystr); if (cyvar < 0) error->all(FLERR,"Variable name for dump image center does not exist"); if (!input->variable->equalstyle(cyvar)) error->all(FLERR,"Variable for dump image center is invalid style"); } if (czstr) { czvar = input->variable->find(czstr); if (czvar < 0) error->all(FLERR,"Variable name for dump image center does not exist"); if (!input->variable->equalstyle(czvar)) error->all(FLERR,"Variable for dump image center is invalid style"); } if (upxstr) { upxvar = input->variable->find(upxstr); if (upxvar < 0) error->all(FLERR,"Variable name for dump image center does not exist"); if (!input->variable->equalstyle(upxvar)) error->all(FLERR,"Variable for dump image center is invalid style"); } if (upystr) { upyvar = input->variable->find(upystr); if (upyvar < 0) error->all(FLERR,"Variable name for dump image center does not exist"); if (!input->variable->equalstyle(upyvar)) error->all(FLERR,"Variable for dump image center is invalid style"); } if (upzstr) { upzvar = input->variable->find(upzstr); if (upzvar < 0) error->all(FLERR,"Variable name for dump image center does not exist"); if (!input->variable->equalstyle(upzvar)) error->all(FLERR,"Variable for dump image center is invalid style"); } if (zoomstr) { zoomvar = input->variable->find(zoomstr); if (zoomvar < 0) error->all(FLERR,"Variable name for dump image zoom does not exist"); if (!input->variable->equalstyle(zoomvar)) error->all(FLERR,"Variable for dump image zoom is invalid style"); } if (perspstr) { perspvar = input->variable->find(perspstr); if (perspvar < 0) error->all(FLERR,"Variable name for dump image persp does not exist"); if (!input->variable->equalstyle(perspvar)) error->all(FLERR,"Variable for dump image persp is invalid style"); } // set up type -> element mapping if (atomflag && acolor == ELEMENT) { for (int i = 1; i <= ntypes; i++) { colorelement[i] = element2color(typenames[i]); if (colorelement[i] == NULL) error->all(FLERR,"Invalid dump image element name"); } } if (atomflag && adiam == ELEMENT) { for (int i = 1; i <= ntypes; i++) { diamelement[i] = element2diam(typenames[i]); if (diamelement[i] == 0.0) error->all(FLERR,"Invalid dump image element name"); } } } /* ---------------------------------------------------------------------- */ void DumpImage::write() { MPI_Request requests[3]; MPI_Status statuses[3]; // open new file openfile(); // reset box center and view parameters if dynamic if (cflag == DYNAMIC) box_center(); if (viewflag == DYNAMIC) view_params(); // nme = # of atoms this proc will contribute to dump // pack buf with x,y,z,color,diameter // set minmax color range if using color map // create my portion of image for my particles nme = count(); if (nme > maxbuf) { maxbuf = nme; memory->destroy(buf); memory->create(buf,maxbuf*size_one,"dump:buf"); } pack(NULL); if (acolor == ATTRIBUTE) color_minmax(); create_image(); // merge images across procs using depth buffer // hi procs send to lo procs, cascading down logarithmically int nhalf = 1; while (nhalf < nprocs) nhalf *= 2; nhalf /= 2; while (nhalf) { if (me < nhalf && me+nhalf < nprocs) { MPI_Irecv(rgbcopy,npixels*3,MPI_BYTE,me+nhalf,0,world,&requests[0]); MPI_Irecv(depthcopy,npixels,MPI_DOUBLE,me+nhalf,0,world,&requests[1]); if (ssao) MPI_Irecv(surfacecopy,npixels*2,MPI_DOUBLE, me+nhalf,0,world,&requests[2]); if (ssao) MPI_Waitall(3,requests,statuses); else MPI_Waitall(2,requests,statuses); for (int i = 0; i < npixels; i++) { if (depthBuffer[i] < 0 || (depthcopy[i] >= 0 && depthcopy[i] < depthBuffer[i])) { depthBuffer[i] = depthcopy[i]; imageBuffer[i*3+0] = rgbcopy[i*3+0]; imageBuffer[i*3+1] = rgbcopy[i*3+1]; imageBuffer[i*3+2] = rgbcopy[i*3+2]; if (ssao) { surfaceBuffer[i*2+0] = surfacecopy[i*2+0]; surfaceBuffer[i*2+1] = surfacecopy[i*2+1]; } } } } else if (me >= nhalf && me < 2*nhalf) { MPI_Send(imageBuffer,npixels*3,MPI_BYTE,me-nhalf,0,world); MPI_Send(depthBuffer,npixels,MPI_DOUBLE,me-nhalf,0,world); if (ssao) MPI_Send(surfaceBuffer,npixels*2,MPI_DOUBLE,me-nhalf,0,world); } nhalf /= 2; } // extra SSAO enhancement // bcast full image to all procs // each works on subset of pixels // gather result back to proc 0 if (ssao) { MPI_Bcast(imageBuffer,npixels*3,MPI_BYTE,0,world); MPI_Bcast(surfaceBuffer,npixels*2,MPI_DOUBLE,0,world); MPI_Bcast(depthBuffer,npixels,MPI_DOUBLE,0,world); compute_SSAO(); int pixelPart = height/nprocs * width*3; MPI_Gather(imageBuffer+me*pixelPart,pixelPart,MPI_BYTE, rgbcopy,pixelPart,MPI_BYTE,0,world); writeBuffer = rgbcopy; } else { writeBuffer = imageBuffer; } // write image file if (me == 0) { if (filetype == JPG) write_JPG(); else write_PPM(); fclose(fp); } } /* ---------------------------------------------------------------------- reset view parameters called once from constructor if view is STATIC called every snapshot from write() if view is DYNAMIC ------------------------------------------------------------------------- */ void DumpImage::box_center() { box_bounds(); if (cxstr) phi = input->variable->compute_equal(cxvar); if (cystr) phi = input->variable->compute_equal(cyvar); if (czstr) phi = input->variable->compute_equal(czvar); xctr = boxxlo + cx*(boxxhi-boxxlo); yctr = boxylo + cy*(boxyhi-boxylo); zctr = boxzlo + cz*(boxzhi-boxzlo); } /* ---------------------------------------------------------------------- reset view parameters called once from constructor if view is STATIC called every snapshot from write() if view is DYNAMIC ------------------------------------------------------------------------- */ void DumpImage::view_params() { // camDir = camera direction if (thetastr) { theta = input->variable->compute_equal(thetavar); if (theta < 0.0 || theta > 180.0) error->all(FLERR,"Invalid dump image theta value"); theta *= MY_PI/180.0; } if (phistr) { phi = input->variable->compute_equal(phivar); phi *= MY_PI/180.0; } camDir[0] = sin(theta)*cos(phi); camDir[1] = sin(theta)*sin(phi); camDir[2] = cos(theta); // up vector if (upxstr) up[0] = input->variable->compute_equal(upxvar); if (upystr) up[1] = input->variable->compute_equal(upyvar); if (upzstr) up[2] = input->variable->compute_equal(upzvar); // zdist = camera distance = function of zoom & bounding box // camPos = camera position = function of camDir and zdist box_bounds(); if (zoomstr) zoom = input->variable->compute_equal(zoomvar); if (zoom <= 0.0) error->all(FLERR,"Invalid dump image zoom value"); if (perspstr) persp = input->variable->compute_equal(perspvar); if (persp < 0.0) error->all(FLERR,"Invalid dump image persp value"); double delx = 2.0*(boxxhi-boxxlo); double dely = 2.0*(boxyhi-boxylo); double delz = 2.0*(boxzhi-boxzlo); double maxdel = MAX(delx,dely); maxdel = MAX(maxdel,delz); zdist = maxdel; zdist /= tan(FOV); zdist += 0.5 * (delx*camDir[0] + dely*camDir[1] + delz*camDir[2]); zdist /= zoom; camPos[0] = camDir[0] * zdist; camPos[1] = camDir[1] * zdist; camPos[2] = camDir[2] * zdist; // camUp = camDir x (Up x camDir) // camDir points at the camera, view direction = -camDir if (camDir[0] == up[0] && camDir[1] == up[1] && camDir[2] == up[2]) { double tmp = up[0]; up[0] = up[1]; up[1] = up[2]; up[2] = tmp; } MathExtra::cross3(up,camDir,camRight); MathExtra::norm3(camRight); MathExtra::cross3(camDir,camRight,camUp); if (camUp[0] == 0.0 && camUp[1] == 0.0 && camUp[2] == 0.0) error->all(FLERR,"Invalid dump image up vector"); MathExtra::norm3(camUp); // light directions in terms of -camDir = z keyLightDir[0] = cos(keyLightTheta) * sin(keyLightPhi); keyLightDir[1] = sin(keyLightTheta); keyLightDir[2] = cos(keyLightTheta) * cos(keyLightPhi); fillLightDir[0] = cos(fillLightTheta) * sin(fillLightPhi); fillLightDir[1] = sin(fillLightTheta); fillLightDir[2] = cos(fillLightTheta) * cos(fillLightPhi); backLightDir[0] = cos(backLightTheta) * sin(backLightPhi); backLightDir[1] = sin(backLightTheta); backLightDir[2] = cos(backLightTheta) * cos(backLightPhi); keyHalfDir[0] = 0 + keyLightDir[0]; keyHalfDir[1] = 0 + keyLightDir[1]; keyHalfDir[2] = 1 + keyLightDir[2]; MathExtra::norm3(keyHalfDir); // adjust shinyness of the reflection specularHardness = 16.0 * shiny; specularIntensity = shiny; // adjust strength of the SSAO if (ssao) { SSAORadius = maxdel * 0.05 * ssaoint; SSAOSamples = static_cast (8.0 + 32.0*ssaoint); SSAOJitter = MY_PI / 12; ambientColor[0] = 0.5; ambientColor[1] = 0.5; ambientColor[2] = 0.5; } // param for rasterizing spheres tanPerPixel = -(maxdel / (double) height); } /* ---------------------------------------------------------------------- simulation box bounds ------------------------------------------------------------------------- */ void DumpImage::box_bounds() { if (domain->triclinic == 0) { boxxlo = domain->boxlo[0]; boxxhi = domain->boxhi[0]; boxylo = domain->boxlo[1]; boxyhi = domain->boxhi[1]; boxzlo = domain->boxlo[2]; boxzhi = domain->boxhi[2]; } else { boxxlo = domain->boxlo_bound[0]; boxxhi = domain->boxhi_bound[0]; boxylo = domain->boxlo_bound[1]; boxyhi = domain->boxhi_bound[1]; boxzlo = domain->boxlo_bound[2]; boxzhi = domain->boxhi_bound[2]; boxxy = domain->xy; boxxz = domain->xz; boxyz = domain->yz; } } /* ---------------------------------------------------------------------- set explicit values for all min/max settings in color map lo/hi current and lvalue/hvalue settings for lo/hi = MIN/MAX VALUE in entries if mlo/mhi = MIN/MAX VALUE, compute bounds on just the atoms being visualized ------------------------------------------------------------------------- */ void DumpImage::color_minmax() { double two[2],twoall[2]; if (mlo == MINVALUE || mhi == MAXVALUE) { double lo = BIG; double hi = -BIG; int m = 0; for (int i = 0; i < nchoose; i++) { lo = MIN(lo,buf[m]); hi = MAX(hi,buf[m+1]); m += size_one; } two[0] = -lo; two[1] = hi; MPI_Allreduce(two,twoall,2,MPI_DOUBLE,MPI_MAX,world); } if (mlo == MINVALUE) locurrent = -twoall[0]; else locurrent = mlovalue; if (mhi == MAXVALUE) hicurrent = twoall[1]; else hicurrent = mhivalue; if (locurrent > hicurrent) error->all(FLERR,"Invalid dump image color range"); if (mstyle == CONTINUOUS) { if (mrange == ABSOLUTE) mentry[0].svalue = locurrent; else mentry[0].svalue = 0.0; if (mrange == ABSOLUTE) mentry[nentry-1].svalue = hicurrent; else mentry[nentry-1].svalue = 1.0; } else if (mstyle == DISCRETE) { for (int i = 0; i < nentry; i++) { if (mentry[i].lo == MINVALUE) { if (mrange == ABSOLUTE) mentry[i].lvalue = locurrent; else mentry[i].lvalue = 0.0; } if (mentry[i].hi == MAXVALUE) { if (mrange == ABSOLUTE) mentry[i].hvalue = hicurrent; else mentry[i].hvalue = 1.0; } } } } /* ---------------------------------------------------------------------- create image for atoms on this proc every pixel has depth ------------------------------------------------------------------------- */ void DumpImage::create_image() { int i,j,m,itype,atom1,atom2; double diameter,delx,dely,delz; double *color,*color1,*color2; double xmid[3]; // initialze image buffers // no need to init surfaceBuffer, since will be based on depth int red = background[0]; int green = background[1]; int blue = background[2]; int ix,iy; for (iy = 0; iy < height; iy ++) { for (ix = 0; ix < width; ix ++) { imageBuffer[iy * width * 3 + ix * 3 + 0] = red; imageBuffer[iy * width * 3 + ix * 3 + 1] = green; imageBuffer[iy * width * 3 + ix * 3 + 2] = blue; depthBuffer[iy * width + ix] = -1; } } // render my atoms if (atomflag) { double **x = atom->x; m = 0; for (i = 0; i < nchoose; i++) { j = clist[i]; if (acolor == TYPE) { itype = static_cast (buf[m]); color = colortype[itype]; } else if (acolor == ELEMENT) { itype = static_cast (buf[m]); color = colorelement[itype]; } else if (acolor == ATTRIBUTE) { color = value2color(buf[m]); } if (adiam == NUMERIC) { diameter = adiamvalue; } else if (adiam == TYPE) { itype = static_cast (buf[m+1]); diameter = diamtype[itype]; } else if (adiam == ELEMENT) { itype = static_cast (buf[m+1]); diameter = diamelement[itype]; } else if (adiam == ATTRIBUTE) { diameter = buf[m+1]; } draw_sphere(x[j],color,diameter); m += size_one; } } // render bonds for my atoms // both atoms in bond must be selected for bond to be rendered // if newton_bond is off, only render bond once // render bond in 2 pieces if crosses periodic boundary // if bond is deleted (type = 0), do not render // if bond is turned off (type < 0), still render if (bondflag) { double **x = atom->x; int *tag = atom->tag; int **bond_atom = atom->bond_atom; int **bond_type = atom->bond_type; int *num_bond = atom->num_bond; int *type = atom->type; int nlocal = atom->nlocal; int nall = atom->nlocal + atom->nghost; int newton_bond = force->newton_bond; // communicate choose flag for ghost atoms to know if they are selected // if bcolor/bdiam = ATOM, setup bufcopy to comm atom color/diam attributes if (comm_forward == 3) { if (nall > maxbufcopy) { maxbufcopy = atom->nmax; memory->destroy(bufcopy); memory->create(bufcopy,maxbufcopy,2,"dump:bufcopy"); } for (i = 0; i < nlocal; i++) bufcopy[i][0] = bufcopy[i][1] = 0.0; m = 0; for (i = 0; i < nchoose; i++) { j = clist[i]; bufcopy[j][0] = buf[m]; bufcopy[j][1] = buf[m+1]; m += size_one; } } comm->forward_comm_dump(this); for (i = 0; i < nchoose; i++) { atom1 = clist[i]; for (m = 0; m < num_bond[atom1]; m++) { atom2 = atom->map(bond_atom[atom1][m]); if (atom2 < 0 || !choose[atom2]) continue; if (newton_bond == 0 && tag[atom1] > tag[atom2]) continue; if (bond_type[atom1][m] == 0) continue; if (bcolor == ATOM) { if (acolor == TYPE) { color1 = colortype[type[atom1]]; color2 = colortype[type[atom2]]; } else if (acolor == ELEMENT) { color1 = colorelement[type[atom1]]; color2 = colorelement[type[atom2]]; } else if (acolor == ATTRIBUTE) { color1 = value2color(bufcopy[atom1][0]); color2 = value2color(bufcopy[atom2][0]); } } else if (bcolor == TYPE) { itype = bond_type[atom1][m]; if (itype < 0) itype = -itype; color = bcolortype[itype]; } if (bdiam == NUMERIC) { diameter = bdiamvalue; } else if (bdiam == ATOM) { if (adiam == NUMERIC) { diameter = adiamvalue; } else if (adiam == TYPE) { diameter = MIN(diamtype[type[atom1]],diamtype[type[atom1]]); } else if (adiam == ELEMENT) { diameter = MIN(diamelement[type[atom1]],diamelement[type[atom1]]); } else if (adiam == ATTRIBUTE) { diameter = MIN(bufcopy[atom1][1],bufcopy[atom2][1]); } } else if (bdiam == TYPE) { itype = bond_type[atom1][m]; if (itype < 0) itype = -itype; diameter = bdiamtype[itype]; } // draw cylinder in 2 pieces if bcolor = ATOM // or bond crosses periodic boundary delx = x[atom2][0] - x[atom1][0]; dely = x[atom2][1] - x[atom1][1]; delz = x[atom2][2] - x[atom1][2]; if (bcolor == ATOM || domain->minimum_image_check(delx,dely,delz)) { domain->minimum_image(delx,dely,delz); xmid[0] = x[atom1][0] + 0.5*delx; xmid[1] = x[atom1][1] + 0.5*dely; xmid[2] = x[atom1][2] + 0.5*delz; if (bcolor == ATOM) draw_cylinder(x[atom1],xmid,color1,diameter,3); else draw_cylinder(x[atom1],xmid,color,diameter,3); xmid[0] = x[atom2][0] - 0.5*delx; xmid[1] = x[atom2][1] - 0.5*dely; xmid[2] = x[atom2][2] - 0.5*delz; if (bcolor == ATOM) draw_cylinder(xmid,x[atom2],color2,diameter,3); else draw_cylinder(xmid,x[atom2],color,diameter,3); } else draw_cylinder(x[atom1],x[atom2],color,diameter,3); } } } // render outline of simulation box, orthogonal or triclinic if (boxflag) { double diameter = MIN(boxxhi-boxxlo,boxyhi-boxylo); if (domain->dimension == 3) diameter = MIN(diameter,boxzhi-boxzlo); diameter *= boxdiam; double (*corners)[3]; double corner[8][3]; if (domain->triclinic == 0) { corner[0][0] = boxxlo; corner[0][1] = boxylo; corner[0][2] = boxzlo; corner[1][0] = boxxhi; corner[1][1] = boxylo; corner[1][2] = boxzlo; corner[2][0] = boxxlo; corner[2][1] = boxyhi; corner[2][2] = boxzlo; corner[3][0] = boxxhi; corner[3][1] = boxyhi; corner[3][2] = boxzlo; corner[4][0] = boxxlo; corner[4][1] = boxylo; corner[4][2] = boxzhi; corner[5][0] = boxxhi; corner[5][1] = boxylo; corner[5][2] = boxzhi; corner[6][0] = boxxlo; corner[6][1] = boxyhi; corner[6][2] = boxzhi; corner[7][0] = boxxhi; corner[7][1] = boxyhi; corner[7][2] = boxzhi; corners = corner; } else { domain->box_corners(); corners = domain->corners; } draw_cylinder(corners[0],corners[1],boxcolor,diameter,3); draw_cylinder(corners[2],corners[3],boxcolor,diameter,3); draw_cylinder(corners[0],corners[2],boxcolor,diameter,3); draw_cylinder(corners[1],corners[3],boxcolor,diameter,3); draw_cylinder(corners[0],corners[4],boxcolor,diameter,3); draw_cylinder(corners[1],corners[5],boxcolor,diameter,3); draw_cylinder(corners[2],corners[6],boxcolor,diameter,3); draw_cylinder(corners[3],corners[7],boxcolor,diameter,3); draw_cylinder(corners[4],corners[5],boxcolor,diameter,3); draw_cylinder(corners[6],corners[7],boxcolor,diameter,3); draw_cylinder(corners[4],corners[6],boxcolor,diameter,3); draw_cylinder(corners[5],corners[7],boxcolor,diameter,3); } // render XYZ axes in red/green/blue // offset by 10% of box size and scale by axeslen if (axesflag) { double diameter = MIN(boxxhi-boxxlo,boxyhi-boxylo); if (domain->dimension == 3) diameter = MIN(diameter,boxzhi-boxzlo); diameter *= axesdiam; double (*corners)[3]; double corner[8][3]; if (domain->triclinic == 0) { corner[0][0] = boxxlo; corner[0][1] = boxylo; corner[0][2] = boxzlo; corner[1][0] = boxxhi; corner[1][1] = boxylo; corner[1][2] = boxzlo; corner[2][0] = boxxlo; corner[2][1] = boxyhi; corner[2][2] = boxzlo; corner[4][0] = boxxlo; corner[4][1] = boxylo; corner[4][2] = boxzhi; corners = corner; } else { domain->box_corners(); corners = domain->corners; } double offset = MAX(boxxhi-boxxlo,boxyhi-boxylo); if (domain->dimension == 3) offset = MAX(offset,boxzhi-boxzlo); offset *= 0.1; corners[0][0] -= offset; corners[0][1] -= offset; corners[0][2] -= offset; corners[1][0] -= offset; corners[1][1] -= offset; corners[1][2] -= offset; corners[2][0] -= offset; corners[2][1] -= offset; corners[2][2] -= offset; corners[4][0] -= offset; corners[4][1] -= offset; corners[4][2] -= offset; corners[1][0] = corners[0][0] + axeslen*(corners[1][0]-corners[0][0]); corners[1][1] = corners[0][1] + axeslen*(corners[1][1]-corners[0][1]); corners[1][2] = corners[0][2] + axeslen*(corners[1][2]-corners[0][2]); corners[2][0] = corners[0][0] + axeslen*(corners[2][0]-corners[0][0]); corners[2][1] = corners[0][1] + axeslen*(corners[2][1]-corners[0][1]); corners[2][2] = corners[0][2] + axeslen*(corners[2][2]-corners[0][2]); corners[4][0] = corners[0][0] + axeslen*(corners[4][0]-corners[0][0]); corners[4][1] = corners[0][1] + axeslen*(corners[4][1]-corners[0][1]); corners[4][2] = corners[0][2] + axeslen*(corners[4][2]-corners[0][2]); draw_cylinder(corners[0],corners[1],color2rgb("red"),diameter,3); draw_cylinder(corners[0],corners[2],color2rgb("green"),diameter,3); draw_cylinder(corners[0],corners[4],color2rgb("blue"),diameter,3); } } /* ---------------------------------------------------------------------- draw sphere at x with surfaceColor and diameter render pixel by pixel onto image plane with depth buffering ------------------------------------------------------------------------- */ void DumpImage::draw_sphere(double *x, double *surfaceColor, double diameter) { int ix,iy; double projRad; double xlocal[3],surface[3]; double depth; xlocal[0] = x[0] - xctr; xlocal[1] = x[1] - yctr; xlocal[2] = x[2] - zctr; double xmap = MathExtra::dot3(camRight,xlocal); double ymap = MathExtra::dot3(camUp,xlocal); double dist = MathExtra::dot3(camPos,camDir) - MathExtra::dot3(xlocal,camDir); double radius = 0.5*diameter; double radsq = radius*radius; double pixelWidth = (tanPerPixel > 0) ? tanPerPixel * dist : -tanPerPixel / zoom; double pixelRadiusFull = radius / pixelWidth; int pixelRadius = static_cast (pixelRadiusFull + 0.5) + 1; double xf = xmap / pixelWidth; double yf = ymap / pixelWidth; int xc = static_cast (xf); int yc = static_cast (yf); double width_error = xf - xc; double height_error = yf - yc; // shift 0,0 to screen center (vs lower left) xc += width / 2; yc += height / 2; for (iy = yc - pixelRadius; iy <= yc + pixelRadius; iy++) { for (ix = xc - pixelRadius; ix <= xc + pixelRadius; ix++) { if (iy < 0 || iy >= height || ix < 0 || ix >= width) continue; surface[1] = ((iy - yc) - height_error) * pixelWidth; surface[0] = ((ix - xc) - width_error) * pixelWidth; projRad = surface[0]*surface[0] + surface[1]*surface[1]; // outside the sphere in the projected image if (projRad > radsq) continue; surface[2] = sqrt(radsq - projRad); depth = dist - surface[2]; surface[0] /= radius; surface[1] /= radius; surface[2] /= radius; draw_pixel (ix, iy, depth, surface, surfaceColor); } } } /* ---------------------------------------------------------------------- draw cylinder from x to y with surfaceColor and diameter render pixel by pixel onto image plane with depth buffering if sflag = 0, draw no end spheres if sflag = 1, draw 1st end sphere if sflag = 2, draw 2nd end sphere if sflag = 3, draw both end spheres ------------------------------------------------------------------------- */ void DumpImage::draw_cylinder(double *x, double *y, double *surfaceColor, double diameter, int sflag) { double surface[3], normal[3]; double mid[3],xaxis[3],yaxis[3],zaxis[3]; double camLDir[3], camLRight[3], camLUp[3]; double zmin, zmax; if (sflag % 2) draw_sphere(x,surfaceColor,diameter); if (sflag/2) draw_sphere(y,surfaceColor,diameter); double radius = 0.5*diameter; double radsq = radius*radius; zaxis[0] = y[0] - x[0]; zaxis[1] = y[1] - x[1]; zaxis[2] = y[2] - x[2]; double rasterWidth = fabs(MathExtra::dot3(zaxis, camRight)) + diameter; double rasterHeight = fabs(MathExtra::dot3(zaxis, camUp)) + diameter; mid[0] = (y[0] + x[0]) * 0.5 - xctr; mid[1] = (y[1] + x[1]) * 0.5 - yctr; mid[2] = (y[2] + x[2]) * 0.5 - zctr; double len = MathExtra::len3(zaxis); MathExtra::scale3(1.0/len,zaxis); len *= 0.5; zmax = len; zmin = -len; double xmap = MathExtra::dot3(camRight,mid); double ymap = MathExtra::dot3(camUp,mid); double dist = MathExtra::dot3(camPos,camDir) - MathExtra::dot3(mid,camDir); double pixelWidth = (tanPerPixel > 0) ? tanPerPixel * dist : -tanPerPixel / zoom; double xf = xmap / pixelWidth; double yf = ymap / pixelWidth; int xc = static_cast (xf); int yc = static_cast (yf); double width_error = xf - xc; double height_error = yf - yc; // shift 0,0 to screen center (vs lower left) xc += width / 2; yc += height / 2; double pixelHalfWidthFull = (rasterWidth * 0.5) / pixelWidth; double pixelHalfHeightFull = (rasterHeight * 0.5) / pixelWidth; int pixelHalfWidth = static_cast (pixelHalfWidthFull + 0.5); int pixelHalfHeight = static_cast (pixelHalfHeightFull + 0.5); if (zaxis[0] == camDir[0] && zaxis[1] == camDir[1] && zaxis[2] == camDir[2]) return; if (zaxis[0] == -camDir[0] && zaxis[1] == -camDir[1] && zaxis[2] == -camDir[2]) return; MathExtra::cross3(zaxis,camDir,yaxis); MathExtra::norm3(yaxis); MathExtra::cross3(yaxis,zaxis,xaxis); MathExtra::norm3(xaxis); camLDir[0] = MathExtra::dot3(camDir,xaxis); camLDir[1] = 0.0; camLDir[2] = MathExtra::dot3(camDir,zaxis); camLRight[0] = MathExtra::dot3(camRight,xaxis); camLRight[1] = MathExtra::dot3(camRight,yaxis); camLRight[2] = MathExtra::dot3(camRight,zaxis); MathExtra::norm3(camLRight); camLUp[0] = MathExtra::dot3(camUp,xaxis); camLUp[1] = MathExtra::dot3(camUp,yaxis); camLUp[2] = MathExtra::dot3(camUp,zaxis); MathExtra::norm3(camLUp); double a = camLDir[0] * camLDir[0]; for (int iy = yc - pixelHalfHeight; iy <= yc + pixelHalfHeight; iy ++) { for (int ix = xc - pixelHalfWidth; ix <= xc + pixelHalfWidth; ix ++) { if (iy < 0 || iy >= height || ix < 0 || ix >= width) continue; double sy = ((iy - yc) - height_error) * pixelWidth; double sx = ((ix - xc) - width_error) * pixelWidth; surface[0] = camLRight[0] * sx + camLUp[0] * sy; surface[1] = camLRight[1] * sx + camLUp[1] * sy; surface[2] = camLRight[2] * sx + camLUp[2] * sy; double b = 2 * camLDir[0] * surface[0]; double c = surface[0] * surface[0] + surface[1] * surface[1] - radsq; double partial = b*b - 4*a*c; if (partial < 0) continue; partial = sqrt (partial); double t = (-b + partial) / (2*a); double t2 = (-b - partial) / (2*a); if (t2 > t) { t = t2; } surface[0] += t * camLDir[0]; surface[1] += t * camLDir[1]; surface[2] += t * camLDir[2]; if (surface[2] > zmax || surface[2] < zmin) continue; // convert surface into the surface normal normal[0] = surface[0] / radius; normal[1] = surface[1] / radius; normal[2] = 0.0; // in camera space surface[0] = MathExtra::dot3 (normal, camLRight); surface[1] = MathExtra::dot3 (normal, camLUp); surface[2] = MathExtra::dot3 (normal, camLDir); double depth = dist - t; draw_pixel (ix, iy, depth, surface, surfaceColor); } } } /* ---------------------------------------------------------------------- */ void DumpImage::draw_pixel(int ix, int iy, double depth, double *surface, double *surfaceColor) { double diffuseKey,diffuseFill,diffuseBack,specularKey; if (depth < 0 || (depthBuffer[ix + iy*width] >= 0 && depth >= depthBuffer[ix + iy*width])) return; depthBuffer[ix + iy*width] = depth; // store only the tangent relative to the camera normal (0,0,-1) surfaceBuffer[0 + ix * 2 + iy*width * 2] = surface[1]; surfaceBuffer[1 + ix * 2 + iy*width * 2] = -surface[0]; diffuseKey = saturate(MathExtra::dot3(surface, keyLightDir)); diffuseFill = saturate(MathExtra::dot3(surface, fillLightDir)); diffuseBack = saturate(MathExtra::dot3(surface, backLightDir)); specularKey = pow(saturate(MathExtra::dot3(surface, keyHalfDir)), specularHardness) * specularIntensity; double c[3]; c[0] = surfaceColor[0] * ambientColor[0]; c[1] = surfaceColor[1] * ambientColor[1]; c[2] = surfaceColor[2] * ambientColor[2]; c[0] += surfaceColor[0] * keyLightColor[0] * diffuseKey; c[1] += surfaceColor[1] * keyLightColor[1] * diffuseKey; c[2] += surfaceColor[2] * keyLightColor[2] * diffuseKey; c[0] += keyLightColor[0] * specularKey; c[1] += keyLightColor[1] * specularKey; c[2] += keyLightColor[2] * specularKey; c[0] += surfaceColor[0] * fillLightColor[0] * diffuseFill; c[1] += surfaceColor[1] * fillLightColor[1] * diffuseFill; c[2] += surfaceColor[2] * fillLightColor[2] * diffuseFill; c[0] += surfaceColor[0] * backLightColor[0] * diffuseBack; c[1] += surfaceColor[1] * backLightColor[1] * diffuseBack; c[2] += surfaceColor[2] * backLightColor[2] * diffuseBack; c[0] = saturate(c[0]); c[1] = saturate(c[1]); c[2] = saturate(c[2]); imageBuffer[0 + ix*3 + iy*width*3] = static_cast(c[0] * 255.0); imageBuffer[1 + ix*3 + iy*width*3] = static_cast(c[1] * 255.0); imageBuffer[2 + ix*3 + iy*width*3] = static_cast(c[2] * 255.0); } /* ---------------------------------------------------------------------- */ void DumpImage::compute_SSAO() { // used for rasterizing the spheres double delTheta = 2.0*MY_PI / SSAOSamples; // typical neighborhood value for shading double pixelWidth = (tanPerPixel > 0) ? tanPerPixel : -tanPerPixel / zoom; int pixelRadius = (int) trunc (SSAORadius / pixelWidth + 0.5); int x,y,s; int hPart = height / nprocs; int index = me * hPart * width; for (y = me * hPart; y < (me + 1) * hPart; y ++) { for (x = 0; x < width; x ++, index ++) { double cdepth = depthBuffer[index]; if (cdepth < 0) { continue; } double sx = surfaceBuffer[index * 2 + 0]; double sy = surfaceBuffer[index * 2 + 1]; double sin_t = -sqrt(sx*sx + sy*sy); double theta = random->uniform() * SSAOJitter; double ao = 0.0; for (s = 0; s < SSAOSamples; s ++) { double hx = cos(theta); double hy = sin(theta); theta += delTheta; // multiply by z cross surface tangent // so that dot (aka cos) works here double scaled_sin_t = sin_t * (hx*sy + hy*sx); // Bresenham's line algorithm to march over depthBuffer int dx = static_cast (hx * pixelRadius); int dy = static_cast (hy * pixelRadius); int ex = x + dx; if (ex < 0) { ex = 0; } if (ex >= width) { ex = width - 1; } int ey = y + dy; if (ey < 0) { ey = 0; } if (ey >= height) { ey = height - 1; } double delta; int small, large; double lenIncr; if (fabs(hx) > fabs(hy)) { small = (hx > 0) ? 1 : -1; large = (hy > 0) ? width : -width; delta = fabs(hy / hx); } else { small = (hy > 0) ? width : -width; large = (hx > 0) ? 1 : -1; delta = fabs(hx / hy); } lenIncr = sqrt (1 + delta * delta) * pixelWidth; // initialize with one step // because the center point doesn't need testing int end = ex + ey * width; int ind = index + small; double len = lenIncr; double err = delta; if (err >= 1.0) { ind += large; err -= 1.0; } double minPeak = -1; double peakLen = 0.0; int stepsTaken = 1; while ((small > 0 && ind <= end) || (small < 0 && ind >= end)) { if (ind < 0 || ind >= (width*height)) { break; } // cdepth - depthBuffer B/C we want it in the negative z direction if (minPeak < 0 || (depthBuffer[ind] >= 0 && depthBuffer[ind] < minPeak)) { minPeak = depthBuffer[ind]; peakLen = len; } ind += small; len += lenIncr; err += delta; if (err >= 1.0) { ind += large; err -= 1.0; } stepsTaken ++; } if (peakLen > 0) { double h = atan ((cdepth - minPeak) / peakLen); ao += saturate(sin (h) - scaled_sin_t); } else { ao += saturate(-scaled_sin_t); } } ao /= (double)SSAOSamples; double c[3]; c[0] = (double) (*(unsigned char *) &imageBuffer[index * 3 + 0]); c[1] = (double) (*(unsigned char *) &imageBuffer[index * 3 + 1]); c[2] = (double) (*(unsigned char *) &imageBuffer[index * 3 + 2]); c[0] *= (1.0 - ao); c[1] *= (1.0 - ao); c[2] *= (1.0 - ao); imageBuffer[index * 3 + 0] = (int) c[0]; imageBuffer[index * 3 + 1] = (int) c[1]; imageBuffer[index * 3 + 2] = (int) c[2]; } } } /* ---------------------------------------------------------------------- */ void DumpImage::write_JPG() { #ifdef LAMMPS_JPEG struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; JSAMPROW row_pointer; cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); jpeg_stdio_dest(&cinfo, fp); cinfo.image_width = width; cinfo.image_height = height; cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, 100, 1); jpeg_start_compress(&cinfo, 1); while (cinfo.next_scanline < cinfo.image_height) { row_pointer = (JSAMPROW) &writeBuffer[(cinfo.image_height - 1 - cinfo.next_scanline) * 3 * width]; jpeg_write_scanlines(&cinfo, &row_pointer, 1); } jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); #endif } /* ---------------------------------------------------------------------- */ void DumpImage::write_PPM() { int x,y; fprintf (fp,"P6\n%d %d\n255\n",width,height); for (y = height-1; y >= 0; y --) for (x = 0; x < width; x ++) fprintf (fp,"%c%c%c", writeBuffer[0 + x*3 + y*width*3], writeBuffer[1 + x*3 + y*width*3], writeBuffer[2 + x*3 + y*width*3]); } /* ---------------------------------------------------------------------- */ int DumpImage::pack_comm(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; m = 0; if (comm_forward == 1) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = choose[j]; } } else { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = choose[j]; buf[m++] = bufcopy[j][0]; buf[m++] = bufcopy[j][1]; } } return comm_forward; } /* ---------------------------------------------------------------------- */ void DumpImage::unpack_comm(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; if (comm_forward == 1) for (i = first; i < last; i++) choose[i] = static_cast (buf[m++]); else { for (i = first; i < last; i++) { choose[i] = static_cast (buf[m++]); bufcopy[i][0] = buf[m++]; bufcopy[i][1] = buf[m++]; } } } /* ---------------------------------------------------------------------- */ int DumpImage::modify_param(int narg, char **arg) { int n = DumpCustom::modify_param(narg,arg); if (n) return n; if (strcmp(arg[0],"acolor") == 0) { if (narg < 3) error->all(FLERR,"Illegal dump_modify command"); int nlo,nhi; force->bounds(arg[1],atom->ntypes,nlo,nhi); // ptrs = list of ncount colornames separated by '/' int ncount = 1; char *nextptr; char *ptr = arg[2]; while (nextptr = strchr(ptr,'/')) { ptr = nextptr + 1; ncount++; } char **ptrs = new char*[ncount+1]; ncount = 0; ptrs[ncount++] = strtok(arg[2],"/"); while (ptrs[ncount++] = strtok(NULL,"/")); ncount--; // assign each of ncount colors in round-robin fashion to types int m = 0; for (int i = nlo; i <= nhi; i++) { colortype[i] = color2rgb(ptrs[m%ncount]); if (colortype[i] == NULL) error->all(FLERR,"Invalid color in dump_modify command"); m++; } delete [] ptrs; return 3; } else if (strcmp(arg[0],"adiam") == 0) { if (narg < 3) error->all(FLERR,"Illegal dump_modify command"); int nlo,nhi; force->bounds(arg[1],atom->ntypes,nlo,nhi); double diam = atof(arg[2]); if (diam <= 0.0) error->all(FLERR,"Illegal dump_modify command"); for (int i = nlo; i <= nhi; i++) diamtype[i] = diam; return 3; } else if (strcmp(arg[0],"amap") == 0) { if (narg < 6) error->all(FLERR,"Illegal dump_modify command"); if (!islower(arg[1][0])) { mlo = NUMERIC; mlovalue = atof(arg[1]); } else if (strcmp(arg[1],"min") == 0) mlo = MINVALUE; else error->all(FLERR,"Illegal dump_modify command"); if (!islower(arg[2][0])) { mhi = NUMERIC; mhivalue = atof(arg[2]); } else if (strcmp(arg[2],"max") == 0) mhi = MAXVALUE; else error->all(FLERR,"Illegal dump_modify command"); if (mlo == NUMERIC && mhi == NUMERIC && mlovalue >= mhivalue) error->all(FLERR,"Illega dump_modify command"); if (strlen(arg[3]) != 2) error->all(FLERR,"Illegal dump_modify command"); if (arg[3][0] == 'c') mstyle = CONTINUOUS; else if (arg[3][0] == 'd') mstyle = DISCRETE; else if (arg[3][0] == 's') mstyle = SEQUENTIAL; else error->all(FLERR,"Illegal dump_modify command"); if (arg[3][1] == 'a') mrange = ABSOLUTE; else if (arg[3][1] == 'f') mrange = FRACTIONAL; else error->all(FLERR,"Illegal dump_modify command"); if (mstyle == SEQUENTIAL) { mbinsize = atof(arg[4]); if (mbinsize <= 0.0) error->all(FLERR,"Illegal dump_modify command"); } mbinsizeinv = 1.0/mbinsize; nentry = atoi(arg[5]); mentry = new MapEntry[nentry]; int n = 6; for (int i = 0; i < nentry; i++) { if (mstyle == CONTINUOUS) { if (n+2 > narg) error->all(FLERR,"Illegal dump_modify command"); if (!islower(arg[n][0])) { mentry[i].single = NUMERIC; mentry[i].svalue = atof(arg[n]); } else if (strcmp(arg[n],"min") == 0) mentry[i].single = MINVALUE; else if (strcmp(arg[n],"max") == 0) mentry[i].single = MAXVALUE; else error->all(FLERR,"Illegal dump_modify command"); mentry[i].color = color2rgb(arg[n+1]); n += 2; } else if (mstyle == DISCRETE) { if (n+3 > narg) error->all(FLERR,"Illegal dump_modify command"); if (!islower(arg[n][0])) { mentry[i].lo = NUMERIC; mentry[i].lvalue = atof(arg[n]); } else if (strcmp(arg[n],"min") == 0) mentry[i].single = MINVALUE; else if (strcmp(arg[n],"max") == 0) mentry[i].single = MAXVALUE; else error->all(FLERR,"Illegal dump_modify command"); if (!islower(arg[n+1][0])) { mentry[i].hi = NUMERIC; mentry[i].hvalue = atof(arg[n+1]); } else if (strcmp(arg[n+1],"min") == 0) mentry[i].single = MINVALUE; else if (strcmp(arg[n+1],"max") == 0) mentry[i].single = MAXVALUE; else error->all(FLERR,"Illegal dump_modify command"); mentry[i].color = color2rgb(arg[n+2]); n += 3; } else if (mstyle == SEQUENTIAL) { if (n+1 > narg) error->all(FLERR,"Illegal dump_modify command"); mentry[i].color = color2rgb(arg[n]); n += 1; } if (mentry[i].color == NULL) error->all(FLERR,"Invalid color in dump_modify command"); } if (mstyle == CONTINUOUS) { if (nentry < 2) error->all(FLERR,"Invalid color map in dump_modify command"); if (mentry[0].single != MINVALUE || mentry[nentry-1].single != MAXVALUE) error->all(FLERR,"Invalid color map in dump_modify command"); for (int i = 2; i < nentry-1; i++) if (mentry[i].svalue <= mentry[i-1].svalue) error->all(FLERR,"Invalid color map in dump_modify command"); } else if (mstyle == DISCRETE) { if (nentry < 1) error->all(FLERR,"Invalid color map in dump_modify command"); if (mentry[nentry-1].lo != MINVALUE || mentry[nentry-1].hi != MAXVALUE) error->all(FLERR,"Invalid color map in dump_modify command"); } else if (mstyle == SEQUENTIAL) { if (nentry < 1) error->all(FLERR,"Invalid color map in dump_modify command"); } return n; } else if (strcmp(arg[0],"bcolor") == 0) { if (narg < 3) error->all(FLERR,"Illegal dump_modify command"); if (atom->nbondtypes == 0) error->all(FLERR,"Dump modify bcolor not allowed with no bond types"); int nlo,nhi; force->bounds(arg[1],atom->nbondtypes,nlo,nhi); // ptrs = list of ncount colornames separated by '/' int ncount = 1; char *nextptr; char *ptr = arg[2]; while (nextptr = strchr(ptr,'/')) { ptr = nextptr + 1; ncount++; } char **ptrs = new char*[ncount+1]; ncount = 0; ptrs[ncount++] = strtok(arg[2],"/"); while (ptrs[ncount++] = strtok(NULL,"/")); ncount--; // assign each of ncount colors in round-robin fashion to types int m = 0; for (int i = nlo; i <= nhi; i++) { bcolortype[i] = color2rgb(ptrs[m%ncount]); if (bcolortype[i] == NULL) error->all(FLERR,"Invalid color in dump_modify command"); m++; } delete [] ptrs; return 3; } else if (strcmp(arg[0],"bdiam") == 0) { if (narg < 3) error->all(FLERR,"Illegal dump_modify command"); if (atom->nbondtypes == 0) error->all(FLERR,"Dump modify bdiam not allowed with no bond types"); int nlo,nhi; force->bounds(arg[1],atom->ntypes,nlo,nhi); double diam = atof(arg[2]); if (diam <= 0.0) error->all(FLERR,"Illegal dump_modify command"); for (int i = nlo; i <= nhi; i++) bdiamtype[i] = diam; return 3; } else if (strcmp(arg[0],"backcolor") == 0) { if (narg < 2) error->all(FLERR,"Illegal dump_modify command"); double *color = color2rgb(arg[1]); if (color == NULL) error->all(FLERR,"Invalid color in dump_modify command"); background[0] = static_cast (color[0]*255.0); background[1] = static_cast (color[1]*255.0); background[2] = static_cast (color[2]*255.0); return 2; } else if (strcmp(arg[0],"boxcolor") == 0) { if (narg < 2) error->all(FLERR,"Illegal dump_modify command"); boxcolor = color2rgb(arg[1]); if (boxcolor == NULL) error->all(FLERR,"Invalid color in dump_modify command"); return 2; } else if (strcmp(arg[0],"color") == 0) { if (narg < 5) error->all(FLERR,"Illegal dump_modify command"); username = (char **) memory->srealloc(username,(ncolors+1)*sizeof(char *),"dump:username"); memory->grow(userrgb,ncolors+1,3,"dump:userrgb"); int n = strlen(arg[1]) + 1; username[ncolors] = new char[n]; strcpy(username[ncolors],arg[1]); userrgb[ncolors][0] = atof(arg[2]); userrgb[ncolors][1] = atof(arg[3]); userrgb[ncolors][2] = atof(arg[4]); if (userrgb[ncolors][0] < 0.0 || userrgb[ncolors][0] > 1.0 || userrgb[ncolors][1] < 0.0 || userrgb[ncolors][1] > 1.0 || userrgb[ncolors][2] < 0.0 || userrgb[ncolors][2] > 1.0) error->all(FLERR,"Illegal dump_modify command"); ncolors++; return 5; } return 0; } /* ---------------------------------------------------------------------- convert value into an RGB color via color map ------------------------------------------------------------------------- */ double *DumpImage::value2color(double value) { double lo,hi; value = MAX(value,locurrent); value = MIN(value,hicurrent); if (mrange == FRACTIONAL) { if (locurrent == hicurrent) value = 0.0; else value = (value-locurrent) / (hicurrent-locurrent); lo = 0.0; hi = 1.0; } else { lo = locurrent; hi = hicurrent; } if (mstyle == CONTINUOUS) { for (int i = 0; i < nentry-1; i++) if (value >= mentry[i].svalue && value <= mentry[i+1].svalue) { double fraction = (value-mentry[i].svalue) / (mentry[i+1].svalue-mentry[i].svalue); interpolate[0] = mentry[i].color[0] + fraction*(mentry[i+1].color[0]-mentry[i].color[0]); interpolate[1] = mentry[i].color[1] + fraction*(mentry[i+1].color[1]-mentry[i].color[1]); interpolate[2] = mentry[i].color[2] + fraction*(mentry[i+1].color[2]-mentry[i].color[2]); return interpolate; } } else if (mstyle == DISCRETE) { for (int i = 0; i < nentry; i++) if (value >= mentry[i].lvalue && value <= mentry[i].hvalue) return mentry[i].color; } else { int ibin = static_cast ((value-lo) * mbinsizeinv); return mentry[ibin%nentry].color; } return NULL; } /* ---------------------------------------------------------------------- search the list of color names for the string color return a pointer to the 3 floating point RGB values search user-defined color names first, then the list of NCOLORS names ------------------------------------------------------------------------- */ -double *DumpImage::color2rgb(char *color) +double *DumpImage::color2rgb(const char *color) { - static char *name[NCOLORS] = { + static const char *name[NCOLORS] = { "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige", "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown", "burlywood", "cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue", "cornsilk", "crimson", "cyan", "darkblue", "darkcyan", "darkgoldenrod", "darkgray", "darkgreen", "darkkhaki", "darkmagenta", "darkolivegreen", "darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen", "darkslateblue", "darkslategray", "darkturquoise", "darkviolet", "deeppink", "deepskyblue", "dimgray", "dodgerblue", "firebrick", "floralwhite", "forestgreen", "fuchsia", "gainsboro", "ghostwhite", "gold", "goldenrod", "gray", "green", "greenyellow", "honeydew", "hotpink", "indianred", "indigo", "ivory", "khaki", "lavender", "lavenderblush", "lawngreen", "lemonchiffon", "lightblue", "lightcoral", "lightcyan", "lightgoldenrodyellow", "lightgreen", "lightgrey", "lightpink", "lightsalmon", "lightseagreen", "lightskyblue", "lightslategray", "lightsteelblue", "lightyellow", "lime", "limegreen", "linen", "magenta", "maroon", "mediumaquamarine", "mediumblue", "mediumorchid", "mediumpurple", "mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise", "mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin", "navajowhite", "navy", "oldlace", "olive", "olivedrab", "orange", "orangered", "orchid", "palegoldenrod", "palegreen", "paleturquoise", "palevioletred", "papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue", "purple", "red", "rosybrown", "royalblue", "saddlebrown", "salmon", "sandybrown", "seagreen", "seashell", "sienna", "silver", "skyblue", "slateblue", "slategray", "snow", "springgreen", "steelblue", "tan", "teal", "thistle", "tomato", "turquoise", "violet", "wheat", "white", "whitesmoke", "yellow", "yellowgreen" }; static double rgb[NCOLORS][3] = { {240/255.0, 248/255.0, 255/255.0}, {250/255.0, 235/255.0, 215/255.0}, {0/255.0, 255/255.0, 255/255.0}, {127/255.0, 255/255.0, 212/255.0}, {240/255.0, 255/255.0, 255/255.0}, {245/255.0, 245/255.0, 220/255.0}, {255/255.0, 228/255.0, 196/255.0}, {0/255.0, 0/255.0, 0/255.0}, {255/255.0, 255/255.0, 205/255.0}, {0/255.0, 0/255.0, 255/255.0}, {138/255.0, 43/255.0, 226/255.0}, {165/255.0, 42/255.0, 42/255.0}, {222/255.0, 184/255.0, 135/255.0}, {95/255.0, 158/255.0, 160/255.0}, {127/255.0, 255/255.0, 0/255.0}, {210/255.0, 105/255.0, 30/255.0}, {255/255.0, 127/255.0, 80/255.0}, {100/255.0, 149/255.0, 237/255.0}, {255/255.0, 248/255.0, 220/255.0}, {220/255.0, 20/255.0, 60/255.0}, {0/255.0, 255/255.0, 255/255.0}, {0/255.0, 0/255.0, 139/255.0}, {0/255.0, 139/255.0, 139/255.0}, {184/255.0, 134/255.0, 11/255.0}, {169/255.0, 169/255.0, 169/255.0}, {0/255.0, 100/255.0, 0/255.0}, {189/255.0, 183/255.0, 107/255.0}, {139/255.0, 0/255.0, 139/255.0}, {85/255.0, 107/255.0, 47/255.0}, {255/255.0, 140/255.0, 0/255.0}, {153/255.0, 50/255.0, 204/255.0}, {139/255.0, 0/255.0, 0/255.0}, {233/255.0, 150/255.0, 122/255.0}, {143/255.0, 188/255.0, 143/255.0}, {72/255.0, 61/255.0, 139/255.0}, {47/255.0, 79/255.0, 79/255.0}, {0/255.0, 206/255.0, 209/255.0}, {148/255.0, 0/255.0, 211/255.0}, {255/255.0, 20/255.0, 147/255.0}, {0/255.0, 191/255.0, 255/255.0}, {105/255.0, 105/255.0, 105/255.0}, {30/255.0, 144/255.0, 255/255.0}, {178/255.0, 34/255.0, 34/255.0}, {255/255.0, 250/255.0, 240/255.0}, {34/255.0, 139/255.0, 34/255.0}, {255/255.0, 0/255.0, 255/255.0}, {220/255.0, 220/255.0, 220/255.0}, {248/255.0, 248/255.0, 255/255.0}, {255/255.0, 215/255.0, 0/255.0}, {218/255.0, 165/255.0, 32/255.0}, {128/255.0, 128/255.0, 128/255.0}, {0/255.0, 128/255.0, 0/255.0}, {173/255.0, 255/255.0, 47/255.0}, {240/255.0, 255/255.0, 240/255.0}, {255/255.0, 105/255.0, 180/255.0}, {205/255.0, 92/255.0, 92/255.0}, {75/255.0, 0/255.0, 130/255.0}, {255/255.0, 240/255.0, 240/255.0}, {240/255.0, 230/255.0, 140/255.0}, {230/255.0, 230/255.0, 250/255.0}, {255/255.0, 240/255.0, 245/255.0}, {124/255.0, 252/255.0, 0/255.0}, {255/255.0, 250/255.0, 205/255.0}, {173/255.0, 216/255.0, 230/255.0}, {240/255.0, 128/255.0, 128/255.0}, {224/255.0, 255/255.0, 255/255.0}, {250/255.0, 250/255.0, 210/255.0}, {144/255.0, 238/255.0, 144/255.0}, {211/255.0, 211/255.0, 211/255.0}, {255/255.0, 182/255.0, 193/255.0}, {255/255.0, 160/255.0, 122/255.0}, {32/255.0, 178/255.0, 170/255.0}, {135/255.0, 206/255.0, 250/255.0}, {119/255.0, 136/255.0, 153/255.0}, {176/255.0, 196/255.0, 222/255.0}, {255/255.0, 255/255.0, 224/255.0}, {0/255.0, 255/255.0, 0/255.0}, {50/255.0, 205/255.0, 50/255.0}, {250/255.0, 240/255.0, 230/255.0}, {255/255.0, 0/255.0, 255/255.0}, {128/255.0, 0/255.0, 0/255.0}, {102/255.0, 205/255.0, 170/255.0}, {0/255.0, 0/255.0, 205/255.0}, {186/255.0, 85/255.0, 211/255.0}, {147/255.0, 112/255.0, 219/255.0}, {60/255.0, 179/255.0, 113/255.0}, {123/255.0, 104/255.0, 238/255.0}, {0/255.0, 250/255.0, 154/255.0}, {72/255.0, 209/255.0, 204/255.0}, {199/255.0, 21/255.0, 133/255.0}, {25/255.0, 25/255.0, 112/255.0}, {245/255.0, 255/255.0, 250/255.0}, {255/255.0, 228/255.0, 225/255.0}, {255/255.0, 228/255.0, 181/255.0}, {255/255.0, 222/255.0, 173/255.0}, {0/255.0, 0/255.0, 128/255.0}, {253/255.0, 245/255.0, 230/255.0}, {128/255.0, 128/255.0, 0/255.0}, {107/255.0, 142/255.0, 35/255.0}, {255/255.0, 165/255.0, 0/255.0}, {255/255.0, 69/255.0, 0/255.0}, {218/255.0, 112/255.0, 214/255.0}, {238/255.0, 232/255.0, 170/255.0}, {152/255.0, 251/255.0, 152/255.0}, {175/255.0, 238/255.0, 238/255.0}, {219/255.0, 112/255.0, 147/255.0}, {255/255.0, 239/255.0, 213/255.0}, {255/255.0, 239/255.0, 213/255.0}, {205/255.0, 133/255.0, 63/255.0}, {255/255.0, 192/255.0, 203/255.0}, {221/255.0, 160/255.0, 221/255.0}, {176/255.0, 224/255.0, 230/255.0}, {128/255.0, 0/255.0, 128/255.0}, {255/255.0, 0/255.0, 0/255.0}, {188/255.0, 143/255.0, 143/255.0}, {65/255.0, 105/255.0, 225/255.0}, {139/255.0, 69/255.0, 19/255.0}, {250/255.0, 128/255.0, 114/255.0}, {244/255.0, 164/255.0, 96/255.0}, {46/255.0, 139/255.0, 87/255.0}, {255/255.0, 245/255.0, 238/255.0}, {160/255.0, 82/255.0, 45/255.0}, {192/255.0, 192/255.0, 192/255.0}, {135/255.0, 206/255.0, 235/255.0}, {106/255.0, 90/255.0, 205/255.0}, {112/255.0, 128/255.0, 144/255.0}, {255/255.0, 250/255.0, 250/255.0}, {0/255.0, 255/255.0, 127/255.0}, {70/255.0, 130/255.0, 180/255.0}, {210/255.0, 180/255.0, 140/255.0}, {0/255.0, 128/255.0, 128/255.0}, {216/255.0, 191/255.0, 216/255.0}, {253/255.0, 99/255.0, 71/255.0}, {64/255.0, 224/255.0, 208/255.0}, {238/255.0, 130/255.0, 238/255.0}, {245/255.0, 222/255.0, 179/255.0}, {255/255.0, 255/255.0, 255/255.0}, {245/255.0, 245/255.0, 245/255.0}, {255/255.0, 255/255.0, 0/255.0}, {154/255.0, 205/255.0, 50/255.0} }; for (int i = 0; i < ncolors; i++) if (strcmp(color,username[i]) == 0) return userrgb[i]; for (int i = 0; i < NCOLORS; i++) if (strcmp(color,name[i]) == 0) return rgb[i]; return NULL; } /* ---------------------------------------------------------------------- search the list of element names for the string element return a pointer to the 3 floating point RGB values this list is used by AtomEye and is taken from its Mendeleyev.c file ------------------------------------------------------------------------- */ double *DumpImage::element2color(char *element) { - - static char *name[NELEMENTS] = { + static const char *name[NELEMENTS] = { "H", "He", "Li", "Be", "B", "C", "N", "O", "F", "Ne", "Na", "Mg", "Al", "Si", "P", "S", "Cl", "Ar", "K", "Ca", "Sc", "Ti", "V", "Cr", "Mn", "Fe", "Co", "Ni", "Cu", "Zn", "Ga", "Ge", "As", "Se", "Br", "Kr", "Rb", "Sr", "Y", "Zr", "Nb", "Mo", "Tc", "Ru", "Rh", "Pd", "Ag", "Cd", "In", "Sn", "Sb", "Te", "I", "Xe", "Cs", "Ba", "La", "Ce", "Pr", "Nd", "Pm", "Sm", "Eu", "Gd", "Tb", "Dy", "Ho", "Er", "Tm", "Yb", "Lu", "Hf", "Ta", "W", "Re", "Os", "Ir", "Pt", "Au", "Hg", "Tl", "Pb", "Bi", "Po", "At", "Rn", "Fr", "Ra", "Ac", "Th", "Pa", "U", "Np", "Pu", "Am", "Cm", "Bk", "Cf", "Es", "Fm", "Md", "No", "Lr", "Rf", "Db", "Sg", "Bh", "Hs", "Mt" }; static double rgb[NELEMENTS][3] = { {0.8, 0.8, 0.8}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.7, 0.7, 0.7}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.9, 0.4, 0}, {0.35, 0.35, 0.35}, {0.2, 0.2, 0.8}, {0.8, 0.2, 0.2}, {0.7, 0.85, 0.45}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6, 0.6, 0.6}, {0.6, 0.6, 0.7}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6901960784, 0.768627451, 0.8705882353}, {0.1, 0.7, 0.3}, {0.95, 0.9, 0.2}, {0.15, 0.5, 0.1}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.5, 0.5, 0.5}, {0.8, 0.8, 0.7}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0, 0.8, 0}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.5176470588, 0.5764705882, 0.6529411765}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.257254902, 0.2666666667, 0.271372549}, {0.95, 0.7900735294, 0.01385869565}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.9, 0, 1}, {0.6431372549, 0.6666666667, 0.6784313725}, {1, 1, 0.3}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.5, 0.08, 0.12}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.5, 0.1, 0.5}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.8, 0.8, 0}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {1, 0.8431372549, 0}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.9, 0.8, 0}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.8, 0.2, 0.2}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.1, 0.7, 0.3}, {0.1, 0.3, 0.7}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.9, 0.8, 0}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725} }; for (int i = 0; i < NELEMENTS; i++) if (strcmp(element,name[i]) == 0) return rgb[i]; return NULL; } /* ---------------------------------------------------------------------- search the list of element names for the string element return a pointer to the 3 floating point RGB values this list is used by AtomEye and is taken from its Mendeleyev.c file ------------------------------------------------------------------------- */ double DumpImage::element2diam(char *element) { - static char *name[NELEMENTS] = { + static const char *name[NELEMENTS] = { "H", "He", "Li", "Be", "B", "C", "N", "O", "F", "Ne", "Na", "Mg", "Al", "Si", "P", "S", "Cl", "Ar", "K", "Ca", "Sc", "Ti", "V", "Cr", "Mn", "Fe", "Co", "Ni", "Cu", "Zn", "Ga", "Ge", "As", "Se", "Br", "Kr", "Rb", "Sr", "Y", "Zr", "Nb", "Mo", "Tc", "Ru", "Rh", "Pd", "Ag", "Cd", "In", "Sn", "Sb", "Te", "I", "Xe", "Cs", "Ba", "La", "Ce", "Pr", "Nd", "Pm", "Sm", "Eu", "Gd", "Tb", "Dy", "Ho", "Er", "Tm", "Yb", "Lu", "Hf", "Ta", "W", "Re", "Os", "Ir", "Pt", "Au", "Hg", "Tl", "Pb", "Bi", "Po", "At", "Rn", "Fr", "Ra", "Ac", "Th", "Pa", "U", "Np", "Pu", "Am", "Cm", "Bk", "Cf", "Es", "Fm", "Md", "No", "Lr", "Rf", "Db", "Sg", "Bh", "Hs", "Mt" }; static double diameter[NELEMENTS] = { 0.35, 1.785, 1.45, 1.05, 0.85, 0.72, 0.65, 0.6, 0.5, 1.5662, 1.8, 1.5, 1.4255, 1.07, 1, 1, 1, 1.8597, 2.2, 1.8, 1.6, 1.4, 1.51995, 1.44225, 1.4, 1.43325, 1.35, 1.35, 1.278, 1.35, 1.3, 1.25, 1.15, 1.15, 1.15, 2.0223, 2.35, 2, 1.8, 1.55, 1.6504, 1.3872, 1.35, 1.3, 1.35, 1.4, 1.6, 1.55, 1.55, 1.45, 1.45, 1.4, 1.4, 2.192, 2.6, 2.15, 1.95, 1.85, 1.85, 1.85, 1.85, 1.85, 1.85, 1.8, 1.75, 1.75, 1.75, 1.75, 1.75, 1.75, 1.75, 1.55, 1.6529, 1.5826, 1.35, 1.3, 1.35, 1.35, 1.35, 1.5, 1.9, 1.8, 1.6, 1.9, 1.6, 1.0, 1.0, 2.15, 1.95, 1.8, 1.8, 1.75, 1.75, 1.75, 1.75, 1.0, 1.0, 1.6, 1.6, 1.0, 1.0, 1.0, 1.0, 1.0, 1.6, 1.0, 1.0, 1.0, 1.0 }; for (int i = 0; i < NELEMENTS; i++) if (strcmp(element,name[i]) == 0) return diameter[i]; return 0.0; } diff --git a/src/dump_image.h b/src/dump_image.h index fd72ea3d1..a46420211 100644 --- a/src/dump_image.h +++ b/src/dump_image.h @@ -1,295 +1,295 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ #ifdef DUMP_CLASS DumpStyle(image,DumpImage) #else #ifndef LMP_DUMP_IMAGE_H #define LMP_DUMP_IMAGE_H #include "math.h" #include "dump_custom.h" namespace LAMMPS_NS { class DumpImage : public DumpCustom { public: DumpImage(class LAMMPS *, int, char**); ~DumpImage(); int pack_comm(int, int *, double *, int, int *); void unpack_comm(int, int, double *); private: int filetype; int acolor,adiam; double adiamvalue; int atomflag,bondflag; int bcolor,bdiam; double bdiamvalue; int width,height; double theta,phi; char *thetastr,*phistr; int thetavar,phivar; int cflag; double cx,cy,cz; char *cxstr,*cystr,*czstr; int cxvar,cyvar,czvar; double up[3]; char *upxstr,*upystr,*upzstr; int upxvar,upyvar,upzvar; double zoom,persp; char *zoomstr,*perspstr; int zoomvar,perspvar; int boxflag,axesflag; double boxdiam,axeslen,axesdiam; double shiny; int ssao,seed; double ssaoint; int npixels,viewflag; double *depthBuffer,*surfaceBuffer; double *depthcopy,*surfacecopy; char *imageBuffer,*rgbcopy,*writeBuffer; double **bufcopy; int maxbufcopy; // constant view params double FOV; double ambientColor[3]; double keyLightTheta; double keyLightPhi; double keyLightColor[3]; double fillLightTheta; double fillLightPhi; double fillLightColor[3]; double backLightTheta; double backLightPhi; double backLightColor[3]; double specularHardness; double specularIntensity; double SSAORadius; int SSAOSamples; double SSAOJitter; // dynamic view params double xctr,yctr,zctr,zdist; double tanPerPixel; double camDir[3],camUp[3],camRight[4],camPos[3]; double keyLightDir[3],fillLightDir[3],backLightDir[3]; double keyHalfDir[3]; // dump_modify values int ncolors; char **username; double **userrgb; double *diamtype,*diamelement,*bdiamtype; double **colortype,**colorelement,**bcolortype; double *boxcolor; int background[3]; // color map int mstyle,mrange; // 2-letter style/range of color map int mlo,mhi; // bounds = NUMERIC or MINVALUE or MAXVALUE double mlovalue,mhivalue; // user bounds if NUMERIC double locurrent,hicurrent; // current bounds for this snapshot double mbinsize,mbinsizeinv; // bin size for sequential color map struct MapEntry { int single,lo,hi; // NUMERIC or MINVALUE or MAXVALUE double svalue,lvalue,hvalue; // actual value double *color; // RGB values }; MapEntry *mentry; int nentry; double interpolate[3]; class RanMars *random; void init_style(); int modify_param(int, char **); void write(); void box_center(); void view_params(); void box_bounds(); void color_minmax(); void create_image(); // rasterizing methods void draw_sphere(double *, double *, double); void draw_cylinder(double *, double *, double *, double, int); void draw_pixel(int, int, double, double *, double*); void compute_SSAO(); void write_JPG(); void write_PPM(); double *value2color(double); - double *color2rgb(char *); + double *color2rgb(const char *); double *element2color(char *); double element2diam(char *); // inlined functions inline double saturate(double v) { if (v < 0.0) return 0.0; else if (v > 1.0) return 1.0; else return v; } inline double distance(double* a, double* b) { return sqrt((a[0] - b[0]) * (a[0] - b[0]) + (a[1] - b[1]) * (a[1] - b[1]) + (a[2] - b[2]) * (a[2] - b[2])); } }; } #endif #endif /* ERROR/WARNING messages: E: Invalid dump image filename UNDOCUMENTED E: Cannot dump JPG file UNDOCUMENTED E: Illegal ... command Self-explanatory. Check the input script syntax and compare to the documentation for the command. You can use -echo screen as a command-line option when running LAMMPS to see the offending line. E: Dump image bond not allowed with no bond types UNDOCUMENTED E: Invalid dump image theta value UNDOCUMENTED E: Dump image persp option is not yet supported UNDOCUMENTED E: Dump image requires one snapshot per file UNDOCUMENTED E: Dump image cannot perform sorting UNDOCUMENTED E: Variable name for dump image theta does not exist UNDOCUMENTED E: Variable for dump image theta is invalid style UNDOCUMENTED E: Variable name for dump image phi does not exist UNDOCUMENTED E: Variable for dump image phi is invalid style UNDOCUMENTED E: Variable name for dump image center does not exist UNDOCUMENTED E: Variable for dump image center is invalid style UNDOCUMENTED E: Variable name for dump image zoom does not exist UNDOCUMENTED E: Variable for dump image zoom is invalid style UNDOCUMENTED E: Variable name for dump image persp does not exist UNDOCUMENTED E: Variable for dump image persp is invalid style UNDOCUMENTED E: Invalid dump image element name UNDOCUMENTED E: Invalid dump image zoom value UNDOCUMENTED E: Invalid dump image persp value UNDOCUMENTED E: Invalid dump image up vector UNDOCUMENTED E: Invalid dump image color range UNDOCUMENTED E: Invalid color in dump_modify command UNDOCUMENTED E: Illega dump_modify command UNDOCUMENTED E: Invalid color map in dump_modify command UNDOCUMENTED E: Dump modify bcolor not allowed with no bond types UNDOCUMENTED E: Dump modify bdiam not allowed with no bond types UNDOCUMENTED */ diff --git a/src/dump_local.cpp b/src/dump_local.cpp index c95f77e7c..f44781194 100644 --- a/src/dump_local.cpp +++ b/src/dump_local.cpp @@ -1,470 +1,470 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ #include "mpi.h" #include "string.h" #include "stdlib.h" #include "dump_local.h" #include "atom.h" #include "modify.h" #include "fix.h" #include "compute.h" #include "domain.h" #include "update.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; enum{INT,DOUBLE}; #define INVOKED_LOCAL 16 /* ---------------------------------------------------------------------- */ DumpLocal::DumpLocal(LAMMPS *lmp, int narg, char **arg) : Dump(lmp, narg, arg) { if (narg == 5) error->all(FLERR,"No dump local arguments specified"); clearstep = 1; nevery = atoi(arg[3]); size_one = nfield = narg-5; pack_choice = new FnPtrPack[nfield]; vtype = new int[nfield]; // computes & fixes which the dump accesses field2index = new int[nfield]; argindex = new int[nfield]; ncompute = 0; id_compute = NULL; compute = NULL; nfix = 0; id_fix = NULL; fix = NULL; // process attributes parse_fields(narg,arg); // setup format strings vformat = new char*[size_one]; format_default = new char[3*size_one+1]; format_default[0] = '\0'; for (int i = 0; i < size_one; i++) { if (vtype[i] == INT) format_default = strcat(format_default,"%d "); else format_default = strcat(format_default,"%g "); vformat[i] = NULL; } // setup column string int n = 0; for (int iarg = 5; iarg < narg; iarg++) n += strlen(arg[iarg]) + 2; columns = new char[n]; columns[0] = '\0'; for (int iarg = 5; iarg < narg; iarg++) { strcat(columns,arg[iarg]); strcat(columns," "); } // setup default label string - char *str = "ENTRIES"; + char *str = (char *) "ENTRIES"; n = strlen(str) + 1; label = new char[n]; strcpy(label,str); } /* ---------------------------------------------------------------------- */ DumpLocal::~DumpLocal() { delete [] pack_choice; delete [] vtype; delete [] field2index; delete [] argindex; for (int i = 0; i < ncompute; i++) delete [] id_compute[i]; memory->sfree(id_compute); delete [] compute; for (int i = 0; i < nfix; i++) delete [] id_fix[i]; memory->sfree(id_fix); delete [] fix; for (int i = 0; i < size_one; i++) delete [] vformat[i]; delete [] vformat; delete [] columns; delete [] label; } /* ---------------------------------------------------------------------- */ void DumpLocal::init_style() { if (sort_flag && sortcol == 0) error->all(FLERR,"Dump local cannot sort by atom ID"); delete [] format; char *str; if (format_user) str = format_user; else str = format_default; int n = strlen(str) + 1; format = new char[n]; strcpy(format,str); // tokenize the format string and add space at end of each format element char *ptr; for (int i = 0; i < size_one; i++) { if (i == 0) ptr = strtok(format," \0"); else ptr = strtok(NULL," \0"); delete [] vformat[i]; vformat[i] = new char[strlen(ptr) + 2]; strcpy(vformat[i],ptr); vformat[i] = strcat(vformat[i]," "); } // find current ptr for each compute,fix,variable // check that fix frequency is acceptable int icompute; for (int i = 0; i < ncompute; i++) { icompute = modify->find_compute(id_compute[i]); if (icompute < 0) error->all(FLERR,"Could not find dump local compute ID"); compute[i] = modify->compute[icompute]; } int ifix; for (int i = 0; i < nfix; i++) { ifix = modify->find_fix(id_fix[i]); if (ifix < 0) error->all(FLERR,"Could not find dump local fix ID"); fix[i] = modify->fix[ifix]; if (nevery % modify->fix[ifix]->local_freq) error->all(FLERR,"Dump local and fix not computed at compatible times"); } // open single file, one time only if (multifile == 0) openfile(); } /* ---------------------------------------------------------------------- */ int DumpLocal::modify_param(int narg, char **arg) { if (strcmp(arg[0],"label") == 0) { if (narg < 2) error->all(FLERR,"Illegal dump_modify command"); delete [] label; int n = strlen(arg[1]) + 1; label = new char[n]; strcpy(label,arg[1]); return 2; } return 0; } /* ---------------------------------------------------------------------- */ void DumpLocal::write_header(bigint ndump) { if (me == 0) { fprintf(fp,"ITEM: TIMESTEP\n"); fprintf(fp,BIGINT_FORMAT "\n",update->ntimestep); fprintf(fp,"ITEM: NUMBER OF %s\n",label); fprintf(fp,BIGINT_FORMAT "\n",ndump); fprintf(fp,"ITEM: %s %s\n",label,columns); } } /* ---------------------------------------------------------------------- */ int DumpLocal::count() { int i; // invoke Computes for local quantities if (ncompute) { for (i = 0; i < ncompute; i++) { if (!(compute[i]->invoked_flag & INVOKED_LOCAL)) { compute[i]->compute_local(); compute[i]->invoked_flag |= INVOKED_LOCAL; } } } // nmine = # of local values I contribute // must be consistent for all input fields nmine = -1; for (int i = 0; i < ncompute; i++) { if (nmine < 0) nmine = compute[i]->size_local_rows; else if (nmine != compute[i]->size_local_rows) error->one(FLERR,"Dump local count is not consistent across input fields"); } for (int i = 0; i < nfix; i++) { if (nmine < 0) nmine = fix[i]->size_local_rows; else if (nmine != fix[i]->size_local_rows) error->one(FLERR,"Dump local count is not consistent across input fields"); } return nmine; } /* ---------------------------------------------------------------------- */ void DumpLocal::pack(int *dummy) { for (int n = 0; n < size_one; n++) (this->*pack_choice[n])(n); } /* ---------------------------------------------------------------------- */ void DumpLocal::write_data(int n, double *mybuf) { int i,j; int m = 0; for (i = 0; i < n; i++) { for (j = 0; j < size_one; j++) { if (vtype[j] == INT) fprintf(fp,vformat[j],static_cast (mybuf[m])); else fprintf(fp,vformat[j],mybuf[m]); m++; } fprintf(fp,"\n"); } } /* ---------------------------------------------------------------------- */ void DumpLocal::parse_fields(int narg, char **arg) { int computefixflag = 0; // customize by adding to if statement int i; for (int iarg = 5; iarg < narg; iarg++) { i = iarg-5; if (strcmp(arg[iarg],"index") == 0) { pack_choice[i] = &DumpLocal::pack_index; vtype[i] = INT; // compute value = c_ID // if no trailing [], then arg is set to 0, else arg is int between [] } else if (strncmp(arg[iarg],"c_",2) == 0) { computefixflag = 1; pack_choice[i] = &DumpLocal::pack_compute; vtype[i] = DOUBLE; int n = strlen(arg[iarg]); char *suffix = new char[n]; strcpy(suffix,&arg[iarg][2]); char *ptr = strchr(suffix,'['); if (ptr) { if (suffix[strlen(suffix)-1] != ']') error->all(FLERR,"Invalid attribute in dump local command"); argindex[i] = atoi(ptr+1); *ptr = '\0'; } else argindex[i] = 0; n = modify->find_compute(suffix); if (n < 0) error->all(FLERR,"Could not find dump local compute ID"); if (modify->compute[n]->local_flag == 0) error->all(FLERR,"Dump local compute does not compute local info"); if (argindex[i] == 0 && modify->compute[n]->size_local_cols > 0) error->all(FLERR,"Dump local compute does not calculate local vector"); if (argindex[i] > 0 && modify->compute[n]->size_local_cols == 0) error->all(FLERR,"Dump local compute does not calculate local array"); if (argindex[i] > 0 && argindex[i] > modify->compute[n]->size_local_cols) error->all(FLERR,"Dump local compute vector is accessed out-of-range"); field2index[i] = add_compute(suffix); delete [] suffix; // fix value = f_ID // if no trailing [], then arg is set to 0, else arg is between [] } else if (strncmp(arg[iarg],"f_",2) == 0) { computefixflag = 1; pack_choice[i] = &DumpLocal::pack_fix; vtype[i] = DOUBLE; int n = strlen(arg[iarg]); char *suffix = new char[n]; strcpy(suffix,&arg[iarg][2]); char *ptr = strchr(suffix,'['); if (ptr) { if (suffix[strlen(suffix)-1] != ']') error->all(FLERR,"Invalid attribute in dump local command"); argindex[i] = atoi(ptr+1); *ptr = '\0'; } else argindex[i] = 0; n = modify->find_fix(suffix); if (n < 0) error->all(FLERR,"Could not find dump local fix ID"); if (modify->fix[n]->local_flag == 0) error->all(FLERR,"Dump local fix does not compute local info"); if (argindex[i] == 0 && modify->fix[n]->size_local_cols > 0) error->all(FLERR,"Dump local fix does not compute local vector"); if (argindex[i] > 0 && modify->fix[n]->size_local_cols == 0) error->all(FLERR,"Dump local fix does not compute local array"); if (argindex[i] > 0 && argindex[i] > modify->fix[n]->size_local_cols) error->all(FLERR,"Dump local fix vector is accessed out-of-range"); field2index[i] = add_fix(suffix); delete [] suffix; } else error->all(FLERR,"Invalid attribute in dump local command"); } if (computefixflag == 0) error->all(FLERR,"Dump local attributes contain no compute or fix"); } /* ---------------------------------------------------------------------- add Compute to list of Compute objects used by dump return index of where this Compute is in list if already in list, do not add, just return index, else add to list ------------------------------------------------------------------------- */ int DumpLocal::add_compute(char *id) { int icompute; for (icompute = 0; icompute < ncompute; icompute++) if (strcmp(id,id_compute[icompute]) == 0) break; if (icompute < ncompute) return icompute; id_compute = (char **) memory->srealloc(id_compute,(ncompute+1)*sizeof(char *),"dump:id_compute"); delete [] compute; compute = new Compute*[ncompute+1]; int n = strlen(id) + 1; id_compute[ncompute] = new char[n]; strcpy(id_compute[ncompute],id); ncompute++; return ncompute-1; } /* ---------------------------------------------------------------------- add Fix to list of Fix objects used by dump return index of where this Fix is in list if already in list, do not add, just return index, else add to list ------------------------------------------------------------------------- */ int DumpLocal::add_fix(char *id) { int ifix; for (ifix = 0; ifix < nfix; ifix++) if (strcmp(id,id_fix[ifix]) == 0) break; if (ifix < nfix) return ifix; id_fix = (char **) memory->srealloc(id_fix,(nfix+1)*sizeof(char *),"dump:id_fix"); delete [] fix; fix = new Fix*[nfix+1]; int n = strlen(id) + 1; id_fix[nfix] = new char[n]; strcpy(id_fix[nfix],id); nfix++; return nfix-1; } /* ---------------------------------------------------------------------- extraction of Compute, Fix results ------------------------------------------------------------------------- */ void DumpLocal::pack_compute(int n) { double *vector = compute[field2index[n]]->vector_local; double **array = compute[field2index[n]]->array_local; int ncount = compute[field2index[n]]->size_local_rows; int index = argindex[n]; if (index == 0) { for (int i = 0; i < ncount; i++) { buf[n] = vector[i]; n += size_one; } } else { index--; for (int i = 0; i < ncount; i++) { buf[n] = array[i][index]; n += size_one; } } } /* ---------------------------------------------------------------------- */ void DumpLocal::pack_fix(int n) { double *vector = fix[field2index[n]]->vector_local; double **array = fix[field2index[n]]->array_local; int index = argindex[n]; if (index == 0) { for (int i = 0; i < nmine; i++) { buf[n] = vector[i]; n += size_one; } } else { index--; for (int i = 0; i < nmine; i++) { buf[n] = array[i][index]; n += size_one; } } } /* ---------------------------------------------------------------------- one method for every attribute dump local can output the local value is packed into buf starting at n with stride size_one customize a new attribute by adding a method ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */ void DumpLocal::pack_index(int n) { int index; MPI_Scan(&nmine,&index,1,MPI_INT,MPI_SUM,world); index -= nmine; for (int i = 0; i < nmine; i++) { buf[n] = ++index; n += size_one; } } diff --git a/src/error.cpp b/src/error.cpp index 9465a6f97..350f8fe1f 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -1,154 +1,154 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ #include "mpi.h" #include "stdlib.h" #include "error.h" #include "universe.h" #include "memory.h" #include "output.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ Error::Error(LAMMPS *lmp) : Pointers(lmp) {} /* ---------------------------------------------------------------------- called by all procs in universe close all output, screen, and log files in world and universe no abort, so insure all procs in universe call, else will hang ------------------------------------------------------------------------- */ void Error::universe_all(const char *file, int line, const char *str) { MPI_Barrier(universe->uworld); if (universe->me == 0) { if (universe->uscreen) fprintf(universe->uscreen, "ERROR: %s (%s:%d)\n",str,file,line); if (universe->ulogfile) fprintf(universe->ulogfile, "ERROR: %s (%s:%d)\n",str,file,line); } if (output) delete output; if (universe->nworlds > 1) { if (screen && screen != stdout) fclose(screen); if (logfile) fclose(logfile); } if (universe->ulogfile) fclose(universe->ulogfile); MPI_Finalize(); exit(1); } /* ---------------------------------------------------------------------- called by one proc in universe forces abort of entire universe if any proc in universe calls ------------------------------------------------------------------------- */ void Error::universe_one(const char *file, int line, const char *str) { if (universe->uscreen) fprintf(universe->uscreen,"ERROR on proc %d: %s (%s:%d)\n", universe->me,str,file,line); MPI_Abort(universe->uworld,1); } /* ---------------------------------------------------------------------- called by all procs in one world close all output, screen, and log files in world insure all procs in world call, else will hang force MPI_Abort if running in multi-partition mode ------------------------------------------------------------------------- */ void Error::all(const char *file, int line, const char *str) { MPI_Barrier(world); int me; MPI_Comm_rank(world,&me); if (me == 0) { if (screen) fprintf(screen,"ERROR: %s (%s:%d)\n",str,file,line); if (logfile) fprintf(logfile,"ERROR: %s (%s:%d)\n",str,file,line); } if (output) delete output; if (screen && screen != stdout) fclose(screen); if (logfile) fclose(logfile); if (universe->nworlds > 1) MPI_Abort(universe->uworld,1); MPI_Finalize(); exit(1); } /* ---------------------------------------------------------------------- called by one proc in world write to world screen only if non-NULL on this proc always write to universe screen forces abort of entire world (and universe) if any proc in world calls ------------------------------------------------------------------------- */ void Error::one(const char *file, int line, const char *str) { int me; MPI_Comm_rank(world,&me); if (screen) fprintf(screen,"ERROR on proc %d: %s (%s:%d)\n", me,str,file,line); if (universe->nworlds > 1) fprintf(universe->uscreen,"ERROR on proc %d: %s (%s:%d)\n", universe->me,str,file,line); MPI_Abort(world,1); } /* ---------------------------------------------------------------------- called by one proc in world only write to screen if non-NULL on this proc since could be file ------------------------------------------------------------------------- */ void Error::warning(const char *file, int line, const char *str, int logflag) { if (screen) fprintf(screen,"WARNING: %s (%s:%d)\n",str,file,line); if (logflag && logfile) fprintf(logfile,"WARNING: %s (%s:%d)\n", str,file,line); } /* ---------------------------------------------------------------------- called by one proc in world, typically proc 0 write message to screen and logfile (if logflag is set) ------------------------------------------------------------------------- */ -void Error::message(const char *file, int line, char *str, int logflag) +void Error::message(const char *file, int line, const char *str, int logflag) { if (screen) fprintf(screen,"%s (%s:%d)\n",str,file,line); if (logflag && logfile) fprintf(logfile,"%s (%s:%d)\n",str,file,line); } /* ---------------------------------------------------------------------- called by all procs in one world close all output, screen, and log files in world no abort, so insure all procs in world call, else will hang ------------------------------------------------------------------------- */ void Error::done() { MPI_Barrier(world); if (output) delete output; if (screen && screen != stdout) fclose(screen); if (logfile) fclose(logfile); MPI_Finalize(); exit(1); } diff --git a/src/error.h b/src/error.h index 28595ac87..df25f7c41 100644 --- a/src/error.h +++ b/src/error.h @@ -1,40 +1,40 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ #ifndef LMP_ERROR_H #define LMP_ERROR_H #include "pointers.h" namespace LAMMPS_NS { class Error : protected Pointers { public: Error(class LAMMPS *); void universe_all(const char *, int, const char *); void universe_one(const char *, int, const char *); void all(const char *, int, const char *); void one(const char *, int, const char *); void warning(const char *, int, const char *, int = 1); - void message(const char *, int, char *, int = 1); + void message(const char *, int, const char *, int = 1); void done(); }; } #endif /* ERROR/WARNING messages: */ diff --git a/src/input.cpp b/src/input.cpp index b0358004d..f04717e52 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -1,1387 +1,1387 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ #include "mpi.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "ctype.h" #include "unistd.h" #include "sys/stat.h" #include "input.h" #include "style_command.h" #include "universe.h" #include "atom.h" #include "atom_vec.h" #include "comm.h" #include "group.h" #include "domain.h" #include "output.h" #include "thermo.h" #include "force.h" #include "pair.h" #include "min.h" #include "modify.h" #include "compute.h" #include "bond.h" #include "angle.h" #include "dihedral.h" #include "improper.h" #include "kspace.h" #include "update.h" #include "neighbor.h" #include "special.h" #include "variable.h" #include "accelerator_cuda.h" #include "error.h" #include "memory.h" #ifdef _OPENMP #include "omp.h" #endif using namespace LAMMPS_NS; #define MAXLINE 2048 #define DELTA 4 /* ---------------------------------------------------------------------- */ Input::Input(LAMMPS *lmp, int argc, char **argv) : Pointers(lmp) { MPI_Comm_rank(world,&me); line = new char[MAXLINE]; copy = new char[MAXLINE]; work = new char[MAXLINE]; narg = maxarg = 0; arg = NULL; echo_screen = 0; echo_log = 1; label_active = 0; labelstr = NULL; jump_skip = 0; if (me == 0) { nfile = maxfile = 1; infiles = (FILE **) memory->smalloc(sizeof(FILE *),"input:infiles"); infiles[0] = infile; } else infiles = NULL; variable = new Variable(lmp); // process command-line args // check for args "-var" and "-echo" // caller has already checked that sufficient arguments exist int iarg = 0; while (iarg < argc) { if (strcmp(argv[iarg],"-var") == 0 || strcmp(argv[iarg],"-v") == 0) { int jarg = iarg+3; while (jarg < argc && argv[jarg][0] != '-') jarg++; variable->set(argv[iarg+1],jarg-iarg-2,&argv[iarg+2]); iarg = jarg; } else if (strcmp(argv[iarg],"-echo") == 0 || strcmp(argv[iarg],"-e") == 0) { narg = 1; char **tmp = arg; // trick echo() into using argv instead of arg arg = &argv[iarg+1]; echo(); arg = tmp; iarg += 2; } else iarg++; } } /* ---------------------------------------------------------------------- */ Input::~Input() { // don't free command and arg strings // they just point to other allocated memory delete variable; delete [] line; delete [] copy; delete [] work; if (labelstr) delete [] labelstr; memory->sfree(arg); memory->sfree(infiles); } /* ---------------------------------------------------------------------- process all input from infile infile = stdin or file if command-line arg "-in" was used ------------------------------------------------------------------------- */ void Input::file() { int m,n; while (1) { // read a line from input script // if line ends in continuation char '&', concatenate next line(s) // n = length of line including str terminator, 0 if end of file // m = position of last printable char in line or -1 if blank line if (me == 0) { m = 0; while (1) { if (fgets(&line[m],MAXLINE-m,infile) == NULL) n = 0; else n = strlen(line) + 1; if (n == 0) break; m = n-2; while (m >= 0 && isspace(line[m])) m--; if (m < 0 || line[m] != '&') break; } } // bcast the line // if n = 0, end-of-file // error if label_active is set, since label wasn't encountered // if original input file, code is done // else go back to previous input file MPI_Bcast(&n,1,MPI_INT,0,world); if (n == 0) { if (label_active) error->all(FLERR,"Label wasn't found in input script"); if (me == 0) { if (infile != stdin) fclose(infile); nfile--; } MPI_Bcast(&nfile,1,MPI_INT,0,world); if (nfile == 0) break; if (me == 0) infile = infiles[nfile-1]; continue; } MPI_Bcast(line,n,MPI_CHAR,0,world); // if n = MAXLINE, line is too long if (n == MAXLINE) { char str[MAXLINE+32]; sprintf(str,"Input line too long: %s",line); error->all(FLERR,str); } // echo the command unless scanning for label if (me == 0 && label_active == 0) { if (echo_screen && screen) fprintf(screen,"%s",line); if (echo_log && logfile) fprintf(logfile,"%s",line); } // parse the line // if no command, skip to next line in input script parse(); if (command == NULL) continue; // if scanning for label, skip command unless it's a label command if (label_active && strcmp(command,"label") != 0) continue; // execute the command if (execute_command()) { char str[MAXLINE]; sprintf(str,"Unknown command: %s",line); error->all(FLERR,str); } } } /* ---------------------------------------------------------------------- process all input from filename ------------------------------------------------------------------------- */ void Input::file(const char *filename) { // error if another nested file still open // if single open file is not stdin, close it // open new filename and set infile, infiles[0] if (me == 0) { if (nfile > 1) error->one(FLERR,"Another input script is already being processed"); if (infile != stdin) fclose(infile); infile = fopen(filename,"r"); if (infile == NULL) { char str[128]; sprintf(str,"Cannot open input script %s",filename); error->one(FLERR,str); } infiles[0] = infile; } else infile = NULL; file(); } /* ---------------------------------------------------------------------- parse the command in single and execute it return command name to caller ------------------------------------------------------------------------- */ char *Input::one(const char *single) { strcpy(line,single); // echo the command unless scanning for label if (me == 0 && label_active == 0) { if (echo_screen && screen) fprintf(screen,"%s\n",line); if (echo_log && logfile) fprintf(logfile,"%s\n",line); } // parse the line // if no command, just return NULL parse(); if (command == NULL) return NULL; // if scanning for label, skip command unless it's a label command if (label_active && strcmp(command,"label") != 0) return NULL; // execute the command and return its name if (execute_command()) { char str[MAXLINE]; sprintf(str,"Unknown command: %s",line); error->all(FLERR,str); } return command; } /* ---------------------------------------------------------------------- parse copy of command line strip comment = all chars from # on replace all $ via variable substitution command = first word narg = # of args arg[] = individual args treat text between single/double quotes as one arg ------------------------------------------------------------------------- */ void Input::parse() { // make a copy to work on strcpy(copy,line); // strip any # comment by resetting string terminator // do not strip # inside single/double quotes char quote = '\0'; char *ptr = copy; while (*ptr) { if (*ptr == '#' && !quote) { *ptr = '\0'; break; } if (*ptr == quote) quote = '\0'; else if (*ptr == '"' || *ptr == '\'') quote = *ptr; ptr++; } // perform $ variable substitution (print changes) // except if searching for a label since earlier variable may not be defined if (!label_active) substitute(copy,1); // command = 1st arg command = strtok(copy," \t\n\r\f"); if (command == NULL) return; // point arg[] at each subsequent arg // treat text between single/double quotes as one arg // insert string terminators in copy to delimit args quote = '\0'; int iarg,argstart; narg = 0; while (1) { if (narg == maxarg) { maxarg += DELTA; arg = (char **) memory->srealloc(arg,maxarg*sizeof(char *),"input:arg"); } arg[narg] = strtok(NULL," \t\n\r\f"); if (!arg[narg]) break; if (!quote && (arg[narg][0] == '"' || arg[narg][0] == '\'')) { quote = arg[narg][0]; argstart = narg; arg[narg] = &arg[narg][1]; } if (quote && arg[narg][strlen(arg[narg])-1] == quote) { for (iarg = argstart; iarg < narg; iarg++) arg[iarg][strlen(arg[iarg])] = ' '; arg[narg][strlen(arg[narg])-1] = '\0'; narg = argstart; quote = '\0'; } narg++; } if (quote) error->all(FLERR,"Unbalanced quotes in input line"); } /* ---------------------------------------------------------------------- substitute for $ variables in str and return it str assumed to be long enough to hold expanded version print updated string if flag is set and not searching for label ------------------------------------------------------------------------- */ void Input::substitute(char *str, int flag) { // use work[] as scratch space to expand str, then copy back to str // do not replace $ inside single/double quotes // var = pts at variable name, ended by NULL // if $ is followed by '{', trailing '}' becomes NULL // else $x becomes x followed by NULL // beyond = pts at text following variable char *var,*value,*beyond; char quote = '\0'; char *ptr = str; while (*ptr) { if (*ptr == '$' && !quote) { if (*(ptr+1) == '{') { var = ptr+2; int i = 0; while (var[i] != '\0' && var[i] != '}') i++; if (var[i] == '\0') error->one(FLERR,"Invalid variable name"); var[i] = '\0'; beyond = ptr + strlen(var) + 3; } else { var = ptr; var[0] = var[1]; var[1] = '\0'; beyond = ptr + strlen(var) + 1; } value = variable->retrieve(var); if (value == NULL) error->one(FLERR,"Substitution for illegal variable"); *ptr = '\0'; strcpy(work,str); if (strlen(work)+strlen(value) >= MAXLINE) error->one(FLERR,"Input line too long after variable substitution"); strcat(work,value); if (strlen(work)+strlen(beyond) >= MAXLINE) error->one(FLERR,"Input line too long after variable substitution"); strcat(work,beyond); strcpy(str,work); ptr += strlen(value); if (flag && me == 0 && label_active == 0) { if (echo_screen && screen) fprintf(screen,"%s",str); if (echo_log && logfile) fprintf(logfile,"%s",str); } continue; } if (*ptr == quote) quote = '\0'; else if (*ptr == '"' || *ptr == '\'') quote = *ptr; ptr++; } } /* ---------------------------------------------------------------------- process a single parsed command return 0 if successful, -1 if did not recognize command ------------------------------------------------------------------------- */ int Input::execute_command() { int flag = 1; if (!strcmp(command,"clear")) clear(); else if (!strcmp(command,"echo")) echo(); else if (!strcmp(command,"if")) ifthenelse(); else if (!strcmp(command,"include")) include(); else if (!strcmp(command,"jump")) jump(); else if (!strcmp(command,"label")) label(); else if (!strcmp(command,"log")) log(); else if (!strcmp(command,"next")) next_command(); else if (!strcmp(command,"partition")) partition(); else if (!strcmp(command,"print")) print(); else if (!strcmp(command,"shell")) shell(); else if (!strcmp(command,"variable")) variable_command(); else if (!strcmp(command,"angle_coeff")) angle_coeff(); else if (!strcmp(command,"angle_style")) angle_style(); else if (!strcmp(command,"atom_modify")) atom_modify(); else if (!strcmp(command,"atom_style")) atom_style(); else if (!strcmp(command,"bond_coeff")) bond_coeff(); else if (!strcmp(command,"bond_style")) bond_style(); else if (!strcmp(command,"boundary")) boundary(); else if (!strcmp(command,"communicate")) communicate(); else if (!strcmp(command,"compute")) compute(); else if (!strcmp(command,"compute_modify")) compute_modify(); else if (!strcmp(command,"dielectric")) dielectric(); else if (!strcmp(command,"dihedral_coeff")) dihedral_coeff(); else if (!strcmp(command,"dihedral_style")) dihedral_style(); else if (!strcmp(command,"dimension")) dimension(); else if (!strcmp(command,"dump")) dump(); else if (!strcmp(command,"dump_modify")) dump_modify(); else if (!strcmp(command,"fix")) fix(); else if (!strcmp(command,"fix_modify")) fix_modify(); else if (!strcmp(command,"group")) group_command(); else if (!strcmp(command,"improper_coeff")) improper_coeff(); else if (!strcmp(command,"improper_style")) improper_style(); else if (!strcmp(command,"kspace_modify")) kspace_modify(); else if (!strcmp(command,"kspace_style")) kspace_style(); else if (!strcmp(command,"lattice")) lattice(); else if (!strcmp(command,"mass")) mass(); else if (!strcmp(command,"min_modify")) min_modify(); else if (!strcmp(command,"min_style")) min_style(); else if (!strcmp(command,"neigh_modify")) neigh_modify(); else if (!strcmp(command,"neighbor")) neighbor_command(); else if (!strcmp(command,"newton")) newton(); else if (!strcmp(command,"package")) package(); else if (!strcmp(command,"pair_coeff")) pair_coeff(); else if (!strcmp(command,"pair_modify")) pair_modify(); else if (!strcmp(command,"pair_style")) pair_style(); else if (!strcmp(command,"pair_write")) pair_write(); else if (!strcmp(command,"processors")) processors(); else if (!strcmp(command,"region")) region(); else if (!strcmp(command,"reset_timestep")) reset_timestep(); else if (!strcmp(command,"restart")) restart(); else if (!strcmp(command,"run_style")) run_style(); else if (!strcmp(command,"special_bonds")) special_bonds(); else if (!strcmp(command,"suffix")) suffix(); else if (!strcmp(command,"thermo")) thermo(); else if (!strcmp(command,"thermo_modify")) thermo_modify(); else if (!strcmp(command,"thermo_style")) thermo_style(); else if (!strcmp(command,"timestep")) timestep(); else if (!strcmp(command,"uncompute")) uncompute(); else if (!strcmp(command,"undump")) undump(); else if (!strcmp(command,"unfix")) unfix(); else if (!strcmp(command,"units")) units(); else flag = 0; // return if command was listed above if (flag) return 0; // check if command is added via style.h if (0) return 0; // dummy line to enable else-if macro expansion #define COMMAND_CLASS #define CommandStyle(key,Class) \ else if (strcmp(command,#key) == 0) { \ Class key(lmp); \ key.command(narg,arg); \ return 0; \ } #include "style_command.h" #undef COMMAND_CLASS // unrecognized command return -1; } /* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */ void Input::clear() { if (narg > 0) error->all(FLERR,"Illegal clear command"); lmp->destroy(); lmp->create(); lmp->post_create(); } /* ---------------------------------------------------------------------- */ void Input::echo() { if (narg != 1) error->all(FLERR,"Illegal echo command"); if (strcmp(arg[0],"none") == 0) { echo_screen = 0; echo_log = 0; } else if (strcmp(arg[0],"screen") == 0) { echo_screen = 1; echo_log = 0; } else if (strcmp(arg[0],"log") == 0) { echo_screen = 0; echo_log = 1; } else if (strcmp(arg[0],"both") == 0) { echo_screen = 1; echo_log = 1; } else error->all(FLERR,"Illegal echo command"); } /* ---------------------------------------------------------------------- */ void Input::ifthenelse() { if (narg < 3) error->all(FLERR,"Illegal if command"); // substitute for variables in Boolean expression for "if" // in case expression was enclosed in quotes // must substitute on copy of arg else will step on subsequent args char *scopy = new char[MAXLINE]; strcpy(scopy,arg[0]); substitute(scopy,0); // evaluate Boolean expression for "if" double btest = variable->evaluate_boolean(scopy); // bound "then" commands if (strcmp(arg[1],"then") != 0) error->all(FLERR,"Illegal if command"); int first = 2; int iarg = first; while (iarg < narg && (strcmp(arg[iarg],"elif") != 0 && strcmp(arg[iarg],"else") != 0)) iarg++; int last = iarg-1; // execute "then" commands // make copies of all arg string commands // required because re-parsing a command via one() will wipe out args if (btest != 0.0) { int ncommands = last-first + 1; if (ncommands <= 0) error->all(FLERR,"Illegal if command"); char **commands = new char*[ncommands]; ncommands = 0; for (int i = first; i <= last; i++) { int n = strlen(arg[i]) + 1; if (n == 1) error->all(FLERR,"Illegal if command"); commands[ncommands] = new char[n]; strcpy(commands[ncommands],arg[i]); ncommands++; } for (int i = 0; i < ncommands; i++) one(commands[i]); for (int i = 0; i < ncommands; i++) delete [] commands[i]; delete [] commands; delete [] scopy; return; } // done if no "elif" or "else" if (iarg == narg) { delete [] scopy; return; } // check "elif" or "else" until find commands to execute // substitute for variables and evaluate Boolean expression for "elif" // must substitute on copy of arg else will step on subsequent args // bound and execute "elif" or "else" commands while (1) { if (iarg+2 > narg) error->all(FLERR,"Illegal if command"); if (strcmp(arg[iarg],"elif") == 0) { strcpy(scopy,arg[iarg+1]); substitute(scopy,0); btest = variable->evaluate_boolean(scopy); first = iarg+2; } else { btest = 1.0; first = iarg+1; } iarg = first; while (iarg < narg && (strcmp(arg[iarg],"elif") != 0 && strcmp(arg[iarg],"else") != 0)) iarg++; last = iarg-1; if (btest == 0.0) continue; int ncommands = last-first + 1; if (ncommands <= 0) error->all(FLERR,"Illegal if command"); char **commands = new char*[ncommands]; ncommands = 0; for (int i = first; i <= last; i++) { int n = strlen(arg[i]) + 1; if (n == 1) error->all(FLERR,"Illegal if command"); commands[ncommands] = new char[n]; strcpy(commands[ncommands],arg[i]); ncommands++; } // execute the list of commands for (int i = 0; i < ncommands; i++) one(commands[i]); // clean up for (int i = 0; i < ncommands; i++) delete [] commands[i]; delete [] commands; delete [] scopy; return; } } /* ---------------------------------------------------------------------- */ void Input::include() { if (narg != 1) error->all(FLERR,"Illegal include command"); if (me == 0) { if (nfile == maxfile) { maxfile++; infiles = (FILE **) memory->srealloc(infiles,maxfile*sizeof(FILE *),"input:infiles"); } infile = fopen(arg[0],"r"); if (infile == NULL) { char str[128]; sprintf(str,"Cannot open input script %s",arg[0]); error->one(FLERR,str); } infiles[nfile++] = infile; } } /* ---------------------------------------------------------------------- */ void Input::jump() { if (narg < 1 || narg > 2) error->all(FLERR,"Illegal jump command"); if (jump_skip) { jump_skip = 0; return; } if (me == 0) { if (strcmp(arg[0],"SELF") == 0) rewind(infile); else { if (infile != stdin) fclose(infile); infile = fopen(arg[0],"r"); if (infile == NULL) { char str[128]; sprintf(str,"Cannot open input script %s",arg[0]); error->one(FLERR,str); } infiles[nfile-1] = infile; } } if (narg == 2) { label_active = 1; if (labelstr) delete [] labelstr; int n = strlen(arg[1]) + 1; labelstr = new char[n]; strcpy(labelstr,arg[1]); } } /* ---------------------------------------------------------------------- */ void Input::label() { if (narg != 1) error->all(FLERR,"Illegal label command"); if (label_active && strcmp(labelstr,arg[0]) == 0) label_active = 0; } /* ---------------------------------------------------------------------- */ void Input::log() { if (narg != 1) error->all(FLERR,"Illegal log command"); if (me == 0) { if (logfile) fclose(logfile); if (strcmp(arg[0],"none") == 0) logfile = NULL; else { logfile = fopen(arg[0],"w"); if (logfile == NULL) { char str[128]; sprintf(str,"Cannot open logfile %s",arg[0]); error->one(FLERR,str); } } if (universe->nworlds == 1) universe->ulogfile = logfile; } } /* ---------------------------------------------------------------------- */ void Input::next_command() { if (variable->next(narg,arg)) jump_skip = 1; } /* ---------------------------------------------------------------------- */ void Input::partition() { if (narg < 3) error->all(FLERR,"Illegal partition command"); int yesflag; if (strcmp(arg[0],"yes") == 0) yesflag = 1; else if (strcmp(arg[0],"no") == 0) yesflag = 0; else error->all(FLERR,"Illegal partition command"); int ilo,ihi; force->bounds(arg[1],universe->nworlds,ilo,ihi); // copy original line to copy, since will use strtok() on it // ptr = start of 4th word strcpy(copy,line); copy[strlen(copy)-1] = '\0'; char *ptr = strtok(copy," \t\n\r\f"); ptr = strtok(NULL," \t\n\r\f"); ptr = strtok(NULL," \t\n\r\f"); ptr += strlen(ptr) + 1; ptr += strspn(ptr," \t\n\r\f"); // execute the remaining command line on requested partitions if (yesflag) { if (universe->iworld+1 >= ilo && universe->iworld+1 <= ihi) one(ptr); } else { if (universe->iworld+1 < ilo || universe->iworld+1 > ihi) one(ptr); } } /* ---------------------------------------------------------------------- */ void Input::print() { if (narg != 1) error->all(FLERR,"Illegal print command"); // substitute for $ variables (no printing) and print arg substitute(arg[0],0); if (me == 0) { if (screen) fprintf(screen,"%s\n",arg[0]); if (logfile) fprintf(logfile,"%s\n",arg[0]); } } /* ---------------------------------------------------------------------- */ void Input::shell() { if (narg < 1) error->all(FLERR,"Illegal shell command"); if (strcmp(arg[0],"cd") == 0) { if (narg != 2) error->all(FLERR,"Illegal shell command"); chdir(arg[1]); } else if (strcmp(arg[0],"mkdir") == 0) { if (narg < 2) error->all(FLERR,"Illegal shell command"); #if !defined(WINDOWS) && !defined(__MINGW32_VERSION) if (me == 0) for (int i = 1; i < narg; i++) mkdir(arg[i], S_IRWXU | S_IRGRP | S_IXGRP); #endif } else if (strcmp(arg[0],"mv") == 0) { if (narg != 3) error->all(FLERR,"Illegal shell command"); if (me == 0) rename(arg[1],arg[2]); } else if (strcmp(arg[0],"rm") == 0) { if (narg < 2) error->all(FLERR,"Illegal shell command"); if (me == 0) for (int i = 1; i < narg; i++) unlink(arg[i]); } else if (strcmp(arg[0],"rmdir") == 0) { if (narg < 2) error->all(FLERR,"Illegal shell command"); if (me == 0) for (int i = 1; i < narg; i++) rmdir(arg[i]); // use work to concat args back into one string separated by spaces // invoke string in shell via system() } else { strcpy(work,arg[0]); for (int i = 1; i < narg; i++) { strcat(work," "); strcat(work,arg[i]); } if (me == 0) system(work); } } /* ---------------------------------------------------------------------- */ void Input::variable_command() { variable->set(narg,arg); } /* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- one function for each LAMMPS-specific input script command ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */ void Input::angle_coeff() { if (domain->box_exist == 0) error->all(FLERR,"Angle_coeff command before simulation box is defined"); if (force->angle == NULL) error->all(FLERR,"Angle_coeff command before angle_style is defined"); if (atom->avec->angles_allow == 0) error->all(FLERR,"Angle_coeff command when no angles allowed"); force->angle->coeff(narg,arg); } /* ---------------------------------------------------------------------- */ void Input::angle_style() { if (narg < 1) error->all(FLERR,"Illegal angle_style command"); if (atom->avec->angles_allow == 0) error->all(FLERR,"Angle_style command when no angles allowed"); force->create_angle(arg[0],lmp->suffix); if (force->angle) force->angle->settings(narg-1,&arg[1]); } /* ---------------------------------------------------------------------- */ void Input::atom_modify() { atom->modify_params(narg,arg); } /* ---------------------------------------------------------------------- */ void Input::atom_style() { if (narg < 1) error->all(FLERR,"Illegal atom_style command"); if (domain->box_exist) error->all(FLERR,"Atom_style command after simulation box is defined"); atom->create_avec(arg[0],narg-1,&arg[1],lmp->suffix); } /* ---------------------------------------------------------------------- */ void Input::bond_coeff() { if (domain->box_exist == 0) error->all(FLERR,"Bond_coeff command before simulation box is defined"); if (force->bond == NULL) error->all(FLERR,"Bond_coeff command before bond_style is defined"); if (atom->avec->bonds_allow == 0) error->all(FLERR,"Bond_coeff command when no bonds allowed"); force->bond->coeff(narg,arg); } /* ---------------------------------------------------------------------- */ void Input::bond_style() { if (narg < 1) error->all(FLERR,"Illegal bond_style command"); if (atom->avec->bonds_allow == 0) error->all(FLERR,"Bond_style command when no bonds allowed"); force->create_bond(arg[0],lmp->suffix); if (force->bond) force->bond->settings(narg-1,&arg[1]); } /* ---------------------------------------------------------------------- */ void Input::boundary() { if (domain->box_exist) error->all(FLERR,"Boundary command after simulation box is defined"); domain->set_boundary(narg,arg); } /* ---------------------------------------------------------------------- */ void Input::communicate() { comm->set(narg,arg); } /* ---------------------------------------------------------------------- */ void Input::compute() { modify->add_compute(narg,arg,lmp->suffix); } /* ---------------------------------------------------------------------- */ void Input::compute_modify() { modify->modify_compute(narg,arg); } /* ---------------------------------------------------------------------- */ void Input::dielectric() { if (narg != 1) error->all(FLERR,"Illegal dielectric command"); force->dielectric = atof(arg[0]); } /* ---------------------------------------------------------------------- */ void Input::dihedral_coeff() { if (domain->box_exist == 0) error->all(FLERR,"Dihedral_coeff command before simulation box is defined"); if (force->dihedral == NULL) error->all(FLERR,"Dihedral_coeff command before dihedral_style is defined"); if (atom->avec->dihedrals_allow == 0) error->all(FLERR,"Dihedral_coeff command when no dihedrals allowed"); force->dihedral->coeff(narg,arg); } /* ---------------------------------------------------------------------- */ void Input::dihedral_style() { if (narg < 1) error->all(FLERR,"Illegal dihedral_style command"); if (atom->avec->dihedrals_allow == 0) error->all(FLERR,"Dihedral_style command when no dihedrals allowed"); force->create_dihedral(arg[0],lmp->suffix); if (force->dihedral) force->dihedral->settings(narg-1,&arg[1]); } /* ---------------------------------------------------------------------- */ void Input::dimension() { if (narg != 1) error->all(FLERR,"Illegal dimension command"); if (domain->box_exist) error->all(FLERR,"Dimension command after simulation box is defined"); domain->dimension = atoi(arg[0]); if (domain->dimension != 2 && domain->dimension != 3) error->all(FLERR,"Illegal dimension command"); // must reset default extra_dof of all computes // since some were created before dimension command is encountered for (int i = 0; i < modify->ncompute; i++) modify->compute[i]->reset_extra_dof(); } /* ---------------------------------------------------------------------- */ void Input::dump() { output->add_dump(narg,arg); } /* ---------------------------------------------------------------------- */ void Input::dump_modify() { output->modify_dump(narg,arg); } /* ---------------------------------------------------------------------- */ void Input::fix() { modify->add_fix(narg,arg,lmp->suffix); } /* ---------------------------------------------------------------------- */ void Input::fix_modify() { modify->modify_fix(narg,arg); } /* ---------------------------------------------------------------------- */ void Input::group_command() { group->assign(narg,arg); } /* ---------------------------------------------------------------------- */ void Input::improper_coeff() { if (domain->box_exist == 0) error->all(FLERR,"Improper_coeff command before simulation box is defined"); if (force->improper == NULL) error->all(FLERR,"Improper_coeff command before improper_style is defined"); if (atom->avec->impropers_allow == 0) error->all(FLERR,"Improper_coeff command when no impropers allowed"); force->improper->coeff(narg,arg); } /* ---------------------------------------------------------------------- */ void Input::improper_style() { if (narg < 1) error->all(FLERR,"Illegal improper_style command"); if (atom->avec->impropers_allow == 0) error->all(FLERR,"Improper_style command when no impropers allowed"); force->create_improper(arg[0],lmp->suffix); if (force->improper) force->improper->settings(narg-1,&arg[1]); } /* ---------------------------------------------------------------------- */ void Input::kspace_modify() { if (force->kspace == NULL) error->all(FLERR,"KSpace style has not yet been set"); force->kspace->modify_params(narg,arg); } /* ---------------------------------------------------------------------- */ void Input::kspace_style() { force->create_kspace(narg,arg,lmp->suffix); } /* ---------------------------------------------------------------------- */ void Input::lattice() { domain->set_lattice(narg,arg); } /* ---------------------------------------------------------------------- */ void Input::mass() { if (narg != 2) error->all(FLERR,"Illegal mass command"); if (domain->box_exist == 0) error->all(FLERR,"Mass command before simulation box is defined"); atom->set_mass(narg,arg); } /* ---------------------------------------------------------------------- */ void Input::min_modify() { update->minimize->modify_params(narg,arg); } /* ---------------------------------------------------------------------- */ void Input::min_style() { if (domain->box_exist == 0) error->all(FLERR,"Min_style command before simulation box is defined"); update->create_minimize(narg,arg); } /* ---------------------------------------------------------------------- */ void Input::neigh_modify() { neighbor->modify_params(narg,arg); } /* ---------------------------------------------------------------------- */ void Input::neighbor_command() { neighbor->set(narg,arg); } /* ---------------------------------------------------------------------- */ void Input::newton() { int newton_pair,newton_bond; if (narg == 1) { if (strcmp(arg[0],"off") == 0) newton_pair = newton_bond = 0; else if (strcmp(arg[0],"on") == 0) newton_pair = newton_bond = 1; else error->all(FLERR,"Illegal newton command"); } else if (narg == 2) { if (strcmp(arg[0],"off") == 0) newton_pair = 0; else if (strcmp(arg[0],"on") == 0) newton_pair= 1; else error->all(FLERR,"Illegal newton command"); if (strcmp(arg[1],"off") == 0) newton_bond = 0; else if (strcmp(arg[1],"on") == 0) newton_bond = 1; else error->all(FLERR,"Illegal newton command"); } else error->all(FLERR,"Illegal newton command"); force->newton_pair = newton_pair; if (newton_bond == 0) { if (domain->box_exist && force->newton_bond == 1) error->all(FLERR,"Newton bond change after simulation box is defined"); force->newton_bond = 0; } else { if (domain->box_exist && force->newton_bond == 0) error->all(FLERR,"Newton bond change after simulation box is defined"); force->newton_bond = 1; } if (newton_pair || newton_bond) force->newton = 1; else force->newton = 0; } /* ---------------------------------------------------------------------- */ void Input::package() { if (domain->box_exist) error->all(FLERR,"Package command after simulation box is defined"); if (narg < 1) error->all(FLERR,"Illegal package command"); if (strcmp(arg[0],"cuda") == 0) { if (!lmp->cuda) error->all(FLERR,"Package cuda command without USER-CUDA installed"); lmp->cuda->accelerator(narg-1,&arg[1]); } else if (strcmp(arg[0],"gpu") == 0) { char **fixarg = new char*[2+narg]; - fixarg[0] = "package_gpu"; - fixarg[1] = "all"; - fixarg[2] = "GPU"; + fixarg[0] = (char *) "package_gpu"; + fixarg[1] = (char *) "all"; + fixarg[2] = (char *) "GPU"; for (int i = 1; i < narg; i++) fixarg[i+2] = arg[i]; modify->allow_early_fix = 1; modify->add_fix(2+narg,fixarg,NULL); modify->allow_early_fix = 0; delete [] fixarg; } else if (strcmp(arg[0],"omp") == 0) { char **fixarg = new char*[2+narg]; - fixarg[0] = "package_omp"; - fixarg[1] = "all"; - fixarg[2] = "OMP"; + fixarg[0] = (char *) "package_omp"; + fixarg[1] = (char *) "all"; + fixarg[2] = (char *) "OMP"; for (int i = 1; i < narg; i++) fixarg[i+2] = arg[i]; modify->allow_early_fix = 1; modify->add_fix(2+narg,fixarg,NULL); modify->allow_early_fix = 0; delete [] fixarg; } else error->all(FLERR,"Illegal package command"); } /* ---------------------------------------------------------------------- */ void Input::pair_coeff() { if (domain->box_exist == 0) error->all(FLERR,"Pair_coeff command before simulation box is defined"); if (force->pair == NULL) error->all(FLERR,"Pair_coeff command before pair_style is defined"); force->pair->coeff(narg,arg); } /* ---------------------------------------------------------------------- */ void Input::pair_modify() { if (force->pair == NULL) error->all(FLERR,"Pair_modify command before pair_style is defined"); force->pair->modify_params(narg,arg); } /* ---------------------------------------------------------------------- if old pair style exists and new style is same, just change settings else create new pair class ------------------------------------------------------------------------- */ void Input::pair_style() { if (narg < 1) error->all(FLERR,"Illegal pair_style command"); if (force->pair && strcmp(arg[0],force->pair_style) == 0) { force->pair->settings(narg-1,&arg[1]); return; } force->create_pair(arg[0],lmp->suffix); if (force->pair) force->pair->settings(narg-1,&arg[1]); } /* ---------------------------------------------------------------------- */ void Input::pair_write() { if (force->pair == NULL) error->all(FLERR,"Pair_write command before pair_style is defined"); force->pair->write_file(narg,arg); } /* ---------------------------------------------------------------------- */ void Input::processors() { if (domain->box_exist) error->all(FLERR,"Processors command after simulation box is defined"); comm->set_processors(narg,arg); } /* ---------------------------------------------------------------------- */ void Input::region() { domain->add_region(narg,arg); } /* ---------------------------------------------------------------------- */ void Input::reset_timestep() { update->reset_timestep(narg,arg); } /* ---------------------------------------------------------------------- */ void Input::restart() { output->create_restart(narg,arg); } /* ---------------------------------------------------------------------- */ void Input::run_style() { if (domain->box_exist == 0) error->all(FLERR,"Run_style command before simulation box is defined"); update->create_integrate(narg,arg,lmp->suffix); } /* ---------------------------------------------------------------------- */ void Input::special_bonds() { // store 1-3,1-4 and dihedral/extra flag values before change // change in 1-2 coeffs will not change the special list double lj2 = force->special_lj[2]; double lj3 = force->special_lj[3]; double coul2 = force->special_coul[2]; double coul3 = force->special_coul[3]; int angle = force->special_angle; int dihedral = force->special_dihedral; int extra = force->special_extra; force->set_special(narg,arg); // if simulation box defined and saved values changed, redo special list if (domain->box_exist && atom->molecular) { if (lj2 != force->special_lj[2] || lj3 != force->special_lj[3] || coul2 != force->special_coul[2] || coul3 != force->special_coul[3] || angle != force->special_angle || dihedral != force->special_dihedral || extra != force->special_extra) { Special special(lmp); special.build(); } } } /* ---------------------------------------------------------------------- */ void Input::suffix() { if (narg != 1) error->all(FLERR,"Illegal suffix command"); if (strcmp(arg[0],"off") == 0) lmp->suffix_enable = 0; else if (strcmp(arg[0],"on") == 0) lmp->suffix_enable = 1; else { delete [] lmp->suffix; int n = strlen(arg[0]) + 1; lmp->suffix = new char[n]; strcpy(lmp->suffix,arg[0]); lmp->suffix_enable = 1; } } /* ---------------------------------------------------------------------- */ void Input::thermo() { if (narg != 1) error->all(FLERR,"Illegal thermo command"); output->thermo_every = atoi(arg[0]); } /* ---------------------------------------------------------------------- */ void Input::thermo_modify() { output->thermo->modify_params(narg,arg); } /* ---------------------------------------------------------------------- */ void Input::thermo_style() { output->create_thermo(narg,arg); } /* ---------------------------------------------------------------------- */ void Input::timestep() { if (narg != 1) error->all(FLERR,"Illegal timestep command"); update->dt = atof(arg[0]); } /* ---------------------------------------------------------------------- */ void Input::uncompute() { if (narg != 1) error->all(FLERR,"Illegal uncompute command"); modify->delete_compute(arg[0]); } /* ---------------------------------------------------------------------- */ void Input::undump() { if (narg != 1) error->all(FLERR,"Illegal undump command"); output->delete_dump(arg[0]); } /* ---------------------------------------------------------------------- */ void Input::unfix() { if (narg != 1) error->all(FLERR,"Illegal unfix command"); modify->delete_fix(arg[0]); } /* ---------------------------------------------------------------------- */ void Input::units() { if (narg != 1) error->all(FLERR,"Illegal units command"); if (domain->box_exist) error->all(FLERR,"Units command after simulation box is defined"); update->set_units(arg[0]); } diff --git a/src/kspace.cpp b/src/kspace.cpp index 116535f8e..aa50ec1cd 100644 --- a/src/kspace.cpp +++ b/src/kspace.cpp @@ -1,80 +1,80 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ #include "stdlib.h" #include "string.h" #include "kspace.h" #include "error.h" #include "comm.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ KSpace::KSpace(LAMMPS *lmp, int narg, char **arg) : Pointers(lmp) { energy = 0.0; order = 5; gridflag = 0; gewaldflag = 0; slabflag = 0; slab_volfactor = 1; } /* ---------------------------------------------------------------------- modify parameters of the KSpace style ------------------------------------------------------------------------- */ void KSpace::modify_params(int narg, char **arg) { int iarg = 0; while (iarg < narg) { if (strcmp(arg[iarg],"mesh") == 0) { if (iarg+4 > narg) error->all(FLERR,"Illegal kspace_modify command"); nx_pppm = atoi(arg[iarg+1]); ny_pppm = atoi(arg[iarg+2]); nz_pppm = atoi(arg[iarg+3]); if (nx_pppm == 0 && ny_pppm == 0 && nz_pppm == 0) gridflag = 0; else gridflag = 1; iarg += 4; } else if (strcmp(arg[iarg],"order") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal kspace_modify command"); order = atoi(arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"gewald") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal kspace_modify command"); g_ewald = atof(arg[iarg+1]); if (g_ewald == 0.0) gewaldflag = 0; else gewaldflag = 1; iarg += 2; } else if (strcmp(arg[iarg],"slab") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal kspace_modify command"); slab_volfactor = atof(arg[iarg+1]); iarg += 2; if (slab_volfactor <= 1.0) error->all(FLERR,"Bad kspace_modify slab parameter"); if (slab_volfactor < 2.0 && comm->me == 0) error->warning(FLERR,"Kspace_modify slab param < 2.0 may " "cause unphysical behavior"); slabflag = 1; } else error->all(FLERR,"Illegal kspace_modify command"); } } /* ---------------------------------------------------------------------- */ -void *KSpace::extract(char *str) +void *KSpace::extract(const char *str) { if (strcmp(str,"scale") == 0) return (void *) &scale; return NULL; } diff --git a/src/kspace.h b/src/kspace.h index 2e4a7e8cb..fa54e4837 100644 --- a/src/kspace.h +++ b/src/kspace.h @@ -1,69 +1,69 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ #ifndef LMP_KSPACE_H #define LMP_KSPACE_H #include "pointers.h" namespace LAMMPS_NS { class KSpace : protected Pointers { friend class ThrOMP; public: double energy; double virial[6]; double g_ewald; int nx_pppm,ny_pppm,nz_pppm; KSpace(class LAMMPS *, int, char **); virtual ~KSpace() {} void modify_params(int, char **); - void *extract(char *); + void *extract(const char *); virtual void init() = 0; virtual void setup() = 0; virtual void compute(int, int) = 0; virtual void timing(int, double &, double &) {} virtual double memory_usage() {return 0.0;} protected: double slab_volfactor; int gridflag,gewaldflag; int order; int slabflag; double scale; }; } #endif /* ERROR/WARNING messages: E: Illegal ... command Self-explanatory. Check the input script syntax and compare to the documentation for the command. You can use -echo screen as a command-line option when running LAMMPS to see the offending line. E: Bad kspace_modify slab parameter Kspace_modify value for the slab/volume keyword must be >= 2.0. W: Kspace_modify slab param < 2.0 may cause unphysical behavior The kspace_modify slab parameter should be larger to insure periodic grids padded with empty space do not overlap. */ diff --git a/src/min.cpp b/src/min.cpp index eebfd03dc..d4e841e2a 100644 --- a/src/min.cpp +++ b/src/min.cpp @@ -1,764 +1,764 @@ /* ---------------------------------------------------------------------- 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 author: Aidan Thompson (SNL) improved CG and backtrack ls, added quadratic ls Sources: Numerical Recipes frprmn routine "Conjugate Gradient Method Without the Agonizing Pain" by JR Shewchuk, http://www-2.cs.cmu.edu/~jrs/jrspapers.html#cg ------------------------------------------------------------------------- */ #include "lmptype.h" #include "math.h" #include "stdlib.h" #include "string.h" #include "min.h" #include "atom.h" #include "domain.h" #include "comm.h" #include "update.h" #include "modify.h" #include "fix_minimize.h" #include "compute.h" #include "neighbor.h" #include "force.h" #include "pair.h" #include "bond.h" #include "angle.h" #include "dihedral.h" #include "improper.h" #include "kspace.h" #include "output.h" #include "thermo.h" #include "timer.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ Min::Min(LAMMPS *lmp) : Pointers(lmp) { dmax = 0.1; searchflag = 0; linestyle = 0; elist_global = elist_atom = NULL; vlist_global = vlist_atom = NULL; nextra_global = 0; fextra = NULL; nextra_atom = 0; xextra_atom = fextra_atom = NULL; extra_peratom = extra_nlen = NULL; extra_max = NULL; requestor = NULL; external_force_clear = 0; } /* ---------------------------------------------------------------------- */ Min::~Min() { delete [] elist_global; delete [] elist_atom; delete [] vlist_global; delete [] vlist_atom; delete [] fextra; memory->sfree(xextra_atom); memory->sfree(fextra_atom); memory->destroy(extra_peratom); memory->destroy(extra_nlen); memory->destroy(extra_max); memory->sfree(requestor); } /* ---------------------------------------------------------------------- */ void Min::init() { // create fix needed for storing atom-based quantities // will delete it at end of run char **fixarg = new char*[3]; fixarg[0] = (char *) "MINIMIZE"; fixarg[1] = (char *) "all"; fixarg[2] = (char *) "MINIMIZE"; modify->add_fix(3,fixarg); delete [] fixarg; fix_minimize = (FixMinimize *) modify->fix[modify->nfix-1]; // clear out extra global and per-atom dof // will receive requests for new per-atom dof during pair init() // can then add vectors to fix_minimize in setup() nextra_global = 0; delete [] fextra; fextra = NULL; nextra_atom = 0; memory->sfree(xextra_atom); memory->sfree(fextra_atom); memory->destroy(extra_peratom); memory->destroy(extra_nlen); memory->destroy(extra_max); memory->sfree(requestor); xextra_atom = fextra_atom = NULL; extra_peratom = extra_nlen = NULL; extra_max = NULL; requestor = NULL; // virial_style: // 1 if computed explicitly by pair->compute via sum over pair interactions // 2 if computed implicitly by pair->virial_compute via sum over ghost atoms if (force->newton_pair) virial_style = 2; else virial_style = 1; // setup lists of computes for global and per-atom PE and pressure ev_setup(); // detect if fix omp is present for clearing force arrays int ifix = modify->find_fix("package_omp"); if (ifix >= 0) external_force_clear = 1; // set flags for what arrays to clear in force_clear() // need to clear additionals arrays if they exist torqueflag = 0; if (atom->torque_flag) torqueflag = 1; erforceflag = 0; if (atom->erforce_flag) erforceflag = 1; e_flag = 0; if (atom->e_flag) e_flag = 1; rho_flag = 0; if (atom->rho_flag) rho_flag = 1; // orthogonal vs triclinic simulation box triclinic = domain->triclinic; // reset reneighboring criteria if necessary neigh_every = neighbor->every; neigh_delay = neighbor->delay; neigh_dist_check = neighbor->dist_check; if (neigh_every != 1 || neigh_delay != 0 || neigh_dist_check != 1) { if (comm->me == 0) error->warning(FLERR, "Resetting reneighboring criteria during minimization"); } neighbor->every = 1; neighbor->delay = 0; neighbor->dist_check = 1; niter = neval = 0; // style-specific initialization init_style(); } /* ---------------------------------------------------------------------- setup before run ------------------------------------------------------------------------- */ void Min::setup() { if (comm->me == 0 && screen) fprintf(screen,"Setting up minimization ...\n"); // setup extra global dof due to fixes // cannot be done in init() b/c update init() is before modify init() nextra_global = modify->min_dof(); if (nextra_global) fextra = new double[nextra_global]; // compute for potential energy int id = modify->find_compute("thermo_pe"); if (id < 0) error->all(FLERR,"Minimization could not find thermo_pe compute"); pe_compute = modify->compute[id]; // style-specific setup does two tasks // setup extra global dof vectors // setup extra per-atom dof vectors due to requests from Pair classes // cannot be done in init() b/c update init() is before modify/pair init() setup_style(); // ndoftotal = total dof for entire minimization problem // dof for atoms, extra per-atom, extra global bigint ndofme = 3*atom->nlocal; for (int m = 0; m < nextra_atom; m++) ndofme += extra_peratom[m]*atom->nlocal; MPI_Allreduce(&ndofme,&ndoftotal,1,MPI_LMP_BIGINT,MPI_SUM,world); ndoftotal += nextra_global; // setup domain, communication and neighboring // acquire ghosts // build neighbor lists atom->setup(); if (triclinic) domain->x2lamda(atom->nlocal); domain->pbc(); domain->reset_box(); comm->setup(); if (neighbor->style) neighbor->setup_bins(); comm->exchange(); if (atom->sortfreq > 0) atom->sort(); comm->borders(); if (triclinic) domain->lamda2x(atom->nlocal+atom->nghost); neighbor->build(); neighbor->ncalls = 0; // remove these restriction eventually if (nextra_global && searchflag == 0) error->all(FLERR, "Cannot use a damped dynamics min style with fix box/relax"); if (nextra_atom && searchflag == 0) error->all(FLERR, "Cannot use a damped dynamics min style with per-atom DOF"); // atoms may have migrated in comm->exchange() reset_vectors(); // compute all forces ev_set(update->ntimestep); force_clear(); modify->setup_pre_force(vflag); if (force->pair) force->pair->compute(eflag,vflag); if (atom->molecular) { if (force->bond) force->bond->compute(eflag,vflag); if (force->angle) force->angle->compute(eflag,vflag); if (force->dihedral) force->dihedral->compute(eflag,vflag); if (force->improper) force->improper->compute(eflag,vflag); } if (force->kspace) { force->kspace->setup(); force->kspace->compute(eflag,vflag); } if (force->newton) comm->reverse_comm(); // update per-atom minimization variables stored by pair styles if (nextra_atom) for (int m = 0; m < nextra_atom; m++) requestor[m]->min_xf_get(m); modify->setup(vflag); output->setup(1); // stats for Finish to print ecurrent = pe_compute->compute_scalar(); if (nextra_global) ecurrent += modify->min_energy(fextra); if (output->thermo->normflag) ecurrent /= atom->natoms; einitial = ecurrent; fnorm2_init = sqrt(fnorm_sqr()); fnorminf_init = fnorm_inf(); } /* ---------------------------------------------------------------------- setup without output or one-time post-init setup flag = 0 = just force calculation flag = 1 = reneighbor and force calculation ------------------------------------------------------------------------- */ void Min::setup_minimal(int flag) { // setup domain, communication and neighboring // acquire ghosts // build neighbor lists if (flag) { if (triclinic) domain->x2lamda(atom->nlocal); domain->pbc(); domain->reset_box(); comm->setup(); if (neighbor->style) neighbor->setup_bins(); comm->exchange(); comm->borders(); if (triclinic) domain->lamda2x(atom->nlocal+atom->nghost); neighbor->build(); neighbor->ncalls = 0; } // atoms may have migrated in comm->exchange() reset_vectors(); // compute all forces ev_set(update->ntimestep); force_clear(); modify->setup_pre_force(vflag); if (force->pair) force->pair->compute(eflag,vflag); if (atom->molecular) { if (force->bond) force->bond->compute(eflag,vflag); if (force->angle) force->angle->compute(eflag,vflag); if (force->dihedral) force->dihedral->compute(eflag,vflag); if (force->improper) force->improper->compute(eflag,vflag); } if (force->kspace) { force->kspace->setup(); force->kspace->compute(eflag,vflag); } if (force->newton) comm->reverse_comm(); // update per-atom minimization variables stored by pair styles if (nextra_atom) for (int m = 0; m < nextra_atom; m++) requestor[m]->min_xf_get(m); modify->setup(vflag); // stats for Finish to print ecurrent = pe_compute->compute_scalar(); if (nextra_global) ecurrent += modify->min_energy(fextra); if (output->thermo->normflag) ecurrent /= atom->natoms; einitial = ecurrent; fnorm2_init = sqrt(fnorm_sqr()); fnorminf_init = fnorm_inf(); } /* ---------------------------------------------------------------------- perform minimization, calling iterate() for N steps ------------------------------------------------------------------------- */ void Min::run(int n) { // minimizer iterations stop_condition = iterate(n); stopstr = stopstrings(stop_condition); // if early exit from iterate loop: // set update->nsteps to niter for Finish stats to print // set output->next values to this timestep // call energy_force() to insure vflag is set when forces computed // output->write does final output for thermo, dump, restart files // add ntimestep to all computes that store invocation times // since are hardwiring call to thermo/dumps and computes may not be ready if (stop_condition) { update->nsteps = niter; if (update->restrict_output == 0) { for (int idump = 0; idump < output->ndump; idump++) output->next_dump[idump] = update->ntimestep; output->next_dump_any = update->ntimestep; if (output->restart_every) output->next_restart = update->ntimestep; } output->next_thermo = update->ntimestep; modify->addstep_compute_all(update->ntimestep); ecurrent = energy_force(0); output->write(update->ntimestep); } } /* ---------------------------------------------------------------------- */ void Min::cleanup() { // stats for Finish to print efinal = ecurrent; fnorm2_final = sqrt(fnorm_sqr()); fnorminf_final = fnorm_inf(); // reset reneighboring criteria neighbor->every = neigh_every; neighbor->delay = neigh_delay; neighbor->dist_check = neigh_dist_check; // delete fix at end of run, so its atom arrays won't persist modify->delete_fix("MINIMIZE"); } /* ---------------------------------------------------------------------- evaluate potential energy and forces may migrate atoms due to reneighboring return new energy, which should include nextra_global dof return negative gradient stored in atom->f return negative gradient for nextra_global dof in fextra ------------------------------------------------------------------------- */ double Min::energy_force(int resetflag) { // check for reneighboring // always communicate since minimizer moved atoms int nflag = neighbor->decide(); if (nflag == 0) { timer->stamp(); comm->forward_comm(); timer->stamp(TIME_COMM); } else { if (modify->n_min_pre_exchange) modify->min_pre_exchange(); if (triclinic) domain->x2lamda(atom->nlocal); domain->pbc(); if (domain->box_change) { domain->reset_box(); comm->setup(); if (neighbor->style) neighbor->setup_bins(); } timer->stamp(); comm->exchange(); if (atom->sortfreq > 0 && update->ntimestep >= atom->nextsort) atom->sort(); comm->borders(); if (triclinic) domain->lamda2x(atom->nlocal+atom->nghost); timer->stamp(TIME_COMM); neighbor->build(); timer->stamp(TIME_NEIGHBOR); } ev_set(update->ntimestep); force_clear(); if (modify->n_min_pre_force) modify->min_pre_force(vflag); timer->stamp(); if (force->pair) { force->pair->compute(eflag,vflag); timer->stamp(TIME_PAIR); } if (atom->molecular) { if (force->bond) force->bond->compute(eflag,vflag); if (force->angle) force->angle->compute(eflag,vflag); if (force->dihedral) force->dihedral->compute(eflag,vflag); if (force->improper) force->improper->compute(eflag,vflag); timer->stamp(TIME_BOND); } if (force->kspace) { force->kspace->compute(eflag,vflag); timer->stamp(TIME_KSPACE); } if (force->newton) { comm->reverse_comm(); timer->stamp(TIME_COMM); } // update per-atom minimization variables stored by pair styles if (nextra_atom) for (int m = 0; m < nextra_atom; m++) requestor[m]->min_xf_get(m); // fixes that affect minimization if (modify->n_min_post_force) modify->min_post_force(vflag); // compute potential energy of system // normalize if thermo PE does double energy = pe_compute->compute_scalar(); if (nextra_global) energy += modify->min_energy(fextra); if (output->thermo->normflag) energy /= atom->natoms; // if reneighbored, atoms migrated // if resetflag = 1, update x0 of atoms crossing PBC // reset vectors used by lo-level minimizer if (nflag) { if (resetflag) fix_minimize->reset_coords(); reset_vectors(); } return energy; } /* ---------------------------------------------------------------------- clear force on own & ghost atoms setup and clear other arrays as needed ------------------------------------------------------------------------- */ void Min::force_clear() { if (external_force_clear) return; int i; if (external_force_clear) return; // clear global force array // nall includes ghosts only if either newton flag is set int nall; if (force->newton) nall = atom->nlocal + atom->nghost; else nall = atom->nlocal; size_t nbytes = sizeof(double) * nall; if (nbytes) { memset(&(atom->f[0][0]),0,3*nbytes); if (torqueflag) memset(&(atom->torque[0][0]),0,3*nbytes); if (erforceflag) memset(&(atom->erforce[0]), 0, nbytes); if (e_flag) memset(&(atom->de[0]), 0, nbytes); if (rho_flag) memset(&(atom->drho[0]), 0, nbytes); } } /* ---------------------------------------------------------------------- pair style makes request to add a per-atom variables to minimization requestor stores callback to pair class to invoke during min to get current variable and forces on it and to update the variable return flag that pair can use if it registers multiple variables ------------------------------------------------------------------------- */ int Min::request(Pair *pair, int peratom, double maxvalue) { int n = nextra_atom + 1; xextra_atom = (double **) memory->srealloc(xextra_atom,n*sizeof(double *), "min:xextra_atom"); fextra_atom = (double **) memory->srealloc(fextra_atom,n*sizeof(double *), "min:fextra_atom"); memory->grow(extra_peratom,n,"min:extra_peratom"); memory->grow(extra_nlen,n,"min:extra_nlen"); memory->grow(extra_max,n,"min:extra_max"); requestor = (Pair **) memory->srealloc(requestor,n*sizeof(Pair *), "min:requestor"); requestor[nextra_atom] = pair; extra_peratom[nextra_atom] = peratom; extra_max[nextra_atom] = maxvalue; nextra_atom++; return nextra_atom-1; } /* ---------------------------------------------------------------------- */ void Min::modify_params(int narg, char **arg) { if (narg == 0) error->all(FLERR,"Illegal min_modify command"); int iarg = 0; while (iarg < narg) { if (strcmp(arg[iarg],"dmax") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal min_modify command"); dmax = atof(arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"line") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal min_modify command"); if (strcmp(arg[iarg+1],"backtrack") == 0) linestyle = 0; else if (strcmp(arg[iarg+1],"quadratic") == 0) linestyle = 1; else error->all(FLERR,"Illegal min_modify command"); iarg += 2; } else error->all(FLERR,"Illegal min_modify command"); } } /* ---------------------------------------------------------------------- setup lists of computes for global and per-atom PE and pressure ------------------------------------------------------------------------- */ void Min::ev_setup() { delete [] elist_global; delete [] elist_atom; delete [] vlist_global; delete [] vlist_atom; elist_global = elist_atom = NULL; vlist_global = vlist_atom = NULL; nelist_global = nelist_atom = 0; nvlist_global = nvlist_atom = 0; for (int i = 0; i < modify->ncompute; i++) { if (modify->compute[i]->peflag) nelist_global++; if (modify->compute[i]->peatomflag) nelist_atom++; if (modify->compute[i]->pressflag) nvlist_global++; if (modify->compute[i]->pressatomflag) nvlist_atom++; } if (nelist_global) elist_global = new Compute*[nelist_global]; if (nelist_atom) elist_atom = new Compute*[nelist_atom]; if (nvlist_global) vlist_global = new Compute*[nvlist_global]; if (nvlist_atom) vlist_atom = new Compute*[nvlist_atom]; nelist_global = nelist_atom = 0; nvlist_global = nvlist_atom = 0; for (int i = 0; i < modify->ncompute; i++) { if (modify->compute[i]->peflag) elist_global[nelist_global++] = modify->compute[i]; if (modify->compute[i]->peatomflag) elist_atom[nelist_atom++] = modify->compute[i]; if (modify->compute[i]->pressflag) vlist_global[nvlist_global++] = modify->compute[i]; if (modify->compute[i]->pressatomflag) vlist_atom[nvlist_atom++] = modify->compute[i]; } } /* ---------------------------------------------------------------------- set eflag,vflag for current iteration invoke matchstep() on all timestep-dependent computes to clear their arrays eflag/vflag based on computes that need info on this ntimestep always set eflag_global = 1, since need energy every iteration eflag = 0 = no energy computation eflag = 1 = global energy only eflag = 2 = per-atom energy only eflag = 3 = both global and per-atom energy vflag = 0 = no virial computation (pressure) vflag = 1 = global virial with pair portion via sum of pairwise interactions vflag = 2 = global virial with pair portion via F dot r including ghosts vflag = 4 = per-atom virial only vflag = 5 or 6 = both global and per-atom virial ------------------------------------------------------------------------- */ void Min::ev_set(bigint ntimestep) { int i,flag; int eflag_global = 1; for (i = 0; i < nelist_global; i++) elist_global[i]->matchstep(ntimestep); flag = 0; int eflag_atom = 0; for (i = 0; i < nelist_atom; i++) if (elist_atom[i]->matchstep(ntimestep)) flag = 1; if (flag) eflag_atom = 2; if (eflag_global) update->eflag_global = update->ntimestep; if (eflag_atom) update->eflag_atom = update->ntimestep; eflag = eflag_global + eflag_atom; flag = 0; int vflag_global = 0; for (i = 0; i < nvlist_global; i++) if (vlist_global[i]->matchstep(ntimestep)) flag = 1; if (flag) vflag_global = virial_style; flag = 0; int vflag_atom = 0; for (i = 0; i < nvlist_atom; i++) if (vlist_atom[i]->matchstep(ntimestep)) flag = 1; if (flag) vflag_atom = 4; if (vflag_global) update->vflag_global = update->ntimestep; if (vflag_atom) update->vflag_atom = update->ntimestep; vflag = vflag_global + vflag_atom; } /* ---------------------------------------------------------------------- compute and return ||force||_2^2 ------------------------------------------------------------------------- */ double Min::fnorm_sqr() { int i,n; double *fatom; double local_norm2_sqr = 0.0; for (i = 0; i < nvec; i++) local_norm2_sqr += fvec[i]*fvec[i]; if (nextra_atom) { for (int m = 0; m < nextra_atom; m++) { fatom = fextra_atom[m]; n = extra_nlen[m]; for (i = 0; i < n; i++) local_norm2_sqr += fatom[i]*fatom[i]; } } double norm2_sqr = 0.0; MPI_Allreduce(&local_norm2_sqr,&norm2_sqr,1,MPI_DOUBLE,MPI_SUM,world); if (nextra_global) for (i = 0; i < nextra_global; i++) norm2_sqr += fextra[i]*fextra[i]; return norm2_sqr; } /* ---------------------------------------------------------------------- compute and return ||force||_inf ------------------------------------------------------------------------- */ double Min::fnorm_inf() { int i,n; double *fatom; double local_norm_inf = 0.0; for (i = 0; i < nvec; i++) local_norm_inf = MAX(fabs(fvec[i]),local_norm_inf); if (nextra_atom) { for (int m = 0; m < nextra_atom; m++) { fatom = fextra_atom[m]; n = extra_nlen[m]; for (i = 0; i < n; i++) local_norm_inf = MAX(fabs(fatom[i]),local_norm_inf); } } double norm_inf = 0.0; MPI_Allreduce(&local_norm_inf,&norm_inf,1,MPI_DOUBLE,MPI_MAX,world); if (nextra_global) for (i = 0; i < nextra_global; i++) norm_inf = MAX(fabs(fextra[i]),norm_inf); return norm_inf; } /* ---------------------------------------------------------------------- possible stop conditions ------------------------------------------------------------------------- */ char *Min::stopstrings(int n) { - char *strings[] = {"max iterations", - "max force evaluations", - "energy tolerance", - "force tolerance", - "search direction is not downhill", - "linesearch alpha is zero", - "forces are zero", - "quadratic factors are zero", - "trust region too small", - "HFTN minimizer error"}; - return strings[n]; + const char *strings[] = {"max iterations", + "max force evaluations", + "energy tolerance", + "force tolerance", + "search direction is not downhill", + "linesearch alpha is zero", + "forces are zero", + "quadratic factors are zero", + "trust region too small", + "HFTN minimizer error"}; + return (char *) strings[n]; } diff --git a/src/modify.cpp b/src/modify.cpp index c07416ac4..aeafe61d5 100644 --- a/src/modify.cpp +++ b/src/modify.cpp @@ -1,1166 +1,1166 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ #include "lmptype.h" #include "stdio.h" #include "string.h" #include "modify.h" #include "style_compute.h" #include "style_fix.h" #include "atom.h" #include "comm.h" #include "fix.h" #include "compute.h" #include "group.h" #include "update.h" #include "domain.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define DELTA 4 // mask settings - same as in fix.cpp #define INITIAL_INTEGRATE 1 #define POST_INTEGRATE 2 #define PRE_EXCHANGE 4 #define PRE_NEIGHBOR 8 #define PRE_FORCE 16 #define POST_FORCE 32 #define FINAL_INTEGRATE 64 #define END_OF_STEP 128 #define THERMO_ENERGY 256 #define INITIAL_INTEGRATE_RESPA 512 #define POST_INTEGRATE_RESPA 1024 #define PRE_FORCE_RESPA 2048 #define POST_FORCE_RESPA 4096 #define FINAL_INTEGRATE_RESPA 8192 #define MIN_PRE_EXCHANGE 16384 #define MIN_PRE_FORCE 32768 #define MIN_POST_FORCE 65536 #define MIN_ENERGY 131072 #define POST_RUN 262144 #define BIG 1.0e20 /* ---------------------------------------------------------------------- */ Modify::Modify(LAMMPS *lmp) : Pointers(lmp) { nfix = maxfix = 0; n_initial_integrate = n_post_integrate = 0; n_pre_exchange = n_pre_neighbor = 0; n_pre_force = n_post_force = 0; n_final_integrate = n_end_of_step = n_thermo_energy = 0; n_initial_integrate_respa = n_post_integrate_respa = 0; n_pre_force_respa = n_post_force_respa = n_final_integrate_respa = 0; n_min_pre_exchange = n_min_pre_force = n_min_post_force = n_min_energy = 0; fix = NULL; fmask = NULL; list_initial_integrate = list_post_integrate = NULL; list_pre_exchange = list_pre_neighbor = NULL; list_pre_force = list_post_force = NULL; list_final_integrate = list_end_of_step = NULL; list_thermo_energy = NULL; list_initial_integrate_respa = list_post_integrate_respa = NULL; list_pre_force_respa = list_post_force_respa = NULL; list_final_integrate_respa = NULL; list_min_pre_exchange = list_min_pre_force = list_min_post_force = list_min_energy = NULL; end_of_step_every = NULL; list_timeflag = NULL; nfix_restart_global = 0; id_restart_global = style_restart_global = state_restart_global = NULL; nfix_restart_peratom = 0; id_restart_peratom = style_restart_peratom = NULL; index_restart_peratom = NULL; allow_early_fix = 0; ncompute = maxcompute = 0; compute = NULL; } /* ---------------------------------------------------------------------- */ Modify::~Modify() { // delete all fixes // do it via delete_fix() so callbacks in Atom are also updated correctly while (nfix) delete_fix(fix[0]->id); memory->sfree(fix); memory->destroy(fmask); // delete all computes for (int i = 0; i < ncompute; i++) delete compute[i]; memory->sfree(compute); delete [] list_initial_integrate; delete [] list_post_integrate; delete [] list_pre_exchange; delete [] list_pre_neighbor; delete [] list_pre_force; delete [] list_post_force; delete [] list_final_integrate; delete [] list_end_of_step; delete [] list_thermo_energy; delete [] list_initial_integrate_respa; delete [] list_post_integrate_respa; delete [] list_pre_force_respa; delete [] list_post_force_respa; delete [] list_final_integrate_respa; delete [] list_min_pre_exchange; delete [] list_min_pre_force; delete [] list_min_post_force; delete [] list_min_energy; delete [] end_of_step_every; delete [] list_timeflag; restart_deallocate(); } /* ---------------------------------------------------------------------- initialize all fixes and computes ------------------------------------------------------------------------- */ void Modify::init() { int i,j; // delete storage of restart info since it is not valid after 1st run restart_deallocate(); // create lists of fixes to call at each stage of run list_init(INITIAL_INTEGRATE,n_initial_integrate,list_initial_integrate); list_init(POST_INTEGRATE,n_post_integrate,list_post_integrate); list_init(PRE_EXCHANGE,n_pre_exchange,list_pre_exchange); list_init(PRE_NEIGHBOR,n_pre_neighbor,list_pre_neighbor); list_init(PRE_FORCE,n_pre_force,list_pre_force); list_init(POST_FORCE,n_post_force,list_post_force); list_init(FINAL_INTEGRATE,n_final_integrate,list_final_integrate); list_init_end_of_step(END_OF_STEP,n_end_of_step,list_end_of_step); list_init_thermo_energy(THERMO_ENERGY,n_thermo_energy,list_thermo_energy); list_init(INITIAL_INTEGRATE_RESPA, n_initial_integrate_respa,list_initial_integrate_respa); list_init(POST_INTEGRATE_RESPA, n_post_integrate_respa,list_post_integrate_respa); list_init(POST_FORCE_RESPA, n_post_force_respa,list_post_force_respa); list_init(PRE_FORCE_RESPA, n_pre_force_respa,list_pre_force_respa); list_init(FINAL_INTEGRATE_RESPA, n_final_integrate_respa,list_final_integrate_respa); list_init(MIN_PRE_EXCHANGE,n_min_pre_exchange,list_min_pre_exchange); list_init(MIN_PRE_FORCE,n_min_pre_force,list_min_pre_force); list_init(MIN_POST_FORCE,n_min_post_force,list_min_post_force); list_init(MIN_ENERGY,n_min_energy,list_min_energy); // init each fix // needs to come before compute init // this is b/c some computes call fix->dof() // FixRigid::dof() depends on its own init having been called for (i = 0; i < nfix; i++) fix[i]->init(); // set global flag if any fix has its restart_pbc flag set restart_pbc_any = 0; for (i = 0; i < nfix; i++) if (fix[i]->restart_pbc) restart_pbc_any = 1; // create list of computes that store invocation times list_init_compute(); // init each compute // set invoked_scalar,vector,etc to -1 to force new run to re-compute them // add initial timestep to all computes that store invocation times // since any of them may be invoked by initial thermo // do not clear out invocation times stored within a compute, // b/c some may be holdovers from previous run, like for ave fixes for (i = 0; i < ncompute; i++) { compute[i]->init(); compute[i]->invoked_scalar = -1; compute[i]->invoked_vector = -1; compute[i]->invoked_array = -1; compute[i]->invoked_peratom = -1; compute[i]->invoked_local = -1; } addstep_compute_all(update->ntimestep); // warn if any particle is time integrated more than once int nlocal = atom->nlocal; int *mask = atom->mask; int *flag = new int[nlocal]; for (i = 0; i < nlocal; i++) flag[i] = 0; int groupbit; for (i = 0; i < nfix; i++) { if (fix[i]->time_integrate == 0) continue; groupbit = fix[i]->groupbit; for (j = 0; j < nlocal; j++) if (mask[j] & groupbit) flag[j]++; } int check = 0; for (i = 0; i < nlocal; i++) if (flag[i] > 1) check = 1; delete [] flag; int checkall; MPI_Allreduce(&check,&checkall,1,MPI_INT,MPI_SUM,world); if (comm->me == 0 && checkall) error->warning(FLERR,"One or more atoms are time integrated more than once"); } /* ---------------------------------------------------------------------- setup for run, calls setup() of all fixes ------------------------------------------------------------------------- */ void Modify::setup(int vflag) { if (update->whichflag == 1) for (int i = 0; i < nfix; i++) fix[i]->setup(vflag); else if (update->whichflag == 2) for (int i = 0; i < nfix; i++) fix[i]->min_setup(vflag); } /* ---------------------------------------------------------------------- setup pre_exchange call, only for fixes that define pre_exchange ------------------------------------------------------------------------- */ void Modify::setup_pre_exchange() { for (int i = 0; i < n_pre_exchange; i++) fix[list_pre_exchange[i]]->setup_pre_exchange(); } /* ---------------------------------------------------------------------- setup pre_force call, only for fixes that define pre_force ------------------------------------------------------------------------- */ void Modify::setup_pre_force(int vflag) { if (update->whichflag == 1) for (int i = 0; i < n_pre_force; i++) fix[list_pre_force[i]]->setup_pre_force(vflag); else if (update->whichflag == 2) for (int i = 0; i < n_min_pre_force; i++) fix[list_min_pre_force[i]]->min_setup_pre_force(vflag); } /* ---------------------------------------------------------------------- 1st half of integrate call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::initial_integrate(int vflag) { for (int i = 0; i < n_initial_integrate; i++) fix[list_initial_integrate[i]]->initial_integrate(vflag); } /* ---------------------------------------------------------------------- post_integrate call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::post_integrate() { for (int i = 0; i < n_post_integrate; i++) fix[list_post_integrate[i]]->post_integrate(); } /* ---------------------------------------------------------------------- pre_exchange call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::pre_exchange() { for (int i = 0; i < n_pre_exchange; i++) fix[list_pre_exchange[i]]->pre_exchange(); } /* ---------------------------------------------------------------------- pre_neighbor call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::pre_neighbor() { for (int i = 0; i < n_pre_neighbor; i++) fix[list_pre_neighbor[i]]->pre_neighbor(); } /* ---------------------------------------------------------------------- pre_force call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::pre_force(int vflag) { for (int i = 0; i < n_pre_force; i++) fix[list_pre_force[i]]->pre_force(vflag); } /* ---------------------------------------------------------------------- post_force call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::post_force(int vflag) { for (int i = 0; i < n_post_force; i++) fix[list_post_force[i]]->post_force(vflag); } /* ---------------------------------------------------------------------- 2nd half of integrate call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::final_integrate() { for (int i = 0; i < n_final_integrate; i++) fix[list_final_integrate[i]]->final_integrate(); } /* ---------------------------------------------------------------------- end-of-timestep call, only for relevant fixes only call fix->end_of_step() on timesteps that are multiples of nevery ------------------------------------------------------------------------- */ void Modify::end_of_step() { for (int i = 0; i < n_end_of_step; i++) if (update->ntimestep % end_of_step_every[i] == 0) fix[list_end_of_step[i]]->end_of_step(); } /* ---------------------------------------------------------------------- thermo energy call, only for relevant fixes called by Thermo class compute_scalar() is fix call to return energy ------------------------------------------------------------------------- */ double Modify::thermo_energy() { double energy = 0.0; for (int i = 0; i < n_thermo_energy; i++) energy += fix[list_thermo_energy[i]]->compute_scalar(); return energy; } /* ---------------------------------------------------------------------- post_run call ------------------------------------------------------------------------- */ void Modify::post_run() { for (int i = 0; i < nfix; i++) fix[i]->post_run(); } /* ---------------------------------------------------------------------- setup rRESPA pre_force call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::setup_pre_force_respa(int vflag, int ilevel) { for (int i = 0; i < n_pre_force; i++) fix[list_pre_force[i]]->setup_pre_force_respa(vflag,ilevel); } /* ---------------------------------------------------------------------- 1st half of rRESPA integrate call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::initial_integrate_respa(int vflag, int ilevel, int iloop) { for (int i = 0; i < n_initial_integrate_respa; i++) fix[list_initial_integrate_respa[i]]-> initial_integrate_respa(vflag,ilevel,iloop); } /* ---------------------------------------------------------------------- rRESPA post_integrate call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::post_integrate_respa(int ilevel, int iloop) { for (int i = 0; i < n_post_integrate_respa; i++) fix[list_post_integrate_respa[i]]->post_integrate_respa(ilevel,iloop); } /* ---------------------------------------------------------------------- rRESPA pre_force call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::pre_force_respa(int vflag, int ilevel, int iloop) { for (int i = 0; i < n_pre_force_respa; i++) fix[list_pre_force_respa[i]]->pre_force_respa(vflag,ilevel,iloop); } /* ---------------------------------------------------------------------- rRESPA post_force call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::post_force_respa(int vflag, int ilevel, int iloop) { for (int i = 0; i < n_post_force_respa; i++) fix[list_post_force_respa[i]]->post_force_respa(vflag,ilevel,iloop); } /* ---------------------------------------------------------------------- 2nd half of rRESPA integrate call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::final_integrate_respa(int ilevel, int iloop) { for (int i = 0; i < n_final_integrate_respa; i++) fix[list_final_integrate_respa[i]]->final_integrate_respa(ilevel,iloop); } /* ---------------------------------------------------------------------- minimizer pre-exchange call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::min_pre_exchange() { for (int i = 0; i < n_min_pre_exchange; i++) fix[list_min_pre_exchange[i]]->min_pre_exchange(); } /* ---------------------------------------------------------------------- minimizer pre-force call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::min_pre_force(int vflag) { for (int i = 0; i < n_min_pre_force; i++) fix[list_min_pre_force[i]]->min_pre_force(vflag); } /* ---------------------------------------------------------------------- minimizer force adjustment call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::min_post_force(int vflag) { for (int i = 0; i < n_min_post_force; i++) fix[list_min_post_force[i]]->min_post_force(vflag); } /* ---------------------------------------------------------------------- minimizer energy/force evaluation, only for relevant fixes return energy and forces on extra degrees of freedom ------------------------------------------------------------------------- */ double Modify::min_energy(double *fextra) { int ifix,index; index = 0; double eng = 0.0; for (int i = 0; i < n_min_energy; i++) { ifix = list_min_energy[i]; eng += fix[ifix]->min_energy(&fextra[index]); index += fix[ifix]->min_dof(); } return eng; } /* ---------------------------------------------------------------------- store current state of extra dof, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::min_store() { for (int i = 0; i < n_min_energy; i++) fix[list_min_energy[i]]->min_store(); } /* ---------------------------------------------------------------------- mange state of extra dof on a stack, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::min_clearstore() { for (int i = 0; i < n_min_energy; i++) fix[list_min_energy[i]]->min_clearstore(); } void Modify::min_pushstore() { for (int i = 0; i < n_min_energy; i++) fix[list_min_energy[i]]->min_pushstore(); } void Modify::min_popstore() { for (int i = 0; i < n_min_energy; i++) fix[list_min_energy[i]]->min_popstore(); } /* ---------------------------------------------------------------------- displace extra dof along vector hextra, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::min_step(double alpha, double *hextra) { int ifix,index; index = 0; for (int i = 0; i < n_min_energy; i++) { ifix = list_min_energy[i]; fix[ifix]->min_step(alpha,&hextra[index]); index += fix[ifix]->min_dof(); } } /* ---------------------------------------------------------------------- compute max allowed step size along vector hextra, only for relevant fixes ------------------------------------------------------------------------- */ double Modify::max_alpha(double *hextra) { int ifix,index; double alpha = BIG; index = 0; for (int i = 0; i < n_min_energy; i++) { ifix = list_min_energy[i]; double alpha_one = fix[ifix]->max_alpha(&hextra[index]); alpha = MIN(alpha,alpha_one); index += fix[ifix]->min_dof(); } return alpha; } /* ---------------------------------------------------------------------- extract extra dof for minimization, only for relevant fixes ------------------------------------------------------------------------- */ int Modify::min_dof() { int ndof = 0; for (int i = 0; i < n_min_energy; i++) ndof += fix[list_min_energy[i]]->min_dof(); return ndof; } /* ---------------------------------------------------------------------- reset reference state of fix, only for relevant fixes ------------------------------------------------------------------------- */ int Modify::min_reset_ref() { int itmp,itmpall; itmpall = 0; for (int i = 0; i < n_min_energy; i++) { itmp = fix[list_min_energy[i]]->min_reset_ref(); if (itmp) itmpall = 1; } return itmpall; } /* ---------------------------------------------------------------------- add a new fix or replace one with same ID ------------------------------------------------------------------------- */ void Modify::add_fix(int narg, char **arg, char *suffix) { if (domain->box_exist == 0 && allow_early_fix == 0) error->all(FLERR,"Fix command before simulation box is defined"); if (narg < 3) error->all(FLERR,"Illegal fix command"); // check group ID int igroup = group->find(arg[1]); if (igroup == -1) error->all(FLERR,"Could not find fix group ID"); // if fix ID exists: // set newflag = 0 so create new fix in same location in fix list // error if new style does not match old style // since can't replace it (all when-to-invoke ptrs would be invalid) // warn if new group != old group // delete old fix, but do not call update_callback(), // since will replace this fix and thus other fix locs will not change // set ptr to NULL in case new fix scans list of fixes, // e.g. scan will occur in add_callback() if called by new fix // if fix ID does not exist: // set newflag = 1 so create new fix // extend fix and fmask lists as necessary int ifix,newflag; for (ifix = 0; ifix < nfix; ifix++) if (strcmp(arg[0],fix[ifix]->id) == 0) break; if (ifix < nfix) { newflag = 0; if (strcmp(arg[2],fix[ifix]->style) != 0) error->all(FLERR,"Replacing a fix, but new style != old style"); if (fix[ifix]->igroup != igroup && comm->me == 0) error->warning(FLERR,"Replacing a fix, but new group != old group"); delete fix[ifix]; fix[ifix] = NULL; } else { newflag = 1; if (nfix == maxfix) { maxfix += DELTA; fix = (Fix **) memory->srealloc(fix,maxfix*sizeof(Fix *),"modify:fix"); memory->grow(fmask,maxfix,"modify:fmask"); } } // create the Fix, first with suffix appended int success = 0; if (suffix && lmp->suffix_enable) { char estyle[256]; sprintf(estyle,"%s/%s",arg[2],suffix); success = 1; if (0) return; #define FIX_CLASS #define FixStyle(key,Class) \ else if (strcmp(estyle,#key) == 0) fix[ifix] = new Class(lmp,narg,arg); #include "style_fix.h" #undef FixStyle #undef FIX_CLASS else success = 0; } if (!success) { if (0) return; #define FIX_CLASS #define FixStyle(key,Class) \ else if (strcmp(arg[2],#key) == 0) fix[ifix] = new Class(lmp,narg,arg); #include "style_fix.h" #undef FixStyle #undef FIX_CLASS else error->all(FLERR,"Invalid fix style"); } // set fix mask values and increment nfix (if new) fmask[ifix] = fix[ifix]->setmask(); if (newflag) nfix++; // check if Fix is in restart_global list // if yes, pass state info to the Fix so it can reset itself for (int i = 0; i < nfix_restart_global; i++) if (strcmp(id_restart_global[i],fix[ifix]->id) == 0 && strcmp(style_restart_global[i],fix[ifix]->style) == 0) { fix[ifix]->restart(state_restart_global[i]); if (comm->me == 0) { char *str = (char *) ("Resetting global state of Fix %s Style %s " "from restart file info\n"); if (screen) fprintf(screen,str,fix[ifix]->id,fix[ifix]->style); if (logfile) fprintf(logfile,str,fix[ifix]->id,fix[ifix]->style); } } // check if Fix is in restart_peratom list // if yes, loop over atoms so they can extract info from atom->extra array for (int i = 0; i < nfix_restart_peratom; i++) if (strcmp(id_restart_peratom[i],fix[ifix]->id) == 0 && strcmp(style_restart_peratom[i],fix[ifix]->style) == 0) { for (int j = 0; j < atom->nlocal; j++) fix[ifix]->unpack_restart(j,index_restart_peratom[i]); if (comm->me == 0) { char *str = (char *) ("Resetting per-atom state of Fix %s Style %s " "from restart file info\n"); if (screen) fprintf(screen,str,fix[ifix]->id,fix[ifix]->style); if (logfile) fprintf(logfile,str,fix[ifix]->id,fix[ifix]->style); } } } /* ---------------------------------------------------------------------- modify a Fix's parameters ------------------------------------------------------------------------- */ void Modify::modify_fix(int narg, char **arg) { if (narg < 2) error->all(FLERR,"Illegal fix_modify command"); // lookup Fix ID int ifix; for (ifix = 0; ifix < nfix; ifix++) if (strcmp(arg[0],fix[ifix]->id) == 0) break; if (ifix == nfix) error->all(FLERR,"Could not find fix_modify ID"); fix[ifix]->modify_params(narg-1,&arg[1]); } /* ---------------------------------------------------------------------- delete a Fix from list of Fixes Atom class must update indices in its list of callbacks to fixes ------------------------------------------------------------------------- */ void Modify::delete_fix(const char *id) { int ifix = find_fix(id); if (ifix < 0) error->all(FLERR,"Could not find fix ID to delete"); delete fix[ifix]; atom->update_callback(ifix); // move other Fixes and fmask down in list one slot for (int i = ifix+1; i < nfix; i++) fix[i-1] = fix[i]; for (int i = ifix+1; i < nfix; i++) fmask[i-1] = fmask[i]; nfix--; } /* ---------------------------------------------------------------------- find a fix by ID return index of fix or -1 if not found ------------------------------------------------------------------------- */ int Modify::find_fix(const char *id) { int ifix; for (ifix = 0; ifix < nfix; ifix++) if (strcmp(id,fix[ifix]->id) == 0) break; if (ifix == nfix) return -1; return ifix; } /* ---------------------------------------------------------------------- add a new compute ------------------------------------------------------------------------- */ void Modify::add_compute(int narg, char **arg, char *suffix) { if (narg < 3) error->all(FLERR,"Illegal compute command"); // error check for (int icompute = 0; icompute < ncompute; icompute++) if (strcmp(arg[0],compute[icompute]->id) == 0) error->all(FLERR,"Reuse of compute ID"); // extend Compute list if necessary if (ncompute == maxcompute) { maxcompute += DELTA; compute = (Compute **) memory->srealloc(compute,maxcompute*sizeof(Compute *),"modify:compute"); } // create the Compute, first with suffix appended int success = 0; if (suffix && lmp->suffix_enable) { char estyle[256]; sprintf(estyle,"%s/%s",arg[2],suffix); success = 1; if (0) return; #define COMPUTE_CLASS #define ComputeStyle(key,Class) \ else if (strcmp(estyle,#key) == 0) \ compute[ncompute] = new Class(lmp,narg,arg); #include "style_compute.h" #undef ComputeStyle #undef COMPUTE_CLASS else success = 0; } if (!success) { if (0) return; #define COMPUTE_CLASS #define ComputeStyle(key,Class) \ else if (strcmp(arg[2],#key) == 0) \ compute[ncompute] = new Class(lmp,narg,arg); #include "style_compute.h" #undef ComputeStyle #undef COMPUTE_CLASS else error->all(FLERR,"Invalid compute style"); } ncompute++; } /* ---------------------------------------------------------------------- modify a Compute's parameters ------------------------------------------------------------------------- */ void Modify::modify_compute(int narg, char **arg) { if (narg < 2) error->all(FLERR,"Illegal compute_modify command"); // lookup Compute ID int icompute; for (icompute = 0; icompute < ncompute; icompute++) if (strcmp(arg[0],compute[icompute]->id) == 0) break; if (icompute == ncompute) error->all(FLERR,"Could not find compute_modify ID"); compute[icompute]->modify_params(narg-1,&arg[1]); } /* ---------------------------------------------------------------------- delete a Compute from list of Computes ------------------------------------------------------------------------- */ -void Modify::delete_compute(char *id) +void Modify::delete_compute(const char *id) { int icompute = find_compute(id); if (icompute < 0) error->all(FLERR,"Could not find compute ID to delete"); delete compute[icompute]; // move other Computes down in list one slot for (int i = icompute+1; i < ncompute; i++) compute[i-1] = compute[i]; ncompute--; } /* ---------------------------------------------------------------------- find a compute by ID return index of compute or -1 if not found ------------------------------------------------------------------------- */ -int Modify::find_compute(char *id) +int Modify::find_compute(const char *id) { int icompute; for (icompute = 0; icompute < ncompute; icompute++) if (strcmp(id,compute[icompute]->id) == 0) break; if (icompute == ncompute) return -1; return icompute; } /* ---------------------------------------------------------------------- clear invoked flag of all computes called everywhere that computes are used, before computes are invoked invoked flag used to avoid re-invoking same compute multiple times and to flag computes that store invocation times as having been invoked ------------------------------------------------------------------------- */ void Modify::clearstep_compute() { for (int icompute = 0; icompute < ncompute; icompute++) compute[icompute]->invoked_flag = 0; } /* ---------------------------------------------------------------------- loop over computes that store invocation times if its invoked flag set on this timestep, schedule next invocation called everywhere that computes are used, after computes are invoked ------------------------------------------------------------------------- */ void Modify::addstep_compute(bigint newstep) { for (int icompute = 0; icompute < n_timeflag; icompute++) if (compute[list_timeflag[icompute]]->invoked_flag) compute[list_timeflag[icompute]]->addstep(newstep); } /* ---------------------------------------------------------------------- loop over all computes schedule next invocation for those that store invocation times called when not sure what computes will be needed on newstep do not loop only over n_timeflag, since may not be set yet ------------------------------------------------------------------------- */ void Modify::addstep_compute_all(bigint newstep) { for (int icompute = 0; icompute < ncompute; icompute++) if (compute[icompute]->timeflag) compute[icompute]->addstep(newstep); } /* ---------------------------------------------------------------------- write to restart file for all Fixes with restart info (1) fixes that have global state (2) fixes that store per-atom quantities ------------------------------------------------------------------------- */ void Modify::write_restart(FILE *fp) { int me = comm->me; int count = 0; for (int i = 0; i < nfix; i++) if (fix[i]->restart_global) count++; if (me == 0) fwrite(&count,sizeof(int),1,fp); int n; for (int i = 0; i < nfix; i++) if (fix[i]->restart_global) { if (me == 0) { n = strlen(fix[i]->id) + 1; fwrite(&n,sizeof(int),1,fp); fwrite(fix[i]->id,sizeof(char),n,fp); n = strlen(fix[i]->style) + 1; fwrite(&n,sizeof(int),1,fp); fwrite(fix[i]->style,sizeof(char),n,fp); } fix[i]->write_restart(fp); } count = 0; for (int i = 0; i < nfix; i++) if (fix[i]->restart_peratom) count++; if (me == 0) fwrite(&count,sizeof(int),1,fp); for (int i = 0; i < nfix; i++) if (fix[i]->restart_peratom) { if (me == 0) { n = strlen(fix[i]->id) + 1; fwrite(&n,sizeof(int),1,fp); fwrite(fix[i]->id,sizeof(char),n,fp); n = strlen(fix[i]->style) + 1; fwrite(&n,sizeof(int),1,fp); fwrite(fix[i]->style,sizeof(char),n,fp); n = fix[i]->maxsize_restart(); fwrite(&n,sizeof(int),1,fp); } } } /* ---------------------------------------------------------------------- read in restart file data on all previously defined Fixes with restart info (1) fixes that have global state (2) fixes that store per-atom quantities return maxsize of extra info that will be stored with any atom ------------------------------------------------------------------------- */ int Modify::read_restart(FILE *fp) { // nfix_restart_global = # of restart entries with global state info int me = comm->me; if (me == 0) fread(&nfix_restart_global,sizeof(int),1,fp); MPI_Bcast(&nfix_restart_global,1,MPI_INT,0,world); // allocate space for each entry if (nfix_restart_global) { id_restart_global = new char*[nfix_restart_global]; style_restart_global = new char*[nfix_restart_global]; state_restart_global = new char*[nfix_restart_global]; } // read each entry and Bcast to all procs // each entry has id string, style string, chunk of state data int n; for (int i = 0; i < nfix_restart_global; i++) { if (me == 0) fread(&n,sizeof(int),1,fp); MPI_Bcast(&n,1,MPI_INT,0,world); id_restart_global[i] = new char[n]; if (me == 0) fread(id_restart_global[i],sizeof(char),n,fp); MPI_Bcast(id_restart_global[i],n,MPI_CHAR,0,world); if (me == 0) fread(&n,sizeof(int),1,fp); MPI_Bcast(&n,1,MPI_INT,0,world); style_restart_global[i] = new char[n]; if (me == 0) fread(style_restart_global[i],sizeof(char),n,fp); MPI_Bcast(style_restart_global[i],n,MPI_CHAR,0,world); if (me == 0) fread(&n,sizeof(int),1,fp); MPI_Bcast(&n,1,MPI_INT,0,world); state_restart_global[i] = new char[n]; if (me == 0) fread(state_restart_global[i],sizeof(char),n,fp); MPI_Bcast(state_restart_global[i],n,MPI_CHAR,0,world); } // nfix_restart_peratom = # of restart entries with peratom info int maxsize = 0; if (me == 0) fread(&nfix_restart_peratom,sizeof(int),1,fp); MPI_Bcast(&nfix_restart_peratom,1,MPI_INT,0,world); // allocate space for each entry if (nfix_restart_peratom) { id_restart_peratom = new char*[nfix_restart_peratom]; style_restart_peratom = new char*[nfix_restart_peratom]; index_restart_peratom = new int[nfix_restart_peratom]; } // read each entry and Bcast to all procs // each entry has id string, style string, maxsize of one atom's data // set index = which set of extra data this fix represents for (int i = 0; i < nfix_restart_peratom; i++) { if (me == 0) fread(&n,sizeof(int),1,fp); MPI_Bcast(&n,1,MPI_INT,0,world); id_restart_peratom[i] = new char[n]; if (me == 0) fread(id_restart_peratom[i],sizeof(char),n,fp); MPI_Bcast(id_restart_peratom[i],n,MPI_CHAR,0,world); if (me == 0) fread(&n,sizeof(int),1,fp); MPI_Bcast(&n,1,MPI_INT,0,world); style_restart_peratom[i] = new char[n]; if (me == 0) fread(style_restart_peratom[i],sizeof(char),n,fp); MPI_Bcast(style_restart_peratom[i],n,MPI_CHAR,0,world); if (me == 0) fread(&n,sizeof(int),1,fp); MPI_Bcast(&n,1,MPI_INT,0,world); maxsize += n; index_restart_peratom[i] = i; } return maxsize; } /* ---------------------------------------------------------------------- delete all lists of restart file Fix info ------------------------------------------------------------------------- */ void Modify::restart_deallocate() { if (nfix_restart_global) { for (int i = 0; i < nfix_restart_global; i++) { delete [] id_restart_global[i]; delete [] style_restart_global[i]; delete [] state_restart_global[i]; } delete [] id_restart_global; delete [] style_restart_global; delete [] state_restart_global; } if (nfix_restart_peratom) { for (int i = 0; i < nfix_restart_peratom; i++) { delete [] id_restart_peratom[i]; delete [] style_restart_peratom[i]; } delete [] id_restart_peratom; delete [] style_restart_peratom; delete [] index_restart_peratom; } nfix_restart_global = nfix_restart_peratom = 0; } /* ---------------------------------------------------------------------- create list of fix indices for fixes which match mask ------------------------------------------------------------------------- */ void Modify::list_init(int mask, int &n, int *&list) { delete [] list; n = 0; for (int i = 0; i < nfix; i++) if (fmask[i] & mask) n++; list = new int[n]; n = 0; for (int i = 0; i < nfix; i++) if (fmask[i] & mask) list[n++] = i; } /* ---------------------------------------------------------------------- create list of fix indices for end_of_step fixes also create end_of_step_every[] ------------------------------------------------------------------------- */ void Modify::list_init_end_of_step(int mask, int &n, int *&list) { delete [] list; delete [] end_of_step_every; n = 0; for (int i = 0; i < nfix; i++) if (fmask[i] & mask) n++; list = new int[n]; end_of_step_every = new int[n]; n = 0; for (int i = 0; i < nfix; i++) if (fmask[i] & mask) { list[n] = i; end_of_step_every[n++] = fix[i]->nevery; } } /* ---------------------------------------------------------------------- create list of fix indices for thermo energy fixes only added to list if fix has THERMO_ENERGY mask and its thermo_energy flag was set via fix_modify ------------------------------------------------------------------------- */ void Modify::list_init_thermo_energy(int mask, int &n, int *&list) { delete [] list; n = 0; for (int i = 0; i < nfix; i++) if (fmask[i] & mask && fix[i]->thermo_energy) n++; list = new int[n]; n = 0; for (int i = 0; i < nfix; i++) if (fmask[i] & mask && fix[i]->thermo_energy) list[n++] = i; } /* ---------------------------------------------------------------------- create list of compute indices for computes which store invocation times ------------------------------------------------------------------------- */ void Modify::list_init_compute() { delete [] list_timeflag; n_timeflag = 0; for (int i = 0; i < ncompute; i++) if (compute[i]->timeflag) n_timeflag++; list_timeflag = new int[n_timeflag]; n_timeflag = 0; for (int i = 0; i < ncompute; i++) if (compute[i]->timeflag) list_timeflag[n_timeflag++] = i; } /* ---------------------------------------------------------------------- return # of bytes of allocated memory from all fixes ------------------------------------------------------------------------- */ bigint Modify::memory_usage() { bigint bytes = 0; for (int i = 0; i < nfix; i++) bytes += static_cast (fix[i]->memory_usage()); for (int i = 0; i < ncompute; i++) bytes += static_cast (compute[i]->memory_usage()); return bytes; } diff --git a/src/modify.h b/src/modify.h index 21c298143..695d31429 100644 --- a/src/modify.h +++ b/src/modify.h @@ -1,206 +1,206 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ #ifndef LMP_MODIFY_H #define LMP_MODIFY_H #include "stdio.h" #include "pointers.h" namespace LAMMPS_NS { class Modify : protected Pointers { public: int nfix,maxfix; int n_initial_integrate,n_post_integrate,n_pre_exchange,n_pre_neighbor; int n_pre_force,n_post_force; int n_final_integrate,n_end_of_step,n_thermo_energy; int n_initial_integrate_respa,n_post_integrate_respa; int n_pre_force_respa,n_post_force_respa,n_final_integrate_respa; int n_min_pre_exchange,n_min_pre_force,n_min_post_force,n_min_energy; int restart_pbc_any; // 1 if any fix sets restart_pbc int nfix_restart_global; // stored fix global info from restart file int nfix_restart_peratom; // stored fix peratom info from restart file int allow_early_fix; // 1 if allow fix creation at start of script class Fix **fix; // list of fixes int *fmask; // bit mask for when each fix is applied int ncompute,maxcompute; // list of computes class Compute **compute; Modify(class LAMMPS *); virtual ~Modify(); virtual void init(); virtual void setup(int); virtual void setup_pre_exchange(); virtual void setup_pre_force(int); virtual void initial_integrate(int); virtual void post_integrate(); void pre_decide(); virtual void pre_exchange(); virtual void pre_neighbor(); virtual void pre_force(int); virtual void post_force(int); virtual void final_integrate(); virtual void end_of_step(); virtual double thermo_energy(); virtual void post_run(); void setup_pre_force_respa(int, int); void initial_integrate_respa(int, int, int); void post_integrate_respa(int, int); void pre_force_respa(int, int, int); void post_force_respa(int, int, int); void final_integrate_respa(int, int); void setup_min_pre_force(int); void min_pre_exchange(); void min_pre_force(int); void min_post_force(int); double min_energy(double *); void min_store(); void min_step(double, double *); void min_clearstore(); void min_pushstore(); void min_popstore(); int min_reset_ref(); double max_alpha(double *); int min_dof(); void add_fix(int, char **, char *suffix = NULL); void modify_fix(int, char **); void delete_fix(const char *); int find_fix(const char *); void add_compute(int, char **, char *suffix = NULL); void modify_compute(int, char **); - void delete_compute(char *); - int find_compute(char *); + void delete_compute(const char *); + int find_compute(const char *); void clearstep_compute(); void addstep_compute(bigint); void addstep_compute_all(bigint); void write_restart(FILE *); int read_restart(FILE *); void restart_deallocate(); bigint memory_usage(); protected: // lists of fixes to apply at different stages of timestep int *list_initial_integrate,*list_post_integrate; int *list_pre_exchange,*list_pre_neighbor; int *list_pre_force,*list_post_force; int *list_final_integrate,*list_end_of_step,*list_thermo_energy; int *list_initial_integrate_respa,*list_post_integrate_respa; int *list_pre_force_respa,*list_post_force_respa; int *list_final_integrate_respa; int *list_min_pre_exchange,*list_min_pre_force; int *list_min_post_force,*list_min_energy; int *end_of_step_every; int n_timeflag; // list of computes that store time invocation int *list_timeflag; char **id_restart_global; // stored fix global info char **style_restart_global; // from read-in restart file char **state_restart_global; char **id_restart_peratom; // stored fix peratom info char **style_restart_peratom; // from read-in restart file int *index_restart_peratom; int index_permanent; // fix/compute index returned to library call void list_init(int, int &, int *&); void list_init_end_of_step(int, int &, int *&); void list_init_thermo_energy(int, int &, int *&); void list_init_compute(); }; } #endif /* ERROR/WARNING messages: W: One or more atoms are time integrated more than once This is probably an error since you typically do not want to advance the positions or velocities of an atom more than once per timestep. E: Fix command before simulation box is defined The fix command cannot be used before a read_data, read_restart, or create_box command. E: Illegal ... command Self-explanatory. Check the input script syntax and compare to the documentation for the command. You can use -echo screen as a command-line option when running LAMMPS to see the offending line. E: Could not find fix group ID A group ID used in the fix command does not exist. E: Replacing a fix, but new style != old style A fix ID can be used a 2nd time, but only if the style matches the previous fix. In this case it is assumed you with to reset a fix's parameters. This error may mean you are mistakenly re-using a fix ID when you do not intend to. W: Replacing a fix, but new group != old group The ID and style of a fix match for a fix you are changing with a fix command, but the new group you are specifying does not match the old group. E: Invalid fix style The choice of fix style is unknown. E: Could not find fix_modify ID A fix ID used in the fix_modify command does not exist. E: Could not find fix ID to delete Self-explanatory. E: Reuse of compute ID A compute ID cannot be used twice. E: Invalid compute style Self-explanatory. E: Could not find compute_modify ID Self-explanatory. E: Could not find compute ID to delete Self-explanatory. */ diff --git a/src/pair.h b/src/pair.h index a1dca5c74..756c894de 100644 --- a/src/pair.h +++ b/src/pair.h @@ -1,253 +1,253 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ #ifndef LMP_PAIR_H #define LMP_PAIR_H #include "pointers.h" namespace LAMMPS_NS { class Pair : protected Pointers { friend class AngleSDK; friend class AngleSDKOMP; friend class BondQuartic; friend class BondQuarticOMP; friend class DihedralCharmm; friend class DihedralCharmmOMP; friend class FixGPU; friend class ThrOMP; public: double eng_vdwl,eng_coul; // accumulated energies double virial[6]; // accumulated virial double *eatom,**vatom; // accumulated per-atom energy/virial double cutforce; // max cutoff for all atom pairs double **cutsq; // cutoff sq for each atom pair int **setflag; // 0/1 = whether each i,j has been set int comm_forward; // size of forward communication (0 if none) int comm_reverse; // size of reverse communication (0 if none) int single_enable; // 1 if single() routine exists int restartinfo; // 1 if pair style writes restart info int respa_enable; // 1 if inner/middle/outer rRESPA routines int one_coeff; // 1 if allows only one coeff * * call int no_virial_fdotr_compute; // 1 if does not invoke virial_fdotr_compute() int ghostneigh; // 1 if pair style needs neighbors of ghosts double **cutghost; // cutoff for each ghost pair int tail_flag; // pair_modify flag for LJ tail correction double etail,ptail; // energy/pressure tail corrections double etail_ij,ptail_ij; int nextra; // # of extra quantities pair style calculates double *pvector; // vector of extra pair quantities int single_extra; // number of extra single values calculated double *svector; // vector of extra single quantities class NeighList *list; // standard neighbor list used by most pairs class NeighList *listhalf; // half list used by some pairs class NeighList *listfull; // full list used by some pairs class NeighList *listgranhistory; // granular history list used by some pairs class NeighList *listinner; // rRESPA lists used by some pairs class NeighList *listmiddle; class NeighList *listouter; Pair(class LAMMPS *); virtual ~Pair(); // top-level Pair methods void init(); void reinit(); double mix_energy(double, double, double, double); double mix_distance(double, double); void write_file(int, char **); void init_bitmap(double, double, int, int &, int &, int &, int &); virtual void modify_params(int, char **); // need to be public, so can be called by pair_style reaxc void v_tally(int, double *); void ev_tally(int, int, int, int, double, double, double, double, double, double); void ev_tally3(int, int, int, double, double, double *, double *, double *, double *); void v_tally3(int, int, int, double *, double *, double *, double *); void v_tally4(int, int, int, int, double *, double *, double *, double *, double *, double *); // general child-class methods virtual void compute(int, int) = 0; virtual void compute_inner() {} virtual void compute_middle() {} virtual void compute_outer(int, int) {} virtual double single(int, int, int, int, double, double, double, double &) {return 0.0;} virtual void settings(int, char **) = 0; virtual void coeff(int, char **) = 0; virtual void init_style(); virtual void init_list(int, class NeighList *); virtual double init_one(int, int) {return 0.0;} virtual void write_restart(FILE *) {} virtual void read_restart(FILE *) {} virtual void write_restart_settings(FILE *) {} virtual void read_restart_settings(FILE *) {} virtual int pack_comm(int, int *, double *, int, int *) {return 0;} virtual void unpack_comm(int, int, double *) {} virtual int pack_reverse_comm(int, int, double *) {return 0;} virtual void unpack_reverse_comm(int, int *, double *) {} virtual double memory_usage(); // specific child-class methods for certain Pair styles - virtual void *extract(char *, int &) {return NULL;} + virtual void *extract(const char *, int &) {return NULL;} virtual void swap_eam(double *, double **) {} virtual void reset_dt() {} virtual void min_xf_pointers(int, double **, double **) {} virtual void min_xf_get(int) {} virtual void min_x_set(int) {} protected: int allocated; // 0/1 = whether arrays are allocated // pair_modify settings int offset_flag,mix_flag; // flags for offset and mixing int ncoultablebits; // size of Coulomb table double tabinner; // inner cutoff for Coulomb table // custom data type for accessing Coulomb tables typedef union {int i; float f;} union_int_float_t; double THIRD; int evflag; // energy,virial settings int eflag_either,eflag_global,eflag_atom; int vflag_either,vflag_global,vflag_atom; int vflag_fdotr; int maxeatom,maxvatom; virtual void ev_setup(int, int); void ev_tally_full(int, double, double, double, double, double, double); void ev_tally_xyz(int, int, int, int, double, double, double, double, double, double, double, double); void ev_tally_xyz_full(int, double, double, double, double, double, double, double, double); void ev_tally4(int, int, int, int, double, double *, double *, double *, double *, double *, double *); void ev_tally_list(int, int *, double, double *); void v_tally2(int, int, double, double *); void v_tally_tensor(int, int, int, int, double, double, double, double, double, double); void virial_fdotr_compute(); inline int sbmask(int j) { return j >> SBBITS & 3; } }; } #endif /* ERROR/WARNING messages: E: Illegal ... command Self-explanatory. Check the input script syntax and compare to the documentation for the command. You can use -echo screen as a command-line option when running LAMMPS to see the offending line. E: Too many total bits for bitmapped lookup table Table size specified via pair_modify command is too large. Note that a value of N generates a 2^N size table. E: Cannot have both pair_modify shift and tail set to yes These 2 options are contradictory. E: Cannot use pair tail corrections with 2d simulations The correction factors are only currently defined for 3d systems. W: Using pair tail corrections with nonperiodic system This is probably a bogus thing to do, since tail corrections are computed by integrating the density of a periodic system out to infinity. E: All pair coeffs are not set All pair coefficients must be set in the data file or by the pair_coeff command before running a simulation. E: Pair style does not support pair_write The pair style does not have a single() function, so it can not be invoked by pair write. E: Invalid atom types in pair_write command Atom types must range from 1 to Ntypes inclusive. E: Invalid style in pair_write command Self-explanatory. Check the input script. E: Invalid cutoffs in pair_write command Inner cutoff must be larger than 0.0 and less than outer cutoff. E: Cannot open pair_write file The specified output file for pair energies and forces cannot be opened. Check that the path and name are correct. E: Bitmapped lookup tables require int/float be same size Cannot use pair tables on this machine, because of word sizes. Use the pair_modify command with table 0 instead. W: Table inner cutoff >= outer cutoff You specified an inner cutoff for a Coulombic table that is longer than the global cutoff. Probably not what you wanted. E: Too many exponent bits for lookup table Table size specified via pair_modify command does not work with your machine's floating point representation. E: Too many mantissa bits for lookup table Table size specified via pair_modify command does not work with your machine's floating point representation. E: Too few bits for lookup table Table size specified via pair_modify command does not work with your machine's floating point representation. */ diff --git a/src/pair_born.cpp b/src/pair_born.cpp index 271b7b1f7..68905a95d 100644 --- a/src/pair_born.cpp +++ b/src/pair_born.cpp @@ -1,409 +1,409 @@ /* ---------------------------------------------------------------------- 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 Author: Sai Jayaraman (Sandia) ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "pair_born.h" #include "atom.h" #include "comm.h" #include "force.h" #include "neigh_list.h" #include "math_const.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace MathConst; /* ---------------------------------------------------------------------- */ PairBorn::PairBorn(LAMMPS *lmp) : Pair(lmp) {} /* ---------------------------------------------------------------------- */ PairBorn::~PairBorn() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut); memory->destroy(a); memory->destroy(rho); memory->destroy(sigma); memory->destroy(c); memory->destroy(d); memory->destroy(rhoinv); memory->destroy(born1); memory->destroy(born2); memory->destroy(born3); memory->destroy(offset); } } /* ---------------------------------------------------------------------- */ void PairBorn::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair; double rsq,r2inv,r6inv,forceborn,factor_lj; double r,rexp; int *ilist,*jlist,*numneigh,**firstneigh; evdwl = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; double **x = atom->x; double **f = atom->f; int *type = atom->type; int nlocal = atom->nlocal; double *special_lj = force->special_lj; int newton_pair = force->newton_pair; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // loop over neighbors of my atoms for (ii = 0; ii < inum; ii++) { i = ilist[ii]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; factor_lj = special_lj[sbmask(j)]; j &= NEIGHMASK; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; jtype = type[j]; if (rsq < cutsq[itype][jtype]) { r2inv = 1.0/rsq; r6inv = r2inv*r2inv*r2inv; r = sqrt(rsq); rexp = exp((sigma[itype][jtype]-r)*rhoinv[itype][jtype]); forceborn = born1[itype][jtype]*r*rexp - born2[itype][jtype]*r6inv + born3[itype][jtype]*r2inv*r6inv; fpair = factor_lj*forceborn*r2inv; f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; if (newton_pair || j < nlocal) { f[j][0] -= delx*fpair; f[j][1] -= dely*fpair; f[j][2] -= delz*fpair; } if (eflag) { evdwl = a[itype][jtype]*rexp - c[itype][jtype]*r6inv + d[itype][jtype]*r6inv*r2inv - offset[itype][jtype]; evdwl *= factor_lj; } if (evflag) ev_tally(i,j,nlocal,newton_pair, evdwl,0.0,fpair,delx,dely,delz); } } } if (vflag_fdotr) virial_fdotr_compute(); } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairBorn::allocate() { allocated = 1; int n = atom->ntypes; memory->create(setflag,n+1,n+1,"pair:setflag"); for (int i = 1; i <= n; i++) for (int j = i; j <= n; j++) setflag[i][j] = 0; memory->create(cutsq,n+1,n+1,"pair:cutsq"); memory->create(cut,n+1,n+1,"pair:cut"); memory->create(a,n+1,n+1,"pair:a"); memory->create(rho,n+1,n+1,"pair:rho"); memory->create(sigma,n+1,n+1,"pair:sigma"); memory->create(c,n+1,n+1,"pair:c"); memory->create(d,n+1,n+1,"pair:d"); memory->create(rhoinv,n+1,n+1,"pair:rhoinv"); memory->create(born1,n+1,n+1,"pair:born1"); memory->create(born2,n+1,n+1,"pair:born2"); memory->create(born3,n+1,n+1,"pair:born3"); memory->create(offset,n+1,n+1,"pair:offset"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairBorn::settings(int narg, char **arg) { if (narg != 1) error->all(FLERR,"Illegal pair_style command"); cut_global = atof(arg[0]); // reset cutoffs that have been explicitly set if (allocated) { int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i+1; j <= atom->ntypes; j++) if (setflag[i][j]) cut[i][j] = cut_global; } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairBorn::coeff(int narg, char **arg) { if (narg < 7 || narg > 8) error->all(FLERR,"Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); double a_one = force->numeric(arg[2]); double rho_one = force->numeric(arg[3]); double sigma_one = force->numeric(arg[4]); if (rho_one <= 0) error->all(FLERR,"Incorrect args for pair coefficients"); double c_one = force->numeric(arg[5]); double d_one = force->numeric(arg[6]); double cut_one = cut_global; if (narg == 8) cut_one = force->numeric(arg[7]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { a[i][j] = a_one; rho[i][j] = rho_one; sigma[i][j] = sigma_one; c[i][j] = c_one; d[i][j] = d_one; cut[i][j] = cut_one; setflag[i][j] = 1; count++; } } if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairBorn::init_one(int i, int j) { if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set"); rhoinv[i][j] = 1.0/rho[i][j]; born1[i][j] = a[i][j]/rho[i][j]; born2[i][j] = 6.0*c[i][j]; born3[i][j] = 8.0*d[i][j]; if (offset_flag) { double rexp = exp((sigma[i][j]-cut[i][j])*rhoinv[i][j]); offset[i][j] = a[i][j]*rexp - c[i][j]/pow(cut[i][j],6.0) + d[i][j]/pow(cut[i][j],8.0); } else offset[i][j] = 0.0; a[j][i] = a[i][j]; c[j][i] = c[i][j]; d[j][i] = d[i][j]; rhoinv[j][i] = rhoinv[i][j]; sigma[j][i] = sigma[i][j]; born1[j][i] = born1[i][j]; born2[j][i] = born2[i][j]; born3[j][i] = born3[i][j]; offset[j][i] = offset[i][j]; // compute I,J contribution to long-range tail correction // count total # of atoms of type I and J via Allreduce if (tail_flag) { int *type = atom->type; int nlocal = atom->nlocal; double count[2],all[2]; count[0] = count[1] = 0.0; for (int k = 0; k < nlocal; k++) { if (type[k] == i) count[0] += 1.0; if (type[k] == j) count[1] += 1.0; } MPI_Allreduce(count,all,2,MPI_DOUBLE,MPI_SUM,world); double rho1 = rho[i][j]; double rho2 = rho1*rho1; double rho3 = rho2*rho1; double rc = cut[i][j]; double rc2 = rc*rc; double rc3 = rc2*rc; double rc5 = rc3*rc2; etail_ij = 2.0*MY_PI*all[0]*all[1] * (a[i][j]*exp((sigma[i][j]-rc)/rho1)*rho1* (rc2 + 2.0*rho1*rc + 2.0*rho2) - c[i][j]/(3.0*rc3) + d[i][j]/(5.0*rc5)); ptail_ij = (-1/3.0)*2.0*MY_PI*all[0]*all[1] * (-a[i][j]*exp((sigma[i][j]-rc)/rho1) * (rc3 + 3.0*rho1*rc2 + 6.0*rho2*rc + 6.0*rho3) + 2.0*c[i][j]/rc3 - 8.0*d[i][j]/(5.0*rc5)); } return cut[i][j]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairBorn::write_restart(FILE *fp) { write_restart_settings(fp); int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { fwrite(&setflag[i][j],sizeof(int),1,fp); if (setflag[i][j]) { fwrite(&a[i][j],sizeof(double),1,fp); fwrite(&rho[i][j],sizeof(double),1,fp); fwrite(&sigma[i][j],sizeof(double),1,fp); fwrite(&c[i][j],sizeof(double),1,fp); fwrite(&d[i][j],sizeof(double),1,fp); fwrite(&cut[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairBorn::read_restart(FILE *fp) { read_restart_settings(fp); allocate(); int i,j; int me = comm->me; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp); MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world); if (setflag[i][j]) { if (me == 0) { fread(&a[i][j],sizeof(double),1,fp); fread(&rho[i][j],sizeof(double),1,fp); fread(&sigma[i][j],sizeof(double),1,fp); fread(&c[i][j],sizeof(double),1,fp); fread(&d[i][j],sizeof(double),1,fp); fread(&cut[i][j],sizeof(double),1,fp); } MPI_Bcast(&a[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&rho[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&c[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&d[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairBorn::write_restart_settings(FILE *fp) { fwrite(&cut_global,sizeof(double),1,fp); fwrite(&offset_flag,sizeof(int),1,fp); fwrite(&mix_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairBorn::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&cut_global,sizeof(double),1,fp); fread(&offset_flag,sizeof(int),1,fp); fread(&mix_flag,sizeof(int),1,fp); } MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world); MPI_Bcast(&offset_flag,1,MPI_INT,0,world); MPI_Bcast(&mix_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- */ double PairBorn::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r2inv,r6inv,r,rexp,forceborn,phiborn; r2inv = 1.0/rsq; r6inv = r2inv*r2inv*r2inv; r = sqrt(rsq); rexp = exp((sigma[itype][jtype]-r)*rhoinv[itype][jtype]); forceborn = born1[itype][jtype]*r*rexp - born2[itype][jtype]*r6inv + born3[itype][jtype]*r2inv*r6inv; fforce = factor_lj*forceborn*r2inv; phiborn = a[itype][jtype]*rexp - c[itype][jtype]*r6inv + d[itype][jtype]*r2inv*r6inv - offset[itype][jtype]; return factor_lj*phiborn; } /* ---------------------------------------------------------------------- */ -void *PairBorn::extract(char *str, int &dim) +void *PairBorn::extract(const char *str, int &dim) { dim = 2; if (strcmp(str,"a") == 0) return (void *) a; if (strcmp(str,"c") == 0) return (void *) c; if (strcmp(str,"d") == 0) return (void *) d; return NULL; } diff --git a/src/pair_born.h b/src/pair_born.h index bc5943d3d..566fdc7c4 100644 --- a/src/pair_born.h +++ b/src/pair_born.h @@ -1,74 +1,74 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ #ifdef PAIR_CLASS PairStyle(born,PairBorn) #else #ifndef PAIR_BORN_H #define PAIR_BORN_H #include "pair.h" namespace LAMMPS_NS { class PairBorn : public Pair { public: PairBorn(class LAMMPS *); virtual ~PairBorn(); virtual void compute(int, int); void settings(int, char **); void coeff(int, char **); double init_one(int, int); void write_restart(FILE *); void read_restart(FILE *); void write_restart_settings(FILE *); void read_restart_settings(FILE *); double single(int, int, int, int, double, double, double, double &); - void *extract(char *, int &); + void *extract(const char *, int &); protected: double cut_global; double **cut; double **a,**rho,**sigma,**c, **d; double **rhoinv,**born1,**born2,**born3,**offset; void allocate(); }; } #endif #endif /* ERROR/WARNING messages: E: Illegal ... command Self-explanatory. Check the input script syntax and compare to the documentation for the command. You can use -echo screen as a command-line option when running LAMMPS to see the offending line. E: Incorrect args for pair coefficients Self-explanatory. Check the input script or data file. E: All pair coeffs are not set All pair coefficients must be set in the data file or by the pair_coeff command before running a simulation. */ diff --git a/src/pair_buck.cpp b/src/pair_buck.cpp index 1a3464e27..abd3d2dad 100644 --- a/src/pair_buck.cpp +++ b/src/pair_buck.cpp @@ -1,378 +1,378 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "pair_buck.h" #include "atom.h" #include "comm.h" #include "force.h" #include "neigh_list.h" #include "math_const.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace MathConst; /* ---------------------------------------------------------------------- */ PairBuck::PairBuck(LAMMPS *lmp) : Pair(lmp) {} /* ---------------------------------------------------------------------- */ PairBuck::~PairBuck() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut); memory->destroy(a); memory->destroy(rho); memory->destroy(c); memory->destroy(rhoinv); memory->destroy(buck1); memory->destroy(buck2); memory->destroy(offset); } } /* ---------------------------------------------------------------------- */ void PairBuck::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair; double rsq,r2inv,r6inv,forcebuck,factor_lj; double r,rexp; int *ilist,*jlist,*numneigh,**firstneigh; evdwl = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; double **x = atom->x; double **f = atom->f; int *type = atom->type; int nlocal = atom->nlocal; double *special_lj = force->special_lj; int newton_pair = force->newton_pair; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // loop over neighbors of my atoms for (ii = 0; ii < inum; ii++) { i = ilist[ii]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; factor_lj = special_lj[sbmask(j)]; j &= NEIGHMASK; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; jtype = type[j]; if (rsq < cutsq[itype][jtype]) { r2inv = 1.0/rsq; r6inv = r2inv*r2inv*r2inv; r = sqrt(rsq); rexp = exp(-r*rhoinv[itype][jtype]); forcebuck = buck1[itype][jtype]*r*rexp - buck2[itype][jtype]*r6inv; fpair = factor_lj*forcebuck*r2inv; f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; if (newton_pair || j < nlocal) { f[j][0] -= delx*fpair; f[j][1] -= dely*fpair; f[j][2] -= delz*fpair; } if (eflag) { evdwl = a[itype][jtype]*rexp - c[itype][jtype]*r6inv - offset[itype][jtype]; evdwl *= factor_lj; } if (evflag) ev_tally(i,j,nlocal,newton_pair, evdwl,0.0,fpair,delx,dely,delz); } } } if (vflag_fdotr) virial_fdotr_compute(); } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairBuck::allocate() { allocated = 1; int n = atom->ntypes; memory->create(setflag,n+1,n+1,"pair:setflag"); for (int i = 1; i <= n; i++) for (int j = i; j <= n; j++) setflag[i][j] = 0; memory->create(cutsq,n+1,n+1,"pair:cutsq"); memory->create(cut,n+1,n+1,"pair:cut_lj"); memory->create(a,n+1,n+1,"pair:a"); memory->create(rho,n+1,n+1,"pair:rho"); memory->create(c,n+1,n+1,"pair:c"); memory->create(rhoinv,n+1,n+1,"pair:rhoinv"); memory->create(buck1,n+1,n+1,"pair:buck1"); memory->create(buck2,n+1,n+1,"pair:buck2"); memory->create(offset,n+1,n+1,"pair:offset"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairBuck::settings(int narg, char **arg) { if (narg != 1) error->all(FLERR,"Illegal pair_style command"); cut_global = force->numeric(arg[0]); // reset cutoffs that have been explicitly set if (allocated) { int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i+1; j <= atom->ntypes; j++) if (setflag[i][j]) cut[i][j] = cut_global; } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairBuck::coeff(int narg, char **arg) { if (narg < 5 || narg > 6) error->all(FLERR,"Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); double a_one = force->numeric(arg[2]); double rho_one = force->numeric(arg[3]); if (rho_one <= 0) error->all(FLERR,"Incorrect args for pair coefficients"); double c_one = force->numeric(arg[4]); double cut_one = cut_global; if (narg == 6) cut_one = force->numeric(arg[5]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { a[i][j] = a_one; rho[i][j] = rho_one; c[i][j] = c_one; cut[i][j] = cut_one; setflag[i][j] = 1; count++; } } if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairBuck::init_one(int i, int j) { if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set"); rhoinv[i][j] = 1.0/rho[i][j]; buck1[i][j] = a[i][j]/rho[i][j]; buck2[i][j] = 6.0*c[i][j]; if (offset_flag) { double rexp = exp(-cut[i][j]/rho[i][j]); offset[i][j] = a[i][j]*rexp - c[i][j]/pow(cut[i][j],6.0); } else offset[i][j] = 0.0; a[j][i] = a[i][j]; c[j][i] = c[i][j]; rhoinv[j][i] = rhoinv[i][j]; buck1[j][i] = buck1[i][j]; buck2[j][i] = buck2[i][j]; offset[j][i] = offset[i][j]; // compute I,J contribution to long-range tail correction // count total # of atoms of type I and J via Allreduce if (tail_flag) { int *type = atom->type; int nlocal = atom->nlocal; double count[2],all[2]; count[0] = count[1] = 0.0; for (int k = 0; k < nlocal; k++) { if (type[k] == i) count[0] += 1.0; if (type[k] == j) count[1] += 1.0; } MPI_Allreduce(count,all,2,MPI_DOUBLE,MPI_SUM,world); double rho1 = rho[i][j]; double rho2 = rho1*rho1; double rho3 = rho2*rho1; double rc = cut[i][j]; double rc2 = rc*rc; double rc3 = rc2*rc; etail_ij = 2.0*MY_PI*all[0]*all[1]* (a[i][j]*exp(-rc/rho1)*rho1*(rc2 + 2.0*rho1*rc + 2.0*rho2) - c[i][j]/(3.0*rc3)); ptail_ij = (-1/3.0)*2.0*MY_PI*all[0]*all[1]* (-a[i][j]*exp(-rc/rho1)* (rc3 + 3.0*rho1*rc2 + 6.0*rho2*rc + 6.0*rho3) + 2.0*c[i][j]/rc3); } return cut[i][j]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairBuck::write_restart(FILE *fp) { write_restart_settings(fp); int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { fwrite(&setflag[i][j],sizeof(int),1,fp); if (setflag[i][j]) { fwrite(&a[i][j],sizeof(double),1,fp); fwrite(&rho[i][j],sizeof(double),1,fp); fwrite(&c[i][j],sizeof(double),1,fp); fwrite(&cut[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairBuck::read_restart(FILE *fp) { read_restart_settings(fp); allocate(); int i,j; int me = comm->me; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp); MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world); if (setflag[i][j]) { if (me == 0) { fread(&a[i][j],sizeof(double),1,fp); fread(&rho[i][j],sizeof(double),1,fp); fread(&c[i][j],sizeof(double),1,fp); fread(&cut[i][j],sizeof(double),1,fp); } MPI_Bcast(&a[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&rho[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&c[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairBuck::write_restart_settings(FILE *fp) { fwrite(&cut_global,sizeof(double),1,fp); fwrite(&offset_flag,sizeof(int),1,fp); fwrite(&mix_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairBuck::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&cut_global,sizeof(double),1,fp); fread(&offset_flag,sizeof(int),1,fp); fread(&mix_flag,sizeof(int),1,fp); } MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world); MPI_Bcast(&offset_flag,1,MPI_INT,0,world); MPI_Bcast(&mix_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- */ double PairBuck::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r2inv,r6inv,r,rexp,forcebuck,phibuck; r2inv = 1.0/rsq; r6inv = r2inv*r2inv*r2inv; r = sqrt(rsq); rexp = exp(-r*rhoinv[itype][jtype]); forcebuck = buck1[itype][jtype]*r*rexp - buck2[itype][jtype]*r6inv; fforce = factor_lj*forcebuck*r2inv; phibuck = a[itype][jtype]*rexp - c[itype][jtype]*r6inv - offset[itype][jtype]; return factor_lj*phibuck; } /* ---------------------------------------------------------------------- */ -void *PairBuck::extract(char *str, int &dim) +void *PairBuck::extract(const char *str, int &dim) { dim = 2; if (strcmp(str,"a") == 0) return (void *) a; if (strcmp(str,"c") == 0) return (void *) c; return NULL; } diff --git a/src/pair_buck.h b/src/pair_buck.h index 4feeaae2b..fe9034329 100644 --- a/src/pair_buck.h +++ b/src/pair_buck.h @@ -1,73 +1,73 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ #ifdef PAIR_CLASS PairStyle(buck,PairBuck) #else #ifndef LMP_PAIR_BUCK_H #define LMP_PAIR_BUCK_H #include "pair.h" namespace LAMMPS_NS { class PairBuck : public Pair { public: PairBuck(class LAMMPS *); virtual ~PairBuck(); virtual void compute(int, int); void settings(int, char **); void coeff(int, char **); double init_one(int, int); void write_restart(FILE *); void read_restart(FILE *); void write_restart_settings(FILE *); void read_restart_settings(FILE *); double single(int, int, int, int, double, double, double, double &); - void *extract(char *, int &); + void *extract(const char *, int &); protected: double cut_global; double **cut; double **a,**rho,**c; double **rhoinv,**buck1,**buck2,**offset; void allocate(); }; } #endif #endif /* ERROR/WARNING messages: E: Illegal ... command Self-explanatory. Check the input script syntax and compare to the documentation for the command. You can use -echo screen as a command-line option when running LAMMPS to see the offending line. E: Incorrect args for pair coefficients Self-explanatory. Check the input script or data file. E: All pair coeffs are not set All pair coefficients must be set in the data file or by the pair_coeff command before running a simulation. */ diff --git a/src/pair_coul_cut.cpp b/src/pair_coul_cut.cpp index fbe2bfdfc..2fb10dabd 100644 --- a/src/pair_coul_cut.cpp +++ b/src/pair_coul_cut.cpp @@ -1,308 +1,308 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "pair_coul_cut.h" #include "atom.h" #include "comm.h" #include "force.h" #include "neighbor.h" #include "neigh_list.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ PairCoulCut::PairCoulCut(LAMMPS *lmp) : Pair(lmp) {} /* ---------------------------------------------------------------------- */ PairCoulCut::~PairCoulCut() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut); memory->destroy(scale); } } /* ---------------------------------------------------------------------- */ void PairCoulCut::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,ecoul,fpair; double rsq,r2inv,rinv,forcecoul,factor_coul; int *ilist,*jlist,*numneigh,**firstneigh; ecoul = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; double **x = atom->x; double **f = atom->f; double *q = atom->q; int *type = atom->type; int nlocal = atom->nlocal; double *special_coul = force->special_coul; int newton_pair = force->newton_pair; double qqrd2e = force->qqrd2e; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // loop over neighbors of my atoms for (ii = 0; ii < inum; ii++) { i = ilist[ii]; qtmp = q[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; factor_coul = special_coul[sbmask(j)]; j &= NEIGHMASK; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; jtype = type[j]; if (rsq < cutsq[itype][jtype]) { r2inv = 1.0/rsq; rinv = sqrt(r2inv); forcecoul = qqrd2e * scale[itype][jtype] * qtmp*q[j]*rinv; fpair = factor_coul*forcecoul * r2inv; f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; if (newton_pair || j < nlocal) { f[j][0] -= delx*fpair; f[j][1] -= dely*fpair; f[j][2] -= delz*fpair; } if (eflag) ecoul = factor_coul * qqrd2e * scale[itype][jtype] * qtmp*q[j]*rinv; if (evflag) ev_tally(i,j,nlocal,newton_pair, 0.0,ecoul,fpair,delx,dely,delz); } } } if (vflag_fdotr) virial_fdotr_compute(); } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairCoulCut::allocate() { allocated = 1; int n = atom->ntypes; memory->create(setflag,n+1,n+1,"pair:setflag"); for (int i = 1; i <= n; i++) for (int j = i; j <= n; j++) setflag[i][j] = 0; memory->create(cutsq,n+1,n+1,"pair:cutsq"); memory->create(cut,n+1,n+1,"pair:cut"); memory->create(scale,n+1,n+1,"pair:scale"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairCoulCut::settings(int narg, char **arg) { if (narg != 1) error->all(FLERR,"Illegal pair_style command"); cut_global = force->numeric(arg[0]); // reset cutoffs that have been explicitly set if (allocated) { int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i+1; j <= atom->ntypes; j++) if (setflag[i][j]) cut[i][j] = cut_global; } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairCoulCut::coeff(int narg, char **arg) { if (narg < 2 || narg > 3) error->all(FLERR,"Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); double cut_one = cut_global; if (narg == 3) cut_one = force->numeric(arg[2]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { cut[i][j] = cut_one; scale[i][j] = 1.0; setflag[i][j] = 1; count++; } } if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairCoulCut::init_style() { if (!atom->q_flag) error->all(FLERR,"Pair style coul/cut requires atom attribute q"); neighbor->request(this); } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairCoulCut::init_one(int i, int j) { if (setflag[i][j] == 0) cut[i][j] = mix_distance(cut[i][i],cut[j][j]); scale[j][i] = scale[i][j]; return cut[i][j]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairCoulCut::write_restart(FILE *fp) { write_restart_settings(fp); int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { fwrite(&setflag[i][j],sizeof(int),1,fp); if (setflag[i][j]) fwrite(&cut[i][j],sizeof(double),1,fp); } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairCoulCut::read_restart(FILE *fp) { read_restart_settings(fp); allocate(); int i,j; int me = comm->me; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp); MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world); if (setflag[i][j]) { if (me == 0) fread(&cut[i][j],sizeof(double),1,fp); MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairCoulCut::write_restart_settings(FILE *fp) { fwrite(&cut_global,sizeof(double),1,fp); fwrite(&offset_flag,sizeof(int),1,fp); fwrite(&mix_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairCoulCut::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&cut_global,sizeof(double),1,fp); fread(&offset_flag,sizeof(int),1,fp); fread(&mix_flag,sizeof(int),1,fp); } MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world); MPI_Bcast(&offset_flag,1,MPI_INT,0,world); MPI_Bcast(&mix_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- */ double PairCoulCut::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r2inv,rinv,forcecoul,phicoul; r2inv = 1.0/rsq; rinv = sqrt(r2inv); forcecoul = force->qqrd2e * atom->q[i]*atom->q[j]*rinv; fforce = factor_coul*forcecoul * r2inv; phicoul = force->qqrd2e * atom->q[i]*atom->q[j]*rinv; return factor_coul*phicoul; } /* ---------------------------------------------------------------------- */ -void *PairCoulCut::extract(char *str, int &dim) +void *PairCoulCut::extract(const char *str, int &dim) { dim = 2; if (strcmp(str,"scale") == 0) return (void *) scale; return NULL; } diff --git a/src/pair_coul_cut.h b/src/pair_coul_cut.h index 4835b32e8..6e3e1fdc8 100644 --- a/src/pair_coul_cut.h +++ b/src/pair_coul_cut.h @@ -1,71 +1,71 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ #ifdef PAIR_CLASS PairStyle(coul/cut,PairCoulCut) #else #ifndef LMP_PAIR_COUL_CUT_H #define LMP_PAIR_COUL_CUT_H #include "pair.h" namespace LAMMPS_NS { class PairCoulCut : public Pair { public: PairCoulCut(class LAMMPS *); virtual ~PairCoulCut(); virtual void compute(int, int); virtual void settings(int, char **); void coeff(int, char **); void init_style(); double init_one(int, int); void write_restart(FILE *); void read_restart(FILE *); virtual void write_restart_settings(FILE *); virtual void read_restart_settings(FILE *); virtual double single(int, int, int, int, double, double, double, double &); - void *extract(char *, int &); + void *extract(const char *, int &); protected: double cut_global; double **cut,**scale; void allocate(); }; } #endif #endif /* ERROR/WARNING messages: E: Illegal ... command Self-explanatory. Check the input script syntax and compare to the documentation for the command. You can use -echo screen as a command-line option when running LAMMPS to see the offending line. E: Incorrect args for pair coefficients Self-explanatory. Check the input script or data file. E: Pair style coul/cut requires atom attribute q The atom style defined does not have these attributes. */ diff --git a/src/pair_gauss.cpp b/src/pair_gauss.cpp index 4649cdb0e..820d1e8b7 100644 --- a/src/pair_gauss.cpp +++ b/src/pair_gauss.cpp @@ -1,335 +1,335 @@ /* ---------------------------------------------------------------------- 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 author: Sai Jayaraman (Sandia) ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "pair_gauss.h" #include "atom.h" #include "comm.h" #include "force.h" #include "neighbor.h" #include "neigh_list.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define EPSILON 1.0e-10 /* ---------------------------------------------------------------------- */ PairGauss::PairGauss(LAMMPS *lmp) :Pair(lmp) { nextra = 1; pvector = new double[1]; } /* ---------------------------------------------------------------------- */ PairGauss::~PairGauss() { delete [] pvector; if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut); memory->destroy(a); memory->destroy(b); memory->destroy(offset); } } /* ---------------------------------------------------------------------- */ void PairGauss::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair; double r,rsq,r2inv,forcelj; int *ilist,*jlist,*numneigh,**firstneigh; evdwl = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; int occ = 0; double **x = atom->x; double **f = atom->f; int *type = atom->type; int nlocal = atom->nlocal; int newton_pair = force->newton_pair; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // loop over neighbors of my atoms for (ii = 0; ii < inum; ii++) { i = ilist[ii]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; j &= NEIGHMASK; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; jtype = type[j]; // define a Gaussian well to be occupied if // the site it interacts with is within the force maximum if (eflag_global && rsq < 0.5/b[itype][jtype]) occ++; if (rsq < cutsq[itype][jtype]) { r2inv = 1.0/rsq; r = sqrt(rsq); forcelj = - 2.0*a[itype][jtype]*b[itype][jtype] * rsq * exp(-b[itype][jtype]*rsq); fpair = forcelj*r2inv; f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; if (newton_pair || j < nlocal) { f[j][0] -= delx*fpair; f[j][1] -= dely*fpair; f[j][2] -= delz*fpair; } if (eflag) evdwl = -(a[itype][jtype]*exp(-b[itype][jtype]*rsq) - offset[itype][jtype]); if (evflag) ev_tally(i,j,nlocal,newton_pair, evdwl,0.0,fpair,delx,dely,delz); } } } if (eflag_global) pvector[0] = occ; if (vflag_fdotr) virial_fdotr_compute(); } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairGauss::allocate() { allocated = 1; int n = atom->ntypes; memory->create(setflag,n+1,n+1,"pair:setflag"); for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) setflag[i][j] = 0; memory->create(cutsq,n+1,n+1,"pair:cutsq"); memory->create(cut,n+1,n+1,"pair:cut_gauss"); memory->create(a,n+1,n+1,"pair:a"); memory->create(b,n+1,n+1,"pair:b"); memory->create(offset,n+1,n+1,"pair:offset"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairGauss::settings(int narg, char **arg) { if (narg != 1) error->all(FLERR,"Illegal pair_style command"); cut_global = atof(arg[0]); // reset cutoffs that have been explicity set if (allocated) { int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i+1; j <= atom->ntypes; j++) if (setflag[i][j]) cut[i][j] = cut_global; } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairGauss::coeff(int narg, char **arg) { if (narg < 4 || narg > 5) error->all(FLERR,"Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo, ihi, jlo, jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); double a_one = atof(arg[2]); double b_one = atof(arg[3]); double cut_one = cut_global; if (narg == 5) cut_one = atof(arg[4]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j<=jhi; j++) { a[i][j] = a_one; b[i][j] = b_one; cut[i][j] = cut_one; setflag[i][j] = 1; count++ ; } } if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairGauss::init_one(int i, int j) { if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set"); if (offset_flag) offset[i][j] = a[i][j]*exp(-b[i][j]*cut[i][j]*cut[i][j]); else offset[i][j] = 0.0; a[j][i] = a[i][j]; b[j][i] = b[i][j]; offset[j][i] = offset[i][j]; return cut[i][j]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairGauss::write_restart(FILE *fp) { write_restart_settings(fp); int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { fwrite(&setflag[i][j],sizeof(int),1,fp); if (setflag[i][j]) { fwrite(&a[i][j],sizeof(double),1,fp); fwrite(&b[i][j],sizeof(double),1,fp); fwrite(&cut[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairGauss::read_restart(FILE *fp) { read_restart_settings(fp); allocate(); int i,j; int me = comm->me; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp); MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world); if (setflag[i][j]) { if (me == 0) { fread(&a[i][j],sizeof(double),1,fp); fread(&b[i][j],sizeof(double),1,fp); fread(&cut[i][j],sizeof(double),1,fp); } MPI_Bcast(&a[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&b[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairGauss::write_restart_settings(FILE *fp) { fwrite(&cut_global,sizeof(double),1,fp); fwrite(&offset_flag,sizeof(int),1,fp); fwrite(&mix_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairGauss::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&cut_global,sizeof(double),1,fp); fread(&offset_flag,sizeof(int),1,fp); fread(&mix_flag,sizeof(int),1,fp); } MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world); MPI_Bcast(&offset_flag,1,MPI_INT,0,world); MPI_Bcast(&mix_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- */ double PairGauss::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r2inv,forcelj,philj,r; r = sqrt(rsq); r2inv = 1.0/rsq; philj = -(a[itype][jtype]*exp(-b[itype][jtype]*rsq) - offset[itype][jtype]); forcelj = -2.0*a[itype][jtype]*b[itype][jtype]*rsq*exp(-b[itype][jtype]*rsq); fforce = forcelj*r2inv; return philj; } /* ---------------------------------------------------------------------- */ -void *PairGauss::extract(char *str, int &dim) +void *PairGauss::extract(const char *str, int &dim) { dim = 2; if (strcmp(str,"a") == 0) return (void *) a; return NULL; } diff --git a/src/pair_gauss.h b/src/pair_gauss.h index fe0f6a65b..115a8948b 100644 --- a/src/pair_gauss.h +++ b/src/pair_gauss.h @@ -1,73 +1,73 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ #ifdef PAIR_CLASS PairStyle(gauss,PairGauss) #else #ifndef PAIR_GAUSS_H #define PAIR_GAUSS_H #include "pair.h" namespace LAMMPS_NS { class PairGauss : public Pair { public: PairGauss(class LAMMPS *); virtual ~PairGauss(); virtual void compute(int,int); void settings(int, char **); void coeff(int, char **); double init_one(int, int); void write_restart(FILE *); void read_restart(FILE *); void write_restart_settings(FILE *); void read_restart_settings(FILE *); double single(int, int, int, int, double, double, double, double &); - void *extract(char *, int &); + void *extract(const char *, int &); protected: double cut_global; double **cut; double **a,**b; double **offset; void allocate(); }; } #endif #endif /* ERROR/WARNING messages: E: Illegal ... command Self-explanatory. Check the input script syntax and compare to the documentation for the command. You can use -echo screen as a command-line option when running LAMMPS to see the offending line. E: Incorrect args for pair coefficients Self-explanatory. Check the input script or data file. E: All pair coeffs are not set All pair coefficients must be set in the data file or by the pair_coeff command before running a simulation. */ diff --git a/src/pair_hybrid.cpp b/src/pair_hybrid.cpp index 71a136600..20f72100f 100644 --- a/src/pair_hybrid.cpp +++ b/src/pair_hybrid.cpp @@ -1,718 +1,718 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ #include "math.h" #include "string.h" #include "ctype.h" #include "pair_hybrid.h" #include "atom.h" #include "force.h" #include "pair.h" #include "neighbor.h" #include "neigh_request.h" #include "update.h" #include "comm.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ PairHybrid::PairHybrid(LAMMPS *lmp) : Pair(lmp) { nstyles = 0; } /* ---------------------------------------------------------------------- */ PairHybrid::~PairHybrid() { if (nstyles) { for (int m = 0; m < nstyles; m++) delete styles[m]; delete [] styles; for (int m = 0; m < nstyles; m++) delete [] keywords[m]; delete [] keywords; } delete [] svector; if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cutghost); memory->destroy(nmap); memory->destroy(map); } } /* ---------------------------------------------------------------------- call each sub-style's compute function accumulate sub-style global/peratom energy/virial in hybrid for global vflag = 1: each sub-style computes own virial[6] sum sub-style virial[6] to hybrid's virial[6] for global vflag = 2: call sub-style with adjusted vflag to prevent it calling virial_fdotr_compute() hybrid calls virial_fdotr_compute() on final accumulated f ------------------------------------------------------------------------- */ void PairHybrid::compute(int eflag, int vflag) { int i,j,m,n; // if no_virial_fdotr_compute is set and global component of // incoming vflag = 2, then // reset vflag as if global component were 1 // necessary since one or more sub-styles cannot compute virial as F dot r if (no_virial_fdotr_compute && vflag % 4 == 2) vflag = 1 + vflag/4 * 4; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = eflag_global = vflag_global = eflag_atom = vflag_atom = 0; // check if global component of incoming vflag = 2 // if so, reset vflag passed to substyle as if it were 0 // necessary so substyle will not invoke virial_fdotr_compute() int vflag_substyle; if (vflag % 4 == 2) vflag_substyle = vflag/4 * 4; else vflag_substyle = vflag; for (m = 0; m < nstyles; m++) { styles[m]->compute(eflag,vflag_substyle); if (eflag_global) { eng_vdwl += styles[m]->eng_vdwl; eng_coul += styles[m]->eng_coul; } if (vflag_global) { for (n = 0; n < 6; n++) virial[n] += styles[m]->virial[n]; } if (eflag_atom) { n = atom->nlocal; if (force->newton_pair) n += atom->nghost; double *eatom_substyle = styles[m]->eatom; for (i = 0; i < n; i++) eatom[i] += eatom_substyle[i]; } if (vflag_atom) { n = atom->nlocal; if (force->newton_pair) n += atom->nghost; double **vatom_substyle = styles[m]->vatom; for (i = 0; i < n; i++) for (j = 0; j < 6; j++) vatom[i][j] += vatom_substyle[i][j]; } } if (vflag_fdotr) virial_fdotr_compute(); } /* ---------------------------------------------------------------------- */ void PairHybrid::compute_inner() { for (int m = 0; m < nstyles; m++) if (styles[m]->respa_enable) styles[m]->compute_inner(); } /* ---------------------------------------------------------------------- */ void PairHybrid::compute_middle() { for (int m = 0; m < nstyles; m++) if (styles[m]->respa_enable) styles[m]->compute_middle(); } /* ---------------------------------------------------------------------- */ void PairHybrid::compute_outer(int eflag, int vflag) { for (int m = 0; m < nstyles; m++) if (styles[m]->respa_enable) styles[m]->compute_outer(eflag,vflag); } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairHybrid::allocate() { allocated = 1; int n = atom->ntypes; memory->create(setflag,n+1,n+1,"pair:setflag"); for (int i = 1; i <= n; i++) for (int j = i; j <= n; j++) setflag[i][j] = 0; memory->create(cutsq,n+1,n+1,"pair:cutsq"); memory->create(cutghost,n+1,n+1,"pair:cutghost"); memory->create(nmap,n+1,n+1,"pair:nmap"); memory->create(map,n+1,n+1,nstyles,"pair:map"); for (int i = 1; i <= n; i++) for (int j = i; j <= n; j++) nmap[i][j] = 0; } /* ---------------------------------------------------------------------- create one pair style for each arg in list ------------------------------------------------------------------------- */ void PairHybrid::settings(int narg, char **arg) { int i,m,istyle; if (narg < 1) error->all(FLERR,"Illegal pair_style command"); // delete old lists, since cannot just change settings if (nstyles) { for (m = 0; m < nstyles; m++) delete styles[m]; delete [] styles; for (m = 0; m < nstyles; m++) delete [] keywords[m]; delete [] keywords; } if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cutghost); memory->destroy(nmap); memory->destroy(map); } allocated = 0; // count sub-styles by skipping numeric args // exception is 1st arg of table style, which is non-numeric word // exception is 1st two args of lj/coul style, which are non-numeric // exception is 1st two args of buck/coul, which are non-numeric // exception is 1st arg of reax/c style, which is non-numeric // execption is 1st 6 args of gran styles, which can have NULLs // need a better way to skip these exceptions nstyles = 0; i = 0; while (i < narg) { if (strcmp(arg[i],"table") == 0) i++; if (strcmp(arg[i],"lj/coul") == 0) i += 2; if (strcmp(arg[i],"buck/coul") == 0) i += 2; if (strcmp(arg[i],"reax/c") == 0) i++; if (strstr(arg[i],"gran/hooke")) i += 6; if (strstr(arg[i],"gran/hertz")) i += 6; i++; while (i < narg && !isalpha(arg[i][0])) i++; nstyles++; } // allocate list of sub-styles styles = new Pair*[nstyles]; keywords = new char*[nstyles]; // allocate each sub-style and call its settings() with subset of args // define subset of args for a sub-style by skipping numeric args // exception is 1st arg of table style, which is non-numeric word // exception is 1st two args of lj/coul style, which are non-numeric // exception is 1st two args of buck/coul, which are non-numeric // exception is 1st arg of reax/c style, which is non-numeric // execption is 1st 6 args of gran styles, which can have NULLs // need a better way to skip these exceptions int dummy; nstyles = 0; i = 0; while (i < narg) { for (m = 0; m < nstyles; m++) if (strcmp(arg[i],keywords[m]) == 0) error->all(FLERR,"Pair style hybrid cannot use same pair style twice"); if (strcmp(arg[i],"hybrid") == 0) error->all(FLERR,"Pair style hybrid cannot have hybrid as an argument"); if (strcmp(arg[i],"none") == 0) error->all(FLERR,"Pair style hybrid cannot have none as an argument"); styles[nstyles] = force->new_pair(arg[i],lmp->suffix,dummy); keywords[nstyles] = new char[strlen(arg[i])+1]; strcpy(keywords[nstyles],arg[i]); istyle = i; if (strcmp(arg[i],"table") == 0) i++; if (strcmp(arg[i],"lj/coul") == 0) i += 2; if (strcmp(arg[i],"buck/coul") == 0) i += 2; if (strcmp(arg[i],"reax/c") == 0) i++; if (strstr(arg[i],"gran/hooke")) i += 6; if (strstr(arg[i],"gran/hertz")) i += 6; i++; while (i < narg && !isalpha(arg[i][0])) i++; styles[nstyles]->settings(i-istyle-1,&arg[istyle+1]); nstyles++; } // set comm_forward, comm_reverse to max of any sub-style for (m = 0; m < nstyles; m++) { if (styles[m]) comm_forward = MAX(comm_forward,styles[m]->comm_forward); if (styles[m]) comm_reverse = MAX(comm_reverse,styles[m]->comm_reverse); } // single_enable = 1 if any sub-style is set // respa_enable = 1 if any sub-style is set // no_virial_fdotr_compute = 1 if any sub-style is set // ghostneigh = 1 if any sub-style is set single_enable = 0; for (m = 0; m < nstyles; m++) if (styles[m]->single_enable) single_enable = 1; for (m = 0; m < nstyles; m++) if (styles[m]->respa_enable) respa_enable = 1; for (m = 0; m < nstyles; m++) if (styles[m]->no_virial_fdotr_compute) no_virial_fdotr_compute = 1; for (m = 0; m < nstyles; m++) if (styles[m]->ghostneigh) ghostneigh = 1; // single_extra = min of all sub-style single_extra // allocate svector single_extra = styles[0]->single_extra; for (m = 1; m < nstyles; m++) single_extra = MIN(single_extra,styles[m]->single_extra); if (single_extra) { delete [] svector; svector = new double[single_extra]; } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairHybrid::coeff(int narg, char **arg) { if (narg < 3) error->all(FLERR,"Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); // 3rd arg = pair sub-style name // allow for "none" as valid sub-style name int m; for (m = 0; m < nstyles; m++) if (strcmp(arg[2],keywords[m]) == 0) break; int none = 0; if (m == nstyles) { if (strcmp(arg[2],"none") == 0) none = 1; else error->all(FLERR,"Pair coeff for hybrid has invalid style"); } // move 1st/2nd args to 2nd/3rd args // just copy ptrs, since arg[] points into original input line arg[2] = arg[1]; arg[1] = arg[0]; // invoke sub-style coeff() starting with 1st arg if (!none) styles[m]->coeff(narg-1,&arg[1]); // if sub-style only allows one pair coeff call (with * * and type mapping) // then unset setflag/map assigned to that style before setting it below // in case pair coeff for this sub-style is being called for 2nd time if (!none && styles[m]->one_coeff) for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) if (nmap[i][j] && map[i][j][0] == m) { setflag[i][j] = 0; nmap[i][j] = 0; } // set setflag and which type pairs map to which sub-style // if sub-style is none: set hybrid setflag, wipe out map // else: set hybrid setflag & map only if substyle setflag is set // previous mappings are wiped out int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { if (none) { setflag[i][j] = 1; nmap[i][j] = 0; count++; } else if (styles[m]->setflag[i][j]) { setflag[i][j] = 1; nmap[i][j] = 1; map[i][j][0] = m; count++; } } } if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairHybrid::init_style() { int i,m,itype,jtype,used,istyle,skip; // error if a sub-style is not used int ntypes = atom->ntypes; for (istyle = 0; istyle < nstyles; istyle++) { used = 0; for (itype = 1; itype <= ntypes; itype++) for (jtype = itype; jtype <= ntypes; jtype++) for (m = 0; m < nmap[itype][jtype]; m++) if (map[itype][jtype][m] == istyle) used = 1; if (used == 0) error->all(FLERR,"Pair hybrid sub-style is not used"); } // each sub-style makes its neighbor list request(s) for (istyle = 0; istyle < nstyles; istyle++) styles[istyle]->init_style(); // create skip lists for each pair neigh request // any kind of list can have its skip flag set at this stage for (i = 0; i < neighbor->nrequest; i++) { if (!neighbor->requests[i]->pair) continue; // istyle = associated sub-style for (istyle = 0; istyle < nstyles; istyle++) if (styles[istyle] == neighbor->requests[i]->requestor) break; // allocate iskip and ijskip // initialize so as to skip all pair types // set ijskip = 0 if type pair matches any entry in sub-style map // set ijskip = 0 if mixing will assign type pair to this sub-style // will occur if type pair is currently unassigned // and both I,I and J,J are assigned to single sub-style // and sub-style for both I,I and J,J match istyle // set iskip = 1 only if all ijskip for itype are 1 int *iskip = new int[ntypes+1]; int **ijskip; memory->create(ijskip,ntypes+1,ntypes+1,"pair_hybrid:ijskip"); for (itype = 1; itype <= ntypes; itype++) for (jtype = 1; jtype <= ntypes; jtype++) ijskip[itype][jtype] = 1; for (itype = 1; itype <= ntypes; itype++) for (jtype = itype; jtype <= ntypes; jtype++) { for (m = 0; m < nmap[itype][jtype]; m++) if (map[itype][jtype][m] == istyle) ijskip[itype][jtype] = ijskip[jtype][itype] = 0; if (nmap[itype][jtype] == 0 && nmap[itype][itype] == 1 && map[itype][itype][0] == istyle && nmap[jtype][jtype] == 1 && map[jtype][jtype][0] == istyle) ijskip[itype][jtype] = ijskip[jtype][itype] = 0; } for (itype = 1; itype <= ntypes; itype++) { iskip[itype] = 1; for (jtype = 1; jtype <= ntypes; jtype++) if (ijskip[itype][jtype] == 0) iskip[itype] = 0; } // if any skipping occurs // set request->skip and copy iskip and ijskip into request // else delete iskip and ijskip skip = 0; for (itype = 1; itype <= ntypes; itype++) for (jtype = 1; jtype <= ntypes; jtype++) if (ijskip[itype][jtype] == 1) skip = 1; if (skip) { neighbor->requests[i]->skip = 1; neighbor->requests[i]->iskip = iskip; neighbor->requests[i]->ijskip = ijskip; } else { delete [] iskip; memory->destroy(ijskip); } } // combine sub-style neigh list requests and create new ones if needed modify_requests(); } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairHybrid::init_one(int i, int j) { // if I,J is not set explicitly: // perform mixing only if I,I sub-style = J,J sub-style // also require I,I and J,J are both assigned to single sub-style if (setflag[i][j] == 0) { if (nmap[i][i] != 1 || nmap[j][j] != 1 || map[i][i][0] != map[j][j][0]) error->one(FLERR,"All pair coeffs are not set"); nmap[i][j] = 1; map[i][j][0] = map[i][i][0]; } // call init/mixing for all sub-styles of I,J // set cutsq in sub-style just as Pair::init() does via call to init_one() // set cutghost for I,J and J,I just as sub-style does // sum tail corrections for I,J // return max cutoff of all sub-styles assigned to I,J // if no sub-styles assigned to I,J (pair_coeff none), cutmax = 0.0 returned double cutmax = 0.0; cutghost[i][j] = cutghost[j][i] = 0.0; if (tail_flag) etail_ij = ptail_ij = 0.0; nmap[j][i] = nmap[i][j]; for (int k = 0; k < nmap[i][j]; k++) { map[j][i][k] = map[i][j][k]; double cut = styles[map[i][j][k]]->init_one(i,j); styles[map[i][j][k]]->cutsq[i][j] = styles[map[i][j][k]]->cutsq[j][i] = cut*cut; if (styles[map[i][j][k]]->ghostneigh) cutghost[i][j] = cutghost[j][i] = MAX(cutghost[i][j],styles[map[i][j][k]]->cutghost[i][j]); if (tail_flag) { etail_ij += styles[map[i][j][k]]->etail_ij; ptail_ij += styles[map[i][j][k]]->ptail_ij; } cutmax = MAX(cutmax,cut); } return cutmax; } /* ---------------------------------------------------------------------- combine sub-style neigh list requests and create new ones if needed ------------------------------------------------------------------------- */ void PairHybrid::modify_requests() { int i,j; NeighRequest *irq,*jrq; // loop over pair requests only // if list is skip list and not copy, look for non-skip list of same kind // if one exists, point at that one via otherlist // else make new non-skip request of same kind and point at that one // don't bother to set ID for new request, since pair hybrid ignores list // only exception is half_from_full: // ignore it, turn off skip, since it will derive from its skip parent // after possible new request creation, unset skip flag and otherlist // for these derived lists: granhistory, rRESPA inner/middle // this prevents neighbor from treating them as skip lists // copy list check is for pair style = hybrid/overlay // which invokes this routine for (i = 0; i < neighbor->nrequest; i++) { if (!neighbor->requests[i]->pair) continue; irq = neighbor->requests[i]; if (irq->skip == 0 || irq->copy) continue; if (irq->half_from_full) { irq->skip = 0; continue; } for (j = 0; j < neighbor->nrequest; j++) { if (!neighbor->requests[j]->pair) continue; jrq = neighbor->requests[j]; if (irq->same_kind(jrq) && jrq->skip == 0) break; } if (j < neighbor->nrequest) irq->otherlist = j; else { int newrequest = neighbor->request(this); neighbor->requests[newrequest]->copy_request(irq); irq->otherlist = newrequest; } if (irq->granhistory || irq->respainner || irq->respamiddle) { irq->skip = 0; irq->otherlist = -1; } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairHybrid::write_restart(FILE *fp) { fwrite(&nstyles,sizeof(int),1,fp); // each sub-style writes its settings, but no coeff info int n; for (int m = 0; m < nstyles; m++) { n = strlen(keywords[m]) + 1; fwrite(&n,sizeof(int),1,fp); fwrite(keywords[m],sizeof(char),n,fp); styles[m]->write_restart_settings(fp); } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairHybrid::read_restart(FILE *fp) { int me = comm->me; if (me == 0) fread(&nstyles,sizeof(int),1,fp); MPI_Bcast(&nstyles,1,MPI_INT,0,world); styles = new Pair*[nstyles]; keywords = new char*[nstyles]; // each sub-style is created via new_pair() // each reads its settings, but no coeff info int n,dummy; for (int m = 0; m < nstyles; m++) { if (me == 0) fread(&n,sizeof(int),1,fp); MPI_Bcast(&n,1,MPI_INT,0,world); keywords[m] = new char[n]; if (me == 0) fread(keywords[m],sizeof(char),n,fp); MPI_Bcast(keywords[m],n,MPI_CHAR,0,world); styles[m] = force->new_pair(keywords[m],lmp->suffix,dummy); styles[m]->read_restart_settings(fp); } } /* ---------------------------------------------------------------------- call sub-style to compute single interaction error if sub-style does not support single() call since overlay could have multiple sub-styles, sum results explicitly ------------------------------------------------------------------------- */ double PairHybrid::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { if (nmap[itype][jtype] == 0) error->one(FLERR,"Invoked pair single on pair style none"); double fone; fforce = 0.0; double esum = 0.0; for (int m = 0; m < nmap[itype][jtype]; m++) { if (rsq < styles[map[itype][jtype][m]]->cutsq[itype][jtype]) { if (styles[map[itype][jtype][m]]->single_enable == 0) error->one(FLERR,"Pair hybrid sub-style does not support single call"); esum += styles[map[itype][jtype][m]]-> single(i,j,itype,jtype,rsq,factor_coul,factor_lj,fone); fforce += fone; // copy substyle extra values into hybrid's svector if (single_extra && styles[map[itype][jtype][m]]->single_extra) for (m = 0; m < single_extra; m++) svector[m] = styles[map[itype][jtype][m]]->svector[m]; } } return esum; } /* ---------------------------------------------------------------------- modify parameters of the pair style call modify_params of PairHybrid also pass command args to each sub-style of hybrid ------------------------------------------------------------------------- */ void PairHybrid::modify_params(int narg, char **arg) { Pair::modify_params(narg,arg); for (int m = 0; m < nstyles; m++) styles[m]->modify_params(narg,arg); } /* ---------------------------------------------------------------------- memory usage of each sub-style ------------------------------------------------------------------------- */ double PairHybrid::memory_usage() { double bytes = maxeatom * sizeof(double); bytes += maxvatom*6 * sizeof(double); for (int m = 0; m < nstyles; m++) bytes += styles[m]->memory_usage(); return bytes; } /* ---------------------------------------------------------------------- extract a ptr to a particular quantity stored by pair pass request thru to sub-styles return first non-NULL result except for cut_coul request for cut_coul, insure all non-NULL results are equal since required by Kspace ------------------------------------------------------------------------- */ -void *PairHybrid::extract(char *str, int &dim) +void *PairHybrid::extract(const char *str, int &dim) { void *cutptr = NULL; void *ptr; double cutvalue; for (int m = 0; m < nstyles; m++) { ptr = styles[m]->extract(str,dim); if (ptr && strcmp(str,"cut_coul") == 0) { double *p_newvalue = (double *) ptr; double newvalue = *p_newvalue; if (cutptr && newvalue != cutvalue) error->all(FLERR, "Coulomb cutoffs of pair hybrid sub-styles do not match"); cutptr = ptr; cutvalue = newvalue; } else if (ptr) return ptr; } if (strcmp(str,"cut_coul") == 0) return cutptr; return NULL; } /* ---------------------------------------------------------------------- */ void PairHybrid::reset_dt() { for (int m = 0; m < nstyles; m++) styles[m]->reset_dt(); } /* ---------------------------------------------------------------------- check if itype,jtype maps to sub-style ------------------------------------------------------------------------- */ int PairHybrid::check_ijtype(int itype, int jtype, char *substyle) { for (int m = 0; m < nmap[itype][jtype]; m++) if (strcmp(keywords[map[itype][jtype][m]],substyle) == 0) return 1; return 0; } diff --git a/src/pair_hybrid.h b/src/pair_hybrid.h index db0459dea..6b4bf8051 100644 --- a/src/pair_hybrid.h +++ b/src/pair_hybrid.h @@ -1,123 +1,123 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ #ifdef PAIR_CLASS PairStyle(hybrid,PairHybrid) #else #ifndef LMP_PAIR_HYBRID_H #define LMP_PAIR_HYBRID_H #include "stdio.h" #include "pair.h" namespace LAMMPS_NS { class PairHybrid : public Pair { public: int nstyles; // # of different sub-styles Pair **styles; // list of Pair style classes char **keywords; // style name of each Pair style PairHybrid(class LAMMPS *); virtual ~PairHybrid(); void compute(int, int); void settings(int, char **); virtual void coeff(int, char **); void init_style(); double init_one(int, int); void write_restart(FILE *); void read_restart(FILE *); double single(int, int, int, int, double, double, double, double &); void modify_params(int narg, char **arg); double memory_usage(); void compute_inner(); void compute_middle(); void compute_outer(int, int); - void *extract(char *, int &); + void *extract(const char *, int &); void reset_dt(); int check_ijtype(int, int, char *); protected: int **nmap; // # of sub-styles itype,jtype points to int ***map; // list of sub-styles itype,jtype points to void allocate(); virtual void modify_requests(); }; } #endif #endif /* ERROR/WARNING messages: E: Illegal ... command Self-explanatory. Check the input script syntax and compare to the documentation for the command. You can use -echo screen as a command-line option when running LAMMPS to see the offending line. E: Pair style hybrid cannot use same pair style twice The sub-style arguments of pair_style hybrid cannot be duplicated. Check the input script. E: Pair style hybrid cannot have hybrid as an argument Self-explanatory. E: Pair style hybrid cannot have none as an argument Self-explanatory. E: Incorrect args for pair coefficients Self-explanatory. Check the input script or data file. E: Pair coeff for hybrid has invalid style Style in pair coeff must have been listed in pair_style command. E: Pair hybrid sub-style is not used No pair_coeff command used a sub-style specified in the pair_style command. E: All pair coeffs are not set All pair coefficients must be set in the data file or by the pair_coeff command before running a simulation. E: Invoked pair single on pair style none A command (e.g. a dump) attempted to invoke the single() function on a pair style none, which is illegal. You are probably attempting to compute per-atom quantities with an undefined pair style. E: Pair hybrid sub-style does not support single call You are attempting to invoke a single() call on a pair style that doesn't support it. E: Coulomb cutoffs of pair hybrid sub-styles do not match If using a Kspace solver, all Coulomb cutoffs of long pair styles must be the same. */ diff --git a/src/pair_lj_cut.cpp b/src/pair_lj_cut.cpp index f5ea2887d..69add0d11 100644 --- a/src/pair_lj_cut.cpp +++ b/src/pair_lj_cut.cpp @@ -1,704 +1,704 @@ /* ---------------------------------------------------------------------- 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 author: Paul Crozier (SNL) ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "pair_lj_cut.h" #include "atom.h" #include "comm.h" #include "force.h" #include "neighbor.h" #include "neigh_list.h" #include "neigh_request.h" #include "update.h" #include "integrate.h" #include "respa.h" #include "math_const.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace MathConst; /* ---------------------------------------------------------------------- */ PairLJCut::PairLJCut(LAMMPS *lmp) : Pair(lmp) { respa_enable = 1; } /* ---------------------------------------------------------------------- */ PairLJCut::~PairLJCut() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut); memory->destroy(epsilon); memory->destroy(sigma); memory->destroy(lj1); memory->destroy(lj2); memory->destroy(lj3); memory->destroy(lj4); memory->destroy(offset); } } /* ---------------------------------------------------------------------- */ void PairLJCut::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair; double rsq,r2inv,r6inv,forcelj,factor_lj; int *ilist,*jlist,*numneigh,**firstneigh; evdwl = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; double **x = atom->x; double **f = atom->f; int *type = atom->type; int nlocal = atom->nlocal; double *special_lj = force->special_lj; int newton_pair = force->newton_pair; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // loop over neighbors of my atoms for (ii = 0; ii < inum; ii++) { i = ilist[ii]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; factor_lj = special_lj[sbmask(j)]; j &= NEIGHMASK; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; jtype = type[j]; if (rsq < cutsq[itype][jtype]) { r2inv = 1.0/rsq; r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); fpair = factor_lj*forcelj*r2inv; f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; if (newton_pair || j < nlocal) { f[j][0] -= delx*fpair; f[j][1] -= dely*fpair; f[j][2] -= delz*fpair; } if (eflag) { evdwl = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]) - offset[itype][jtype]; evdwl *= factor_lj; } if (evflag) ev_tally(i,j,nlocal,newton_pair, evdwl,0.0,fpair,delx,dely,delz); } } } if (vflag_fdotr) virial_fdotr_compute(); } /* ---------------------------------------------------------------------- */ void PairLJCut::compute_inner() { int i,j,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,fpair; double rsq,r2inv,r6inv,forcelj,factor_lj,rsw; int *ilist,*jlist,*numneigh,**firstneigh; double **x = atom->x; double **f = atom->f; int *type = atom->type; int nlocal = atom->nlocal; double *special_lj = force->special_lj; int newton_pair = force->newton_pair; inum = listinner->inum; ilist = listinner->ilist; numneigh = listinner->numneigh; firstneigh = listinner->firstneigh; double cut_out_on = cut_respa[0]; double cut_out_off = cut_respa[1]; double cut_out_diff = cut_out_off - cut_out_on; double cut_out_on_sq = cut_out_on*cut_out_on; double cut_out_off_sq = cut_out_off*cut_out_off; // loop over neighbors of my atoms for (ii = 0; ii < inum; ii++) { i = ilist[ii]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; factor_lj = special_lj[sbmask(j)]; j &= NEIGHMASK; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; if (rsq < cut_out_off_sq) { r2inv = 1.0/rsq; r6inv = r2inv*r2inv*r2inv; jtype = type[j]; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); fpair = factor_lj*forcelj*r2inv; if (rsq > cut_out_on_sq) { rsw = (sqrt(rsq) - cut_out_on)/cut_out_diff; fpair *= 1.0 - rsw*rsw*(3.0 - 2.0*rsw); } f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; if (newton_pair || j < nlocal) { f[j][0] -= delx*fpair; f[j][1] -= dely*fpair; f[j][2] -= delz*fpair; } } } } } /* ---------------------------------------------------------------------- */ void PairLJCut::compute_middle() { int i,j,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,fpair; double rsq,r2inv,r6inv,forcelj,factor_lj,rsw; int *ilist,*jlist,*numneigh,**firstneigh; double **x = atom->x; double **f = atom->f; int *type = atom->type; int nlocal = atom->nlocal; double *special_lj = force->special_lj; int newton_pair = force->newton_pair; inum = listmiddle->inum; ilist = listmiddle->ilist; numneigh = listmiddle->numneigh; firstneigh = listmiddle->firstneigh; double cut_in_off = cut_respa[0]; double cut_in_on = cut_respa[1]; double cut_out_on = cut_respa[2]; double cut_out_off = cut_respa[3]; double cut_in_diff = cut_in_on - cut_in_off; double cut_out_diff = cut_out_off - cut_out_on; double cut_in_off_sq = cut_in_off*cut_in_off; double cut_in_on_sq = cut_in_on*cut_in_on; double cut_out_on_sq = cut_out_on*cut_out_on; double cut_out_off_sq = cut_out_off*cut_out_off; // loop over neighbors of my atoms for (ii = 0; ii < inum; ii++) { i = ilist[ii]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; factor_lj = special_lj[sbmask(j)]; j &= NEIGHMASK; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; if (rsq < cut_out_off_sq && rsq > cut_in_off_sq) { r2inv = 1.0/rsq; r6inv = r2inv*r2inv*r2inv; jtype = type[j]; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); fpair = factor_lj*forcelj*r2inv; if (rsq < cut_in_on_sq) { rsw = (sqrt(rsq) - cut_in_off)/cut_in_diff; fpair *= rsw*rsw*(3.0 - 2.0*rsw); } if (rsq > cut_out_on_sq) { rsw = (sqrt(rsq) - cut_out_on)/cut_out_diff; fpair *= 1.0 + rsw*rsw*(2.0*rsw - 3.0); } f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; if (newton_pair || j < nlocal) { f[j][0] -= delx*fpair; f[j][1] -= dely*fpair; f[j][2] -= delz*fpair; } } } } } /* ---------------------------------------------------------------------- */ void PairLJCut::compute_outer(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair; double rsq,r2inv,r6inv,forcelj,factor_lj,rsw; int *ilist,*jlist,*numneigh,**firstneigh; evdwl = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; int *type = atom->type; int nlocal = atom->nlocal; double *special_lj = force->special_lj; int newton_pair = force->newton_pair; inum = listouter->inum; ilist = listouter->ilist; numneigh = listouter->numneigh; firstneigh = listouter->firstneigh; double cut_in_off = cut_respa[2]; double cut_in_on = cut_respa[3]; double cut_in_diff = cut_in_on - cut_in_off; double cut_in_off_sq = cut_in_off*cut_in_off; double cut_in_on_sq = cut_in_on*cut_in_on; // loop over neighbors of my atoms for (ii = 0; ii < inum; ii++) { i = ilist[ii]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; factor_lj = special_lj[sbmask(j)]; j &= NEIGHMASK; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; jtype = type[j]; if (rsq < cutsq[itype][jtype]) { if (rsq > cut_in_off_sq) { r2inv = 1.0/rsq; r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); fpair = factor_lj*forcelj*r2inv; if (rsq < cut_in_on_sq) { rsw = (sqrt(rsq) - cut_in_off)/cut_in_diff; fpair *= rsw*rsw*(3.0 - 2.0*rsw); } f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; if (newton_pair || j < nlocal) { f[j][0] -= delx*fpair; f[j][1] -= dely*fpair; f[j][2] -= delz*fpair; } } if (eflag) { r2inv = 1.0/rsq; r6inv = r2inv*r2inv*r2inv; evdwl = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]) - offset[itype][jtype]; evdwl *= factor_lj; } if (vflag) { if (rsq <= cut_in_off_sq) { r2inv = 1.0/rsq; r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); fpair = factor_lj*forcelj*r2inv; } else if (rsq < cut_in_on_sq) fpair = factor_lj*forcelj*r2inv; } if (evflag) ev_tally(i,j,nlocal,newton_pair, evdwl,0.0,fpair,delx,dely,delz); } } } } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairLJCut::allocate() { allocated = 1; int n = atom->ntypes; memory->create(setflag,n+1,n+1,"pair:setflag"); for (int i = 1; i <= n; i++) for (int j = i; j <= n; j++) setflag[i][j] = 0; memory->create(cutsq,n+1,n+1,"pair:cutsq"); memory->create(cut,n+1,n+1,"pair:cut"); memory->create(epsilon,n+1,n+1,"pair:epsilon"); memory->create(sigma,n+1,n+1,"pair:sigma"); memory->create(lj1,n+1,n+1,"pair:lj1"); memory->create(lj2,n+1,n+1,"pair:lj2"); memory->create(lj3,n+1,n+1,"pair:lj3"); memory->create(lj4,n+1,n+1,"pair:lj4"); memory->create(offset,n+1,n+1,"pair:offset"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairLJCut::settings(int narg, char **arg) { if (narg != 1) error->all(FLERR,"Illegal pair_style command"); cut_global = force->numeric(arg[0]); // reset cutoffs that have been explicitly set if (allocated) { int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i+1; j <= atom->ntypes; j++) if (setflag[i][j]) cut[i][j] = cut_global; } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairLJCut::coeff(int narg, char **arg) { if (narg < 4 || narg > 5) error->all(FLERR,"Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(arg[2]); double sigma_one = force->numeric(arg[3]); double cut_one = cut_global; if (narg == 5) cut_one = force->numeric(arg[4]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { epsilon[i][j] = epsilon_one; sigma[i][j] = sigma_one; cut[i][j] = cut_one; setflag[i][j] = 1; count++; } } if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairLJCut::init_style() { // request regular or rRESPA neighbor lists int irequest; if (update->whichflag == 1 && strstr(update->integrate_style,"respa")) { int respa = 0; if (((Respa *) update->integrate)->level_inner >= 0) respa = 1; if (((Respa *) update->integrate)->level_middle >= 0) respa = 2; if (respa == 0) irequest = neighbor->request(this); else if (respa == 1) { irequest = neighbor->request(this); neighbor->requests[irequest]->id = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respainner = 1; irequest = neighbor->request(this); neighbor->requests[irequest]->id = 3; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respaouter = 1; } else { irequest = neighbor->request(this); neighbor->requests[irequest]->id = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respainner = 1; irequest = neighbor->request(this); neighbor->requests[irequest]->id = 2; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respamiddle = 1; irequest = neighbor->request(this); neighbor->requests[irequest]->id = 3; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respaouter = 1; } } else irequest = neighbor->request(this); // set rRESPA cutoffs if (strstr(update->integrate_style,"respa") && ((Respa *) update->integrate)->level_inner >= 0) cut_respa = ((Respa *) update->integrate)->cutoff; else cut_respa = NULL; } /* ---------------------------------------------------------------------- neighbor callback to inform pair style of neighbor list to use regular or rRESPA ------------------------------------------------------------------------- */ void PairLJCut::init_list(int id, NeighList *ptr) { if (id == 0) list = ptr; else if (id == 1) listinner = ptr; else if (id == 2) listmiddle = ptr; else if (id == 3) listouter = ptr; } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairLJCut::init_one(int i, int j) { if (setflag[i][j] == 0) { epsilon[i][j] = mix_energy(epsilon[i][i],epsilon[j][j], sigma[i][i],sigma[j][j]); sigma[i][j] = mix_distance(sigma[i][i],sigma[j][j]); cut[i][j] = mix_distance(cut[i][i],cut[j][j]); } lj1[i][j] = 48.0 * epsilon[i][j] * pow(sigma[i][j],12.0); lj2[i][j] = 24.0 * epsilon[i][j] * pow(sigma[i][j],6.0); lj3[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],12.0); lj4[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],6.0); if (offset_flag) { double ratio = sigma[i][j] / cut[i][j]; offset[i][j] = 4.0 * epsilon[i][j] * (pow(ratio,12.0) - pow(ratio,6.0)); } else offset[i][j] = 0.0; lj1[j][i] = lj1[i][j]; lj2[j][i] = lj2[i][j]; lj3[j][i] = lj3[i][j]; lj4[j][i] = lj4[i][j]; offset[j][i] = offset[i][j]; // check interior rRESPA cutoff if (cut_respa && cut[i][j] < cut_respa[3]) error->all(FLERR,"Pair cutoff < Respa interior cutoff"); // compute I,J contribution to long-range tail correction // count total # of atoms of type I and J via Allreduce if (tail_flag) { int *type = atom->type; int nlocal = atom->nlocal; double count[2],all[2]; count[0] = count[1] = 0.0; for (int k = 0; k < nlocal; k++) { if (type[k] == i) count[0] += 1.0; if (type[k] == j) count[1] += 1.0; } MPI_Allreduce(count,all,2,MPI_DOUBLE,MPI_SUM,world); double sig2 = sigma[i][j]*sigma[i][j]; double sig6 = sig2*sig2*sig2; double rc3 = cut[i][j]*cut[i][j]*cut[i][j]; double rc6 = rc3*rc3; double rc9 = rc3*rc6; etail_ij = 8.0*MY_PI*all[0]*all[1]*epsilon[i][j] * sig6 * (sig6 - 3.0*rc6) / (9.0*rc9); ptail_ij = 16.0*MY_PI*all[0]*all[1]*epsilon[i][j] * sig6 * (2.0*sig6 - 3.0*rc6) / (9.0*rc9); } return cut[i][j]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJCut::write_restart(FILE *fp) { write_restart_settings(fp); int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { fwrite(&setflag[i][j],sizeof(int),1,fp); if (setflag[i][j]) { fwrite(&epsilon[i][j],sizeof(double),1,fp); fwrite(&sigma[i][j],sizeof(double),1,fp); fwrite(&cut[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJCut::read_restart(FILE *fp) { read_restart_settings(fp); allocate(); int i,j; int me = comm->me; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp); MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world); if (setflag[i][j]) { if (me == 0) { fread(&epsilon[i][j],sizeof(double),1,fp); fread(&sigma[i][j],sizeof(double),1,fp); fread(&cut[i][j],sizeof(double),1,fp); } MPI_Bcast(&epsilon[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJCut::write_restart_settings(FILE *fp) { fwrite(&cut_global,sizeof(double),1,fp); fwrite(&offset_flag,sizeof(int),1,fp); fwrite(&mix_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJCut::read_restart_settings(FILE *fp) { int me = comm->me; if (me == 0) { fread(&cut_global,sizeof(double),1,fp); fread(&offset_flag,sizeof(int),1,fp); fread(&mix_flag,sizeof(int),1,fp); } MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world); MPI_Bcast(&offset_flag,1,MPI_INT,0,world); MPI_Bcast(&mix_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- */ double PairLJCut::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r2inv,r6inv,forcelj,philj; r2inv = 1.0/rsq; r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); fforce = factor_lj*forcelj*r2inv; philj = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]) - offset[itype][jtype]; return factor_lj*philj; } /* ---------------------------------------------------------------------- */ -void *PairLJCut::extract(char *str, int &dim) +void *PairLJCut::extract(const char *str, int &dim) { dim = 2; if (strcmp(str,"epsilon") == 0) return (void *) epsilon; return NULL; } diff --git a/src/pair_lj_cut.h b/src/pair_lj_cut.h index 200f4ab43..8eb4a4867 100644 --- a/src/pair_lj_cut.h +++ b/src/pair_lj_cut.h @@ -1,80 +1,80 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ #ifdef PAIR_CLASS PairStyle(lj/cut,PairLJCut) #else #ifndef LMP_PAIR_LJ_CUT_H #define LMP_PAIR_LJ_CUT_H #include "pair.h" namespace LAMMPS_NS { class PairLJCut : public Pair { public: PairLJCut(class LAMMPS *); virtual ~PairLJCut(); virtual void compute(int, int); void settings(int, char **); void coeff(int, char **); void init_style(); void init_list(int, class NeighList *); double init_one(int, int); void write_restart(FILE *); void read_restart(FILE *); void write_restart_settings(FILE *); void read_restart_settings(FILE *); double single(int, int, int, int, double, double, double, double &); - void *extract(char *, int &); + void *extract(const char *, int &); void compute_inner(); void compute_middle(); void compute_outer(int, int); protected: double cut_global; double **cut; double **epsilon,**sigma; double **lj1,**lj2,**lj3,**lj4,**offset; double *cut_respa; void allocate(); }; } #endif #endif /* ERROR/WARNING messages: E: Illegal ... command Self-explanatory. Check the input script syntax and compare to the documentation for the command. You can use -echo screen as a command-line option when running LAMMPS to see the offending line. E: Incorrect args for pair coefficients Self-explanatory. Check the input script or data file. E: Pair cutoff < Respa interior cutoff One or more pairwise cutoffs are too short to use with the specified rRESPA cutoffs. */ diff --git a/src/pair_soft.cpp b/src/pair_soft.cpp index 63f0b72b0..fb2889ddf 100644 --- a/src/pair_soft.cpp +++ b/src/pair_soft.cpp @@ -1,307 +1,307 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "pair_soft.h" #include "atom.h" #include "comm.h" #include "force.h" #include "update.h" #include "neigh_list.h" #include "math_const.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace MathConst; /* ---------------------------------------------------------------------- */ PairSoft::PairSoft(LAMMPS *lmp) : Pair(lmp) {} /* ---------------------------------------------------------------------- */ PairSoft::~PairSoft() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(prefactor); memory->destroy(cut); } } /* ---------------------------------------------------------------------- */ void PairSoft::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair; double r,rsq,arg,factor_lj; int *ilist,*jlist,*numneigh,**firstneigh; evdwl = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; double **x = atom->x; double **f = atom->f; int *type = atom->type; int nlocal = atom->nlocal; double *special_lj = force->special_lj; int newton_pair = force->newton_pair; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // loop over neighbors of my atoms for (ii = 0; ii < inum; ii++) { i = ilist[ii]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; factor_lj = special_lj[sbmask(j)]; j &= NEIGHMASK; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; jtype = type[j]; if (rsq < cutsq[itype][jtype]) { r = sqrt(rsq); arg = MY_PI*r/cut[itype][jtype]; if (r > 0.0) fpair = factor_lj * prefactor[itype][jtype] * sin(arg) * MY_PI/cut[itype][jtype]/r; else fpair = 0.0; f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; if (newton_pair || j < nlocal) { f[j][0] -= delx*fpair; f[j][1] -= dely*fpair; f[j][2] -= delz*fpair; } if (eflag) evdwl = factor_lj * prefactor[itype][jtype] * (1.0+cos(arg)); if (evflag) ev_tally(i,j,nlocal,newton_pair, evdwl,0.0,fpair,delx,dely,delz); } } } if (vflag_fdotr) virial_fdotr_compute(); } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairSoft::allocate() { allocated = 1; int n = atom->ntypes; memory->create(setflag,n+1,n+1,"pair:setflag"); for (int i = 1; i <= n; i++) for (int j = i; j <= n; j++) setflag[i][j] = 0; memory->create(cutsq,n+1,n+1,"pair:cutsq"); memory->create(prefactor,n+1,n+1,"pair:prefactor"); memory->create(cut,n+1,n+1,"pair:cut"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairSoft::settings(int narg, char **arg) { if (narg != 1) error->all(FLERR,"Illegal pair_style command"); cut_global = force->numeric(arg[0]); // reset cutoffs that have been explicitly set if (allocated) { int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i+1; j <= atom->ntypes; j++) if (setflag[i][j]) cut[i][j] = cut_global; } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairSoft::coeff(int narg, char **arg) { if (narg < 3 || narg > 4) error->all(FLERR,"Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); double prefactor_one = force->numeric(arg[2]); double cut_one = cut_global; if (narg == 4) cut_one = force->numeric(arg[3]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { prefactor[i][j] = prefactor_one; cut[i][j] = cut_one; setflag[i][j] = 1; count++; } } if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairSoft::init_one(int i, int j) { // always mix prefactors geometrically if (setflag[i][j] == 0) { prefactor[i][j] = sqrt(prefactor[i][i]*prefactor[j][j]); cut[i][j] = mix_distance(cut[i][i],cut[j][j]); } prefactor[j][i] = prefactor[i][j]; cut[j][i] = cut[i][j]; return cut[i][j]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairSoft::write_restart(FILE *fp) { write_restart_settings(fp); int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { fwrite(&setflag[i][j],sizeof(int),1,fp); if (setflag[i][j]) { fwrite(&prefactor[i][j],sizeof(double),1,fp); fwrite(&cut[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairSoft::read_restart(FILE *fp) { read_restart_settings(fp); allocate(); int i,j; int me = comm->me; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp); MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world); if (setflag[i][j]) { if (me == 0) { fread(&prefactor[i][j],sizeof(double),1,fp); fread(&cut[i][j],sizeof(double),1,fp); } MPI_Bcast(&prefactor[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairSoft::write_restart_settings(FILE *fp) { fwrite(&cut_global,sizeof(double),1,fp); fwrite(&mix_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairSoft::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&cut_global,sizeof(double),1,fp); fread(&mix_flag,sizeof(int),1,fp); } MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world); MPI_Bcast(&mix_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- */ double PairSoft::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r,arg,philj; r = sqrt(rsq); arg = MY_PI*r/cut[itype][jtype]; fforce = factor_lj * prefactor[itype][jtype] * sin(arg) * MY_PI/cut[itype][jtype]/r; philj = prefactor[itype][jtype] * (1.0+cos(arg)); return factor_lj*philj; } /* ---------------------------------------------------------------------- */ -void *PairSoft::extract(char *str, int &dim) +void *PairSoft::extract(const char *str, int &dim) { dim = 2; if (strcmp(str,"a") == 0) return (void *) prefactor; return NULL; } diff --git a/src/pair_soft.h b/src/pair_soft.h index 0156a877e..c5927cefd 100644 --- a/src/pair_soft.h +++ b/src/pair_soft.h @@ -1,70 +1,70 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ #ifdef PAIR_CLASS PairStyle(soft,PairSoft) #else #ifndef LMP_PAIR_SOFT_H #define LMP_PAIR_SOFT_H #include "pair.h" namespace LAMMPS_NS { class PairSoft : public Pair { friend class Pair; public: PairSoft(class LAMMPS *); virtual ~PairSoft(); virtual void compute(int, int); void settings(int, char **); void coeff(int, char **); double init_one(int, int); void write_restart(FILE *); void read_restart(FILE *); void write_restart_settings(FILE *); void read_restart_settings(FILE *); double single(int, int, int, int, double, double, double, double &); - void *extract(char *, int &); + void *extract(const char *, int &); protected: double cut_global; double **prefactor; double **cut; void allocate(); }; } #endif #endif /* ERROR/WARNING messages: E: Illegal ... command Self-explanatory. Check the input script syntax and compare to the documentation for the command. You can use -echo screen as a command-line option when running LAMMPS to see the offending line. E: Incorrect args for pair coefficients Self-explanatory. Check the input script or data file. */ diff --git a/src/pair_table.cpp b/src/pair_table.cpp index c27c667ab..b2c34d98b 100644 --- a/src/pair_table.cpp +++ b/src/pair_table.cpp @@ -1,961 +1,962 @@ /* ---------------------------------------------------------------------- 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 author: Paul Crozier (SNL) ------------------------------------------------------------------------- */ #include "mpi.h" #include "math.h" #include "stdlib.h" #include "string.h" #include "pair_table.h" #include "atom.h" #include "force.h" #include "comm.h" #include "neigh_list.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define LOOKUP 0 #define LINEAR 1 #define SPLINE 2 #define BITMAP 3 #define R 1 #define RSQ 2 #define BMP 3 #define MAXLINE 1024 /* ---------------------------------------------------------------------- */ PairTable::PairTable(LAMMPS *lmp) : Pair(lmp) { ntables = 0; tables = NULL; } /* ---------------------------------------------------------------------- */ PairTable::~PairTable() { for (int m = 0; m < ntables; m++) free_table(&tables[m]); memory->sfree(tables); if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(tabindex); } } /* ---------------------------------------------------------------------- */ void PairTable::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype,itable; double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair; double rsq,factor_lj,fraction,value,a,b; int *ilist,*jlist,*numneigh,**firstneigh; Table *tb; union_int_float_t rsq_lookup; int tlm1 = tablength - 1; evdwl = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; double **x = atom->x; double **f = atom->f; int *type = atom->type; int nlocal = atom->nlocal; double *special_lj = force->special_lj; int newton_pair = force->newton_pair; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // loop over neighbors of my atoms for (ii = 0; ii < inum; ii++) { i = ilist[ii]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; factor_lj = special_lj[sbmask(j)]; j &= NEIGHMASK; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; jtype = type[j]; if (rsq < cutsq[itype][jtype]) { tb = &tables[tabindex[itype][jtype]]; if (rsq < tb->innersq) error->one(FLERR,"Pair distance < table inner cutoff"); if (tabstyle == LOOKUP) { itable = static_cast ((rsq - tb->innersq) * tb->invdelta); if (itable >= tlm1) error->one(FLERR,"Pair distance > table outer cutoff"); fpair = factor_lj * tb->f[itable]; } else if (tabstyle == LINEAR) { itable = static_cast ((rsq - tb->innersq) * tb->invdelta); if (itable >= tlm1) error->one(FLERR,"Pair distance > table outer cutoff"); fraction = (rsq - tb->rsq[itable]) * tb->invdelta; value = tb->f[itable] + fraction*tb->df[itable]; fpair = factor_lj * value; } else if (tabstyle == SPLINE) { itable = static_cast ((rsq - tb->innersq) * tb->invdelta); if (itable >= tlm1) error->one(FLERR,"Pair distance > table outer cutoff"); b = (rsq - tb->rsq[itable]) * tb->invdelta; a = 1.0 - b; value = a * tb->f[itable] + b * tb->f[itable+1] + ((a*a*a-a)*tb->f2[itable] + (b*b*b-b)*tb->f2[itable+1]) * tb->deltasq6; fpair = factor_lj * value; } else { rsq_lookup.f = rsq; itable = rsq_lookup.i & tb->nmask; itable >>= tb->nshiftbits; fraction = (rsq_lookup.f - tb->rsq[itable]) * tb->drsq[itable]; value = tb->f[itable] + fraction*tb->df[itable]; fpair = factor_lj * value; } f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; if (newton_pair || j < nlocal) { f[j][0] -= delx*fpair; f[j][1] -= dely*fpair; f[j][2] -= delz*fpair; } if (eflag) { if (tabstyle == LOOKUP) evdwl = tb->e[itable]; else if (tabstyle == LINEAR || tabstyle == BITMAP) evdwl = tb->e[itable] + fraction*tb->de[itable]; else evdwl = a * tb->e[itable] + b * tb->e[itable+1] + ((a*a*a-a)*tb->e2[itable] + (b*b*b-b)*tb->e2[itable+1]) * tb->deltasq6; evdwl *= factor_lj; } if (evflag) ev_tally(i,j,nlocal,newton_pair, evdwl,0.0,fpair,delx,dely,delz); } } } if (vflag_fdotr) virial_fdotr_compute(); } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairTable::allocate() { allocated = 1; int nt = atom->ntypes; memory->create(setflag,nt+1,nt+1,"pair:setflag"); for (int i = 1; i <= nt; i++) for (int j = i; j <= nt; j++) setflag[i][j] = 0; memory->create(cutsq,nt+1,nt+1,"pair:cutsq"); memory->create(tabindex,nt+1,nt+1,"pair:tabindex"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairTable::settings(int narg, char **arg) { if (narg != 2) error->all(FLERR,"Illegal pair_style command"); // new settings if (strcmp(arg[0],"lookup") == 0) tabstyle = LOOKUP; else if (strcmp(arg[0],"linear") == 0) tabstyle = LINEAR; else if (strcmp(arg[0],"spline") == 0) tabstyle = SPLINE; else if (strcmp(arg[0],"bitmap") == 0) tabstyle = BITMAP; else error->all(FLERR,"Unknown table style in pair_style command"); tablength = force->inumeric(arg[1]); if (tablength < 2) error->all(FLERR,"Illegal number of pair table entries"); // delete old tables, since cannot just change settings for (int m = 0; m < ntables; m++) free_table(&tables[m]); memory->sfree(tables); if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(tabindex); } allocated = 0; ntables = 0; tables = NULL; } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairTable::coeff(int narg, char **arg) { if (narg != 4 && narg != 5) error->all(FLERR,"Illegal pair_coeff command"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); int me; MPI_Comm_rank(world,&me); tables = (Table *) memory->srealloc(tables,(ntables+1)*sizeof(Table),"pair:tables"); Table *tb = &tables[ntables]; null_table(tb); if (me == 0) read_table(tb,arg[2],arg[3]); bcast_table(tb); // set table cutoff if (narg == 5) tb->cut = force->numeric(arg[4]); else if (tb->rflag) tb->cut = tb->rhi; else tb->cut = tb->rfile[tb->ninput-1]; // error check on table parameters // insure cutoff is within table // for BITMAP tables, file values can be in non-ascending order if (tb->ninput <= 1) error->one(FLERR,"Invalid pair table length"); double rlo,rhi; if (tb->rflag == 0) { rlo = tb->rfile[0]; rhi = tb->rfile[tb->ninput-1]; } else { rlo = tb->rlo; rhi = tb->rhi; } if (tb->cut <= rlo || tb->cut > rhi) error->all(FLERR,"Invalid pair table cutoff"); if (rlo <= 0.0) error->all(FLERR,"Invalid pair table cutoff"); // match = 1 if don't need to spline read-in tables // this is only the case if r values needed by final tables // exactly match r values read from file // for tabstyle SPLINE, always need to build spline tables tb->match = 0; if (tabstyle == LINEAR && tb->ninput == tablength && tb->rflag == RSQ && tb->rhi == tb->cut) tb->match = 1; if (tabstyle == BITMAP && tb->ninput == 1 << tablength && tb->rflag == BMP && tb->rhi == tb->cut) tb->match = 1; if (tb->rflag == BMP && tb->match == 0) error->all(FLERR,"Bitmapped table in file does not match requested table"); // spline read-in values and compute r,e,f vectors within table if (tb->match == 0) spline_table(tb); compute_table(tb); // store ptr to table in tabindex int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { tabindex[i][j] = ntables; setflag[i][j] = 1; count++; } } if (count == 0) error->all(FLERR,"Illegal pair_coeff command"); ntables++; } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairTable::init_one(int i, int j) { if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set"); tabindex[j][i] = tabindex[i][j]; return tables[tabindex[i][j]].cut; } /* ---------------------------------------------------------------------- read a table section from a tabulated potential file only called by proc 0 this function sets these values in Table: ninput,rfile,efile,ffile,rflag,rlo,rhi,fpflag,fplo,fphi,ntablebits ------------------------------------------------------------------------- */ void PairTable::read_table(Table *tb, char *file, char *keyword) { char line[MAXLINE]; // open file FILE *fp = fopen(file,"r"); if (fp == NULL) { char str[128]; sprintf(str,"Cannot open file %s",file); error->one(FLERR,str); } // loop until section found with matching keyword while (1) { if (fgets(line,MAXLINE,fp) == NULL) error->one(FLERR,"Did not find keyword in table file"); if (strspn(line," \t\n\r") == strlen(line)) continue; // blank line if (line[0] == '#') continue; // comment if (strstr(line,keyword) == line) break; // matching keyword fgets(line,MAXLINE,fp); // no match, skip section param_extract(tb,line); fgets(line,MAXLINE,fp); for (int i = 0; i < tb->ninput; i++) fgets(line,MAXLINE,fp); } // read args on 2nd line of section // allocate table arrays for file values fgets(line,MAXLINE,fp); param_extract(tb,line); memory->create(tb->rfile,tb->ninput,"pair:rfile"); memory->create(tb->efile,tb->ninput,"pair:efile"); memory->create(tb->ffile,tb->ninput,"pair:ffile"); // setup bitmap parameters for table to read in tb->ntablebits = 0; int masklo,maskhi,nmask,nshiftbits; if (tb->rflag == BMP) { while (1 << tb->ntablebits < tb->ninput) tb->ntablebits++; if (1 << tb->ntablebits != tb->ninput) error->one(FLERR,"Bitmapped table is incorrect length in table file"); init_bitmap(tb->rlo,tb->rhi,tb->ntablebits,masklo,maskhi,nmask,nshiftbits); } // read r,e,f table values from file // if rflag set, compute r // if rflag not set, use r from file int itmp; double rtmp; union_int_float_t rsq_lookup; fgets(line,MAXLINE,fp); for (int i = 0; i < tb->ninput; i++) { fgets(line,MAXLINE,fp); sscanf(line,"%d %lg %lg %lg",&itmp,&rtmp,&tb->efile[i],&tb->ffile[i]); if (tb->rflag == R) rtmp = tb->rlo + (tb->rhi - tb->rlo)*i/(tb->ninput-1); else if (tb->rflag == RSQ) { rtmp = tb->rlo*tb->rlo + (tb->rhi*tb->rhi - tb->rlo*tb->rlo)*i/(tb->ninput-1); rtmp = sqrt(rtmp); } else if (tb->rflag == BMP) { rsq_lookup.i = i << nshiftbits; rsq_lookup.i |= masklo; if (rsq_lookup.f < tb->rlo*tb->rlo) { rsq_lookup.i = i << nshiftbits; rsq_lookup.i |= maskhi; } rtmp = sqrtf(rsq_lookup.f); } tb->rfile[i] = rtmp; } // close file fclose(fp); } /* ---------------------------------------------------------------------- broadcast read-in table info from proc 0 to other procs this function communicates these values in Table: ninput,rfile,efile,ffile,rflag,rlo,rhi,fpflag,fplo,fphi ------------------------------------------------------------------------- */ void PairTable::bcast_table(Table *tb) { MPI_Bcast(&tb->ninput,1,MPI_INT,0,world); int me; MPI_Comm_rank(world,&me); if (me > 0) { memory->create(tb->rfile,tb->ninput,"pair:rfile"); memory->create(tb->efile,tb->ninput,"pair:efile"); memory->create(tb->ffile,tb->ninput,"pair:ffile"); } MPI_Bcast(tb->rfile,tb->ninput,MPI_DOUBLE,0,world); MPI_Bcast(tb->efile,tb->ninput,MPI_DOUBLE,0,world); MPI_Bcast(tb->ffile,tb->ninput,MPI_DOUBLE,0,world); MPI_Bcast(&tb->rflag,1,MPI_INT,0,world); if (tb->rflag) { MPI_Bcast(&tb->rlo,1,MPI_DOUBLE,0,world); MPI_Bcast(&tb->rhi,1,MPI_DOUBLE,0,world); } MPI_Bcast(&tb->fpflag,1,MPI_INT,0,world); if (tb->fpflag) { MPI_Bcast(&tb->fplo,1,MPI_DOUBLE,0,world); MPI_Bcast(&tb->fphi,1,MPI_DOUBLE,0,world); } } /* ---------------------------------------------------------------------- build spline representation of e,f over entire range of read-in table this function sets these values in Table: e2file,f2file ------------------------------------------------------------------------- */ void PairTable::spline_table(Table *tb) { memory->create(tb->e2file,tb->ninput,"pair:e2file"); memory->create(tb->f2file,tb->ninput,"pair:f2file"); double ep0 = - tb->ffile[0]; double epn = - tb->ffile[tb->ninput-1]; spline(tb->rfile,tb->efile,tb->ninput,ep0,epn,tb->e2file); if (tb->fpflag == 0) { tb->fplo = (tb->ffile[1] - tb->ffile[0]) / (tb->rfile[1] - tb->rfile[0]); tb->fphi = (tb->ffile[tb->ninput-1] - tb->ffile[tb->ninput-2]) / (tb->rfile[tb->ninput-1] - tb->rfile[tb->ninput-2]); } double fp0 = tb->fplo; double fpn = tb->fphi; spline(tb->rfile,tb->ffile,tb->ninput,fp0,fpn,tb->f2file); } /* ---------------------------------------------------------------------- extract attributes from parameter line in table section format of line: N value R/RSQ/BITMAP lo hi FP fplo fphi N is required, other params are optional ------------------------------------------------------------------------- */ void PairTable::param_extract(Table *tb, char *line) { tb->ninput = 0; tb->rflag = 0; tb->fpflag = 0; char *word = strtok(line," \t\n\r\f"); while (word) { if (strcmp(word,"N") == 0) { word = strtok(NULL," \t\n\r\f"); tb->ninput = atoi(word); } else if (strcmp(word,"R") == 0 || strcmp(word,"RSQ") == 0 || strcmp(word,"BITMAP") == 0) { if (strcmp(word,"R") == 0) tb->rflag = R; else if (strcmp(word,"RSQ") == 0) tb->rflag = RSQ; else if (strcmp(word,"BITMAP") == 0) tb->rflag = BMP; word = strtok(NULL," \t\n\r\f"); tb->rlo = atof(word); word = strtok(NULL," \t\n\r\f"); tb->rhi = atof(word); } else if (strcmp(word,"FP") == 0) { tb->fpflag = 1; word = strtok(NULL," \t\n\r\f"); tb->fplo = atof(word); word = strtok(NULL," \t\n\r\f"); tb->fphi = atof(word); } else { printf("WORD: %s\n",word); error->one(FLERR,"Invalid keyword in pair table parameters"); } word = strtok(NULL," \t\n\r\f"); } if (tb->ninput == 0) error->one(FLERR,"Pair table parameters did not set N"); } /* ---------------------------------------------------------------------- compute r,e,f vectors from splined values ------------------------------------------------------------------------- */ void PairTable::compute_table(Table *tb) { int tlm1 = tablength-1; // inner = inner table bound // cut = outer table bound // delta = table spacing in rsq for N-1 bins double inner; if (tb->rflag) inner = tb->rlo; else inner = tb->rfile[0]; tb->innersq = inner*inner; tb->delta = (tb->cut*tb->cut - tb->innersq) / tlm1; tb->invdelta = 1.0/tb->delta; // direct lookup tables // N-1 evenly spaced bins in rsq from inner to cut // e,f = value at midpt of bin // e,f are N-1 in length since store 1 value at bin midpt // f is converted to f/r when stored in f[i] // e,f are never a match to read-in values, always computed via spline interp if (tabstyle == LOOKUP) { memory->create(tb->e,tlm1,"pair:e"); memory->create(tb->f,tlm1,"pair:f"); double r,rsq; for (int i = 0; i < tlm1; i++) { rsq = tb->innersq + (i+0.5)*tb->delta; r = sqrt(rsq); tb->e[i] = splint(tb->rfile,tb->efile,tb->e2file,tb->ninput,r); tb->f[i] = splint(tb->rfile,tb->ffile,tb->f2file,tb->ninput,r)/r; } } // linear tables // N-1 evenly spaced bins in rsq from inner to cut // rsq,e,f = value at lower edge of bin // de,df values = delta from lower edge to upper edge of bin // rsq,e,f are N in length so de,df arrays can compute difference // f is converted to f/r when stored in f[i] // e,f can match read-in values, else compute via spline interp if (tabstyle == LINEAR) { memory->create(tb->rsq,tablength,"pair:rsq"); memory->create(tb->e,tablength,"pair:e"); memory->create(tb->f,tablength,"pair:f"); memory->create(tb->de,tlm1,"pair:de"); memory->create(tb->df,tlm1,"pair:df"); double r,rsq; for (int i = 0; i < tablength; i++) { rsq = tb->innersq + i*tb->delta; r = sqrt(rsq); tb->rsq[i] = rsq; if (tb->match) { tb->e[i] = tb->efile[i]; tb->f[i] = tb->ffile[i]/r; } else { tb->e[i] = splint(tb->rfile,tb->efile,tb->e2file,tb->ninput,r); tb->f[i] = splint(tb->rfile,tb->ffile,tb->f2file,tb->ninput,r)/r; } } for (int i = 0; i < tlm1; i++) { tb->de[i] = tb->e[i+1] - tb->e[i]; tb->df[i] = tb->f[i+1] - tb->f[i]; } } // cubic spline tables // N-1 evenly spaced bins in rsq from inner to cut // rsq,e,f = value at lower edge of bin // e2,f2 = spline coefficient for each bin // rsq,e,f,e2,f2 are N in length so have N-1 spline bins // f is converted to f/r after e is splined // e,f can match read-in values, else compute via spline interp if (tabstyle == SPLINE) { memory->create(tb->rsq,tablength,"pair:rsq"); memory->create(tb->e,tablength,"pair:e"); memory->create(tb->f,tablength,"pair:f"); memory->create(tb->e2,tablength,"pair:e2"); memory->create(tb->f2,tablength,"pair:f2"); tb->deltasq6 = tb->delta*tb->delta / 6.0; double r,rsq; for (int i = 0; i < tablength; i++) { rsq = tb->innersq + i*tb->delta; r = sqrt(rsq); tb->rsq[i] = rsq; if (tb->match) { tb->e[i] = tb->efile[i]; tb->f[i] = tb->ffile[i]/r; } else { tb->e[i] = splint(tb->rfile,tb->efile,tb->e2file,tb->ninput,r); tb->f[i] = splint(tb->rfile,tb->ffile,tb->f2file,tb->ninput,r); } } // ep0,epn = dE/dr at inner and at cut double ep0 = - tb->f[0]; double epn = - tb->f[tlm1]; spline(tb->rsq,tb->e,tablength,ep0,epn,tb->e2); // fp0,fpn = dh/dg at inner and at cut // h(r) = f(r)/r and g(r) = r^2 // dh/dg = (1/r df/dr - f/r^2) / 2r // dh/dg in secant approx = (f(r2)/r2 - f(r1)/r1) / (g(r2) - g(r1)) double fp0,fpn; double secant_factor = 0.1; if (tb->fpflag) fp0 = (tb->fplo/sqrt(tb->innersq) - tb->f[0]/tb->innersq) / (2.0 * sqrt(tb->innersq)); else { double rsq1 = tb->innersq; double rsq2 = rsq1 + secant_factor*tb->delta; fp0 = (splint(tb->rfile,tb->ffile,tb->f2file,tb->ninput,sqrt(rsq2)) / sqrt(rsq2) - tb->f[0] / sqrt(rsq1)) / (secant_factor*tb->delta); } if (tb->fpflag && tb->cut == tb->rfile[tb->ninput-1]) fpn = (tb->fphi/tb->cut - tb->f[tlm1]/(tb->cut*tb->cut)) / (2.0 * tb->cut); else { double rsq2 = tb->cut * tb->cut; double rsq1 = rsq2 - secant_factor*tb->delta; fpn = (tb->f[tlm1] / sqrt(rsq2) - splint(tb->rfile,tb->ffile,tb->f2file,tb->ninput,sqrt(rsq1)) / sqrt(rsq1)) / (secant_factor*tb->delta); } for (int i = 0; i < tablength; i++) tb->f[i] /= sqrt(tb->rsq[i]); spline(tb->rsq,tb->f,tablength,fp0,fpn,tb->f2); } // bitmapped linear tables // 2^N bins from inner to cut, spaced in bitmapped manner // f is converted to f/r when stored in f[i] // e,f can match read-in values, else compute via spline interp if (tabstyle == BITMAP) { double r; union_int_float_t rsq_lookup; int masklo,maskhi; // linear lookup tables of length ntable = 2^n // stored value = value at lower edge of bin init_bitmap(inner,tb->cut,tablength,masklo,maskhi,tb->nmask,tb->nshiftbits); int ntable = 1 << tablength; int ntablem1 = ntable - 1; memory->create(tb->rsq,ntable,"pair:rsq"); memory->create(tb->e,ntable,"pair:e"); memory->create(tb->f,ntable,"pair:f"); memory->create(tb->de,ntable,"pair:de"); memory->create(tb->df,ntable,"pair:df"); memory->create(tb->drsq,ntable,"pair:drsq"); union_int_float_t minrsq_lookup; minrsq_lookup.i = 0 << tb->nshiftbits; minrsq_lookup.i |= maskhi; for (int i = 0; i < ntable; i++) { rsq_lookup.i = i << tb->nshiftbits; rsq_lookup.i |= masklo; if (rsq_lookup.f < tb->innersq) { rsq_lookup.i = i << tb->nshiftbits; rsq_lookup.i |= maskhi; } r = sqrtf(rsq_lookup.f); tb->rsq[i] = rsq_lookup.f; if (tb->match) { tb->e[i] = tb->efile[i]; tb->f[i] = tb->ffile[i]/r; } else { tb->e[i] = splint(tb->rfile,tb->efile,tb->e2file,tb->ninput,r); tb->f[i] = splint(tb->rfile,tb->ffile,tb->f2file,tb->ninput,r)/r; } minrsq_lookup.f = MIN(minrsq_lookup.f,rsq_lookup.f); } tb->innersq = minrsq_lookup.f; for (int i = 0; i < ntablem1; i++) { tb->de[i] = tb->e[i+1] - tb->e[i]; tb->df[i] = tb->f[i+1] - tb->f[i]; tb->drsq[i] = 1.0/(tb->rsq[i+1] - tb->rsq[i]); } // get the delta values for the last table entries // tables are connected periodically between 0 and ntablem1 tb->de[ntablem1] = tb->e[0] - tb->e[ntablem1]; tb->df[ntablem1] = tb->f[0] - tb->f[ntablem1]; tb->drsq[ntablem1] = 1.0/(tb->rsq[0] - tb->rsq[ntablem1]); // get the correct delta values at itablemax // smallest r is in bin itablemin // largest r is in bin itablemax, which is itablemin-1, // or ntablem1 if itablemin=0 // deltas at itablemax only needed if corresponding rsq < cut*cut // if so, compute deltas between rsq and cut*cut // if tb->match, data at cut*cut is unavailable, so we'll take // deltas at itablemax-1 as a good approximation double e_tmp,f_tmp; int itablemin = minrsq_lookup.i & tb->nmask; itablemin >>= tb->nshiftbits; int itablemax = itablemin - 1; if (itablemin == 0) itablemax = ntablem1; int itablemaxm1 = itablemax - 1; if (itablemax == 0) itablemaxm1 = ntablem1; rsq_lookup.i = itablemax << tb->nshiftbits; rsq_lookup.i |= maskhi; if (rsq_lookup.f < tb->cut*tb->cut) { if (tb->match) { tb->de[itablemax] = tb->de[itablemaxm1]; tb->df[itablemax] = tb->df[itablemaxm1]; tb->drsq[itablemax] = tb->drsq[itablemaxm1]; } else { rsq_lookup.f = tb->cut*tb->cut; r = sqrtf(rsq_lookup.f); e_tmp = splint(tb->rfile,tb->efile,tb->e2file,tb->ninput,r); f_tmp = splint(tb->rfile,tb->ffile,tb->f2file,tb->ninput,r)/r; tb->de[itablemax] = e_tmp - tb->e[itablemax]; tb->df[itablemax] = f_tmp - tb->f[itablemax]; tb->drsq[itablemax] = 1.0/(rsq_lookup.f - tb->rsq[itablemax]); } } } } /* ---------------------------------------------------------------------- set all ptrs in a table to NULL, so can be freed safely ------------------------------------------------------------------------- */ void PairTable::null_table(Table *tb) { tb->rfile = tb->efile = tb->ffile = NULL; tb->e2file = tb->f2file = NULL; tb->rsq = tb->drsq = tb->e = tb->de = NULL; tb->f = tb->df = tb->e2 = tb->f2 = NULL; } /* ---------------------------------------------------------------------- free all arrays in a table ------------------------------------------------------------------------- */ void PairTable::free_table(Table *tb) { memory->destroy(tb->rfile); memory->destroy(tb->efile); memory->destroy(tb->ffile); memory->destroy(tb->e2file); memory->destroy(tb->f2file); memory->destroy(tb->rsq); memory->destroy(tb->drsq); memory->destroy(tb->e); memory->destroy(tb->de); memory->destroy(tb->f); memory->destroy(tb->df); memory->destroy(tb->e2); memory->destroy(tb->f2); } /* ---------------------------------------------------------------------- spline and splint routines modified from Numerical Recipes ------------------------------------------------------------------------- */ void PairTable::spline(double *x, double *y, int n, double yp1, double ypn, double *y2) { int i,k; double p,qn,sig,un; double *u = new double[n]; if (yp1 > 0.99e30) y2[0] = u[0] = 0.0; else { y2[0] = -0.5; u[0] = (3.0/(x[1]-x[0])) * ((y[1]-y[0]) / (x[1]-x[0]) - yp1); } for (i = 1; i < n-1; i++) { sig = (x[i]-x[i-1]) / (x[i+1]-x[i-1]); p = sig*y2[i-1] + 2.0; y2[i] = (sig-1.0) / p; u[i] = (y[i+1]-y[i]) / (x[i+1]-x[i]) - (y[i]-y[i-1]) / (x[i]-x[i-1]); u[i] = (6.0*u[i] / (x[i+1]-x[i-1]) - sig*u[i-1]) / p; } if (ypn > 0.99e30) qn = un = 0.0; else { qn = 0.5; un = (3.0/(x[n-1]-x[n-2])) * (ypn - (y[n-1]-y[n-2]) / (x[n-1]-x[n-2])); } y2[n-1] = (un-qn*u[n-2]) / (qn*y2[n-2] + 1.0); for (k = n-2; k >= 0; k--) y2[k] = y2[k]*y2[k+1] + u[k]; delete [] u; } /* ---------------------------------------------------------------------- */ double PairTable::splint(double *xa, double *ya, double *y2a, int n, double x) { int klo,khi,k; double h,b,a,y; klo = 0; khi = n-1; while (khi-klo > 1) { k = (khi+klo) >> 1; if (xa[k] > x) khi = k; else klo = k; } h = xa[khi]-xa[klo]; a = (xa[khi]-x) / h; b = (x-xa[klo]) / h; y = a*ya[klo] + b*ya[khi] + ((a*a*a-a)*y2a[klo] + (b*b*b-b)*y2a[khi]) * (h*h)/6.0; return y; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairTable::write_restart(FILE *fp) { write_restart_settings(fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairTable::read_restart(FILE *fp) { read_restart_settings(fp); allocate(); } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairTable::write_restart_settings(FILE *fp) { fwrite(&tabstyle,sizeof(int),1,fp); fwrite(&tablength,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairTable::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&tabstyle,sizeof(int),1,fp); fread(&tablength,sizeof(int),1,fp); } MPI_Bcast(&tabstyle,1,MPI_DOUBLE,0,world); MPI_Bcast(&tablength,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- */ double PairTable::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { int itable; double fraction,value,a,b,phi; int tlm1 = tablength - 1; Table *tb = &tables[tabindex[itype][jtype]]; if (rsq < tb->innersq) error->one(FLERR,"Pair distance < table inner cutoff"); if (tabstyle == LOOKUP) { itable = static_cast ((rsq-tb->innersq) * tb->invdelta); if (itable >= tlm1) error->one(FLERR,"Pair distance > table outer cutoff"); fforce = factor_lj * tb->f[itable]; } else if (tabstyle == LINEAR) { itable = static_cast ((rsq-tb->innersq) * tb->invdelta); if (itable >= tlm1) error->one(FLERR,"Pair distance > table outer cutoff"); fraction = (rsq - tb->rsq[itable]) * tb->invdelta; value = tb->f[itable] + fraction*tb->df[itable]; fforce = factor_lj * value; } else if (tabstyle == SPLINE) { itable = static_cast ((rsq-tb->innersq) * tb->invdelta); if (itable >= tlm1) error->one(FLERR,"Pair distance > table outer cutoff"); b = (rsq - tb->rsq[itable]) * tb->invdelta; a = 1.0 - b; value = a * tb->f[itable] + b * tb->f[itable+1] + ((a*a*a-a)*tb->f2[itable] + (b*b*b-b)*tb->f2[itable+1]) * tb->deltasq6; fforce = factor_lj * value; } else { union_int_float_t rsq_lookup; rsq_lookup.f = rsq; itable = rsq_lookup.i & tb->nmask; itable >>= tb->nshiftbits; fraction = (rsq_lookup.f - tb->rsq[itable]) * tb->drsq[itable]; value = tb->f[itable] + fraction*tb->df[itable]; fforce = factor_lj * value; } if (tabstyle == LOOKUP) phi = tb->e[itable]; else if (tabstyle == LINEAR || tabstyle == BITMAP) phi = tb->e[itable] + fraction*tb->de[itable]; else phi = a * tb->e[itable] + b * tb->e[itable+1] + ((a*a*a-a)*tb->e2[itable] + (b*b*b-b)*tb->e2[itable+1]) * tb->deltasq6; return factor_lj*phi; } /* ---------------------------------------------------------------------- return the Coulomb cutoff for tabled potentials called by KSpace solvers which require that all pairwise cutoffs be the same loop over all tables not just those indexed by tabindex[i][j] since no way to know which tables are active since pair::init() not yet called ------------------------------------------------------------------------- */ -void *PairTable::extract(char *str, int &dim) +void *PairTable::extract(const char *str, int &dim) { if (strcmp(str,"cut_coul") != 0) return NULL; if (ntables == 0) error->all(FLERR,"All pair coeffs are not set"); double cut_coul = tables[0].cut; for (int m = 1; m < ntables; m++) if (tables[m].cut != cut_coul) - error->all(FLERR,"Pair table cutoffs must all be equal to use with KSpace"); + error->all(FLERR, + "Pair table cutoffs must all be equal to use with KSpace"); dim = 0; return &tables[0].cut; } diff --git a/src/pair_table.h b/src/pair_table.h index 80c8f556c..11ffa4d75 100644 --- a/src/pair_table.h +++ b/src/pair_table.h @@ -1,146 +1,146 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ #ifdef PAIR_CLASS PairStyle(table,PairTable) #else #ifndef LMP_PAIR_TABLE_H #define LMP_PAIR_TABLE_H #include "pair.h" namespace LAMMPS_NS { class PairTable : public Pair { public: PairTable(class LAMMPS *); virtual ~PairTable(); virtual void compute(int, int); void settings(int, char **); void coeff(int, char **); double init_one(int, int); void write_restart(FILE *); void read_restart(FILE *); void write_restart_settings(FILE *); void read_restart_settings(FILE *); double single(int, int, int, int, double, double, double, double &); - void *extract(char *, int &); + void *extract(const char *, int &); protected: int tabstyle,tablength; enum {LOOKUP=0, LINEAR=1, SPLINE=2, BITMAP=3}; struct Table { int ninput,rflag,fpflag,match,ntablebits; int nshiftbits,nmask; double rlo,rhi,fplo,fphi,cut; double *rfile,*efile,*ffile; double *e2file,*f2file; double innersq,delta,invdelta,deltasq6; double *rsq,*drsq,*e,*de,*f,*df,*e2,*f2; }; int ntables; Table *tables; int **tabindex; void allocate(); void read_table(Table *, char *, char *); void param_extract(Table *, char *); void bcast_table(Table *); void spline_table(Table *); void compute_table(Table *); void null_table(Table *); void free_table(Table *); void spline(double *, double *, int, double, double, double *); double splint(double *, double *, double *, int, double); }; } #endif #endif /* ERROR/WARNING messages: E: Pair distance < table inner cutoff Two atoms are closer together than the pairwise table allows. E: Pair distance > table outer cutoff Two atoms are further apart than the pairwise table allows. E: Illegal ... command Self-explanatory. Check the input script syntax and compare to the documentation for the command. You can use -echo screen as a command-line option when running LAMMPS to see the offending line. E: Unknown table style in pair_style command Style of table is invalid for use with pair_style table command. E: Illegal number of pair table entries There must be at least 2 table entries. E: Invalid pair table length Length of read-in pair table is invalid E: Invalid pair table cutoff Cutoffs in pair_coeff command are not valid with read-in pair table. E: Bitmapped table in file does not match requested table Setting for bitmapped table in pair_coeff command must match table in file exactly. E: All pair coeffs are not set All pair coefficients must be set in the data file or by the pair_coeff command before running a simulation. E: Cannot open file %s The specified file cannot be opened. Check that the path and name are correct. E: Did not find keyword in table file Keyword used in pair_coeff command was not found in table file. E: Bitmapped table is incorrect length in table file Number of table entries is not a correct power of 2. E: Invalid keyword in pair table parameters Keyword used in list of table parameters is not recognized. E: Pair table parameters did not set N List of pair table parameters must include N setting. E: Pair table cutoffs must all be equal to use with KSpace When using pair style table with a long-range KSpace solver, the cutoffs for all atom type pairs must all be the same, since the long-range solver starts at that cutoff. */ diff --git a/src/read_data.cpp b/src/read_data.cpp index 872076b11..31addac3a 100644 --- a/src/read_data.cpp +++ b/src/read_data.cpp @@ -1,1448 +1,1448 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ #include "lmptype.h" #include "math.h" #include "mpi.h" #include "string.h" #include "stdlib.h" #include "ctype.h" #include "read_data.h" #include "atom.h" #include "atom_vec.h" #include "atom_vec_ellipsoid.h" #include "atom_vec_line.h" #include "atom_vec_tri.h" #include "comm.h" #include "update.h" #include "force.h" #include "pair.h" #include "domain.h" #include "bond.h" #include "angle.h" #include "dihedral.h" #include "improper.h" #include "error.h" #include "memory.h" #include "special.h" using namespace LAMMPS_NS; #define MAXLINE 256 #define LB_FACTOR 1.1 #define CHUNK 1024 #define DELTA 4 // must be 2 or larger // customize for new sections #define NSECTIONS 23 // change when add to header::section_keywords /* ---------------------------------------------------------------------- */ ReadData::ReadData(LAMMPS *lmp) : Pointers(lmp) { MPI_Comm_rank(world,&me); line = new char[MAXLINE]; keyword = new char[MAXLINE]; buffer = new char[CHUNK*MAXLINE]; narg = maxarg = 0; arg = NULL; // customize for new sections // pointers to atom styles that store extra info nellipsoids = 0; avec_ellipsoid = (AtomVecEllipsoid *) atom->style_match("ellipsoid"); nlines = 0; avec_line = (AtomVecLine *) atom->style_match("line"); ntris = 0; avec_tri = (AtomVecTri *) atom->style_match("tri"); } /* ---------------------------------------------------------------------- */ ReadData::~ReadData() { delete [] line; delete [] keyword; delete [] buffer; memory->sfree(arg); } /* ---------------------------------------------------------------------- */ void ReadData::command(int narg, char **arg) { if (narg != 1) error->all(FLERR,"Illegal read_data command"); if (domain->box_exist) error->all(FLERR,"Cannot read_data after simulation box is defined"); if (domain->dimension == 2 && domain->zperiodic == 0) error->all(FLERR,"Cannot run 2d simulation with nonperiodic Z dimension"); // scan data file to determine max topology needed per atom // allocate initial topology arrays if (atom->molecular) { if (me == 0) { if (screen) fprintf(screen,"Scanning data file ...\n"); open(arg[0]); header(0); scan(atom->bond_per_atom,atom->angle_per_atom, atom->dihedral_per_atom,atom->improper_per_atom); if (compressed) pclose(fp); else fclose(fp); atom->bond_per_atom += atom->extra_bond_per_atom; } MPI_Bcast(&atom->bond_per_atom,1,MPI_INT,0,world); MPI_Bcast(&atom->angle_per_atom,1,MPI_INT,0,world); MPI_Bcast(&atom->dihedral_per_atom,1,MPI_INT,0,world); MPI_Bcast(&atom->improper_per_atom,1,MPI_INT,0,world); } else atom->bond_per_atom = atom->angle_per_atom = atom->dihedral_per_atom = atom->improper_per_atom = 0; // read header info if (me == 0) { if (screen) fprintf(screen,"Reading data file ...\n"); open(arg[0]); } header(1); domain->box_exist = 1; // problem setup using info from header update->ntimestep = 0; int n; if (comm->nprocs == 1) n = static_cast (atom->natoms); else n = static_cast (LB_FACTOR * atom->natoms / comm->nprocs); atom->allocate_type_arrays(); atom->avec->grow(n); n = atom->nmax; domain->print_box(" "); domain->set_initial_box(); domain->set_global_box(); comm->set_proc_grid(); domain->set_local_box(); // customize for new sections // read rest of file in free format int atomflag = 0; while (strlen(keyword)) { if (strcmp(keyword,"Atoms") == 0) { atoms(); atomflag = 1; } else if (strcmp(keyword,"Velocities") == 0) { if (atomflag == 0) error->all(FLERR,"Must read Atoms before Velocities"); velocities(); } else if (strcmp(keyword,"Ellipsoids") == 0) { if (!avec_ellipsoid) error->all(FLERR,"Invalid data file section: Ellipsoids"); if (atomflag == 0) error->all(FLERR,"Must read Atoms before Ellipsoids"); bonus(nellipsoids,(AtomVec *) avec_ellipsoid,"ellipsoids"); } else if (strcmp(keyword,"Lines") == 0) { if (!avec_line) error->all(FLERR,"Invalid data file section: Lines"); if (atomflag == 0) error->all(FLERR,"Must read Atoms before Lines"); bonus(nlines,(AtomVec *) avec_line,"lines"); } else if (strcmp(keyword,"Triangles") == 0) { if (!avec_tri) error->all(FLERR,"Invalid data file section: Triangles"); if (atomflag == 0) error->all(FLERR,"Must read Atoms before Triangles"); bonus(ntris,(AtomVec *) avec_tri,"triangles"); } else if (strcmp(keyword,"Bonds") == 0) { if (atom->avec->bonds_allow == 0) error->all(FLERR,"Invalid data file section: Bonds"); if (atomflag == 0) error->all(FLERR,"Must read Atoms before Bonds"); bonds(); } else if (strcmp(keyword,"Angles") == 0) { if (atom->avec->angles_allow == 0) error->all(FLERR,"Invalid data file section: Angles"); if (atomflag == 0) error->all(FLERR,"Must read Atoms before Angles"); angles(); } else if (strcmp(keyword,"Dihedrals") == 0) { if (atom->avec->dihedrals_allow == 0) error->all(FLERR,"Invalid data file section: Dihedrals"); if (atomflag == 0) error->all(FLERR,"Must read Atoms before Dihedrals"); dihedrals(); } else if (strcmp(keyword,"Impropers") == 0) { if (atom->avec->impropers_allow == 0) error->all(FLERR,"Invalid data file section: Impropers"); if (atomflag == 0) error->all(FLERR,"Must read Atoms before Impropers"); impropers(); } else if (strcmp(keyword,"Masses") == 0) { mass(); } else if (strcmp(keyword,"Pair Coeffs") == 0) { if (force->pair == NULL) error->all(FLERR,"Must define pair_style before Pair Coeffs"); paircoeffs(); } else if (strcmp(keyword,"Bond Coeffs") == 0) { if (atom->avec->bonds_allow == 0) error->all(FLERR,"Invalid data file section: Bond Coeffs"); if (force->bond == NULL) error->all(FLERR,"Must define bond_style before Bond Coeffs"); bondcoeffs(); } else if (strcmp(keyword,"Angle Coeffs") == 0) { if (atom->avec->angles_allow == 0) error->all(FLERR,"Invalid data file section: Angle Coeffs"); if (force->angle == NULL) error->all(FLERR,"Must define angle_style before Angle Coeffs"); anglecoeffs(0); } else if (strcmp(keyword,"Dihedral Coeffs") == 0) { if (atom->avec->dihedrals_allow == 0) error->all(FLERR,"Invalid data file section: Dihedral Coeffs"); if (force->dihedral == NULL) error->all(FLERR,"Must define dihedral_style before Dihedral Coeffs"); dihedralcoeffs(0); } else if (strcmp(keyword,"Improper Coeffs") == 0) { if (atom->avec->impropers_allow == 0) error->all(FLERR,"Invalid data file section: Improper Coeffs"); if (force->improper == NULL) error->all(FLERR,"Must define improper_style before Improper Coeffs"); impropercoeffs(0); } else if (strcmp(keyword,"BondBond Coeffs") == 0) { if (atom->avec->angles_allow == 0) error->all(FLERR,"Invalid data file section: BondBond Coeffs"); if (force->angle == NULL) error->all(FLERR,"Must define angle_style before BondBond Coeffs"); anglecoeffs(1); } else if (strcmp(keyword,"BondAngle Coeffs") == 0) { if (atom->avec->angles_allow == 0) error->all(FLERR,"Invalid data file section: BondAngle Coeffs"); if (force->angle == NULL) error->all(FLERR,"Must define angle_style before BondAngle Coeffs"); anglecoeffs(2); } else if (strcmp(keyword,"MiddleBondTorsion Coeffs") == 0) { if (atom->avec->dihedrals_allow == 0) error->all(FLERR,"Invalid data file section: MiddleBondTorsion Coeffs"); if (force->dihedral == NULL) error->all(FLERR, "Must define dihedral_style before " "MiddleBondTorsion Coeffs"); dihedralcoeffs(1); } else if (strcmp(keyword,"EndBondTorsion Coeffs") == 0) { if (atom->avec->dihedrals_allow == 0) error->all(FLERR,"Invalid data file section: EndBondTorsion Coeffs"); if (force->dihedral == NULL) error->all(FLERR, "Must define dihedral_style before EndBondTorsion Coeffs"); dihedralcoeffs(2); } else if (strcmp(keyword,"AngleTorsion Coeffs") == 0) { if (atom->avec->dihedrals_allow == 0) error->all(FLERR,"Invalid data file section: AngleTorsion Coeffs"); if (force->dihedral == NULL) error->all(FLERR, "Must define dihedral_style before AngleTorsion Coeffs"); dihedralcoeffs(3); } else if (strcmp(keyword,"AngleAngleTorsion Coeffs") == 0) { if (atom->avec->dihedrals_allow == 0) error->all(FLERR,"Invalid data file section: AngleAngleTorsion Coeffs"); if (force->dihedral == NULL) error->all(FLERR, "Must define dihedral_style before " "AngleAngleTorsion Coeffs"); dihedralcoeffs(4); } else if (strcmp(keyword,"BondBond13 Coeffs") == 0) { if (atom->avec->dihedrals_allow == 0) error->all(FLERR,"Invalid data file section: BondBond13 Coeffs"); if (force->dihedral == NULL) error->all(FLERR,"Must define dihedral_style before BondBond13 Coeffs"); dihedralcoeffs(5); } else if (strcmp(keyword,"AngleAngle Coeffs") == 0) { if (atom->avec->impropers_allow == 0) error->all(FLERR,"Invalid data file section: AngleAngle Coeffs"); if (force->improper == NULL) error->all(FLERR,"Must define improper_style before AngleAngle Coeffs"); impropercoeffs(1); } else { char str[128]; sprintf(str,"Unknown identifier in data file: %s",keyword); error->all(FLERR,str); } parse_keyword(0,1); } // close file if (me == 0) { if (compressed) pclose(fp); else fclose(fp); } // error if natoms > 0 yet no atoms were read if (atom->natoms > 0 && atomflag == 0) error->all(FLERR,"No atoms in data file"); // create bond topology now that system is defined if (atom->molecular) { Special special(lmp); special.build(); } } /* ---------------------------------------------------------------------- read free-format header of data file if flag = 0, only called by proc 0 if flag = 1, called by all procs so bcast lines as read them 1st line and blank lines are skipped non-blank lines are checked for header keywords and leading value is read header ends with EOF or non-blank line containing no header keyword if EOF, line is set to blank line else line has first keyword line for rest of file ------------------------------------------------------------------------- */ void ReadData::header(int flag) { int n; char *ptr; // customize for new sections - char *section_keywords[NSECTIONS] = + const char *section_keywords[NSECTIONS] = {"Atoms","Velocities","Ellipsoids","Lines","Triangles", "Bonds","Angles","Dihedrals","Impropers", "Masses","Pair Coeffs","Bond Coeffs","Angle Coeffs", "Dihedral Coeffs","Improper Coeffs", "BondBond Coeffs","BondAngle Coeffs","MiddleBondTorsion Coeffs", "EndBondTorsion Coeffs","AngleTorsion Coeffs", "AngleAngleTorsion Coeffs","BondBond13 Coeffs","AngleAngle Coeffs"}; // skip 1st line of file if (me == 0) { char *eof = fgets(line,MAXLINE,fp); if (eof == NULL) error->one(FLERR,"Unexpected end of data file"); } // customize for new header lines while (1) { // read a line and bcast length if flag is set if (me == 0) { if (fgets(line,MAXLINE,fp) == NULL) n = 0; else n = strlen(line) + 1; } if (flag) MPI_Bcast(&n,1,MPI_INT,0,world); // if n = 0 then end-of-file so return with blank line if (n == 0) { line[0] = '\0'; return; } // bcast line if flag is set if (flag) MPI_Bcast(line,n,MPI_CHAR,0,world); // trim anything from '#' onward // if line is blank, continue if (ptr = strchr(line,'#')) *ptr = '\0'; if (strspn(line," \t\n\r") == strlen(line)) continue; // search line for header keyword and set corresponding variable if (strstr(line,"atoms")) sscanf(line,BIGINT_FORMAT,&atom->natoms); else if (strstr(line,"bonds")) sscanf(line,BIGINT_FORMAT,&atom->nbonds); else if (strstr(line,"angles")) sscanf(line,BIGINT_FORMAT,&atom->nangles); else if (strstr(line,"dihedrals")) sscanf(line,BIGINT_FORMAT, &atom->ndihedrals); else if (strstr(line,"impropers")) sscanf(line,BIGINT_FORMAT, &atom->nimpropers); else if (strstr(line,"atom types")) sscanf(line,"%d",&atom->ntypes); else if (strstr(line,"bond types")) sscanf(line,"%d",&atom->nbondtypes); else if (strstr(line,"angle types")) sscanf(line,"%d",&atom->nangletypes); else if (strstr(line,"dihedral types")) sscanf(line,"%d",&atom->ndihedraltypes); else if (strstr(line,"improper types")) sscanf(line,"%d",&atom->nimpropertypes); else if (strstr(line,"extra bond per atom")) sscanf(line,"%d",&atom->extra_bond_per_atom); else if (strstr(line,"ellipsoids")) { if (!avec_ellipsoid) error->all(FLERR,"No ellipsoids allowed with this atom style"); sscanf(line,BIGINT_FORMAT,&nellipsoids); } else if (strstr(line,"lines")) { if (!avec_line) error->all(FLERR,"No lines allowed with this atom style"); sscanf(line,BIGINT_FORMAT,&nlines); } else if (strstr(line,"triangles")) { if (!avec_tri) error->all(FLERR,"No triangles allowed with this atom style"); sscanf(line,BIGINT_FORMAT,&ntris); } else if (strstr(line,"xlo xhi")) sscanf(line,"%lg %lg",&domain->boxlo[0],&domain->boxhi[0]); else if (strstr(line,"ylo yhi")) sscanf(line,"%lg %lg",&domain->boxlo[1],&domain->boxhi[1]); else if (strstr(line,"zlo zhi")) sscanf(line,"%lg %lg",&domain->boxlo[2],&domain->boxhi[2]); else if (strstr(line,"xy xz yz")) { domain->triclinic = 1; sscanf(line,"%lg %lg %lg",&domain->xy,&domain->xz,&domain->yz); } else break; } // error check on total system size if (atom->natoms < 0 || atom->natoms > MAXBIGINT || atom->nbonds < 0 || atom->nbonds > MAXBIGINT || atom->nangles < 0 || atom->nangles > MAXBIGINT || atom->ndihedrals < 0 || atom->ndihedrals > MAXBIGINT || atom->nimpropers < 0 || atom->nimpropers > MAXBIGINT) { if (flag == 0) error->one(FLERR,"System in data file is too big"); else error->all(FLERR,"System in data file is too big"); } // check that exiting string is a valid section keyword parse_keyword(1,flag); for (n = 0; n < NSECTIONS; n++) if (strcmp(keyword,section_keywords[n]) == 0) break; if (n == NSECTIONS) { char str[128]; sprintf(str,"Unknown identifier in data file: %s",keyword); error->all(FLERR,str); } // error check on consistency of header values if ((atom->nbonds || atom->nbondtypes) && atom->avec->bonds_allow == 0) error->one(FLERR,"No bonds allowed with this atom style"); if ((atom->nangles || atom->nangletypes) && atom->avec->angles_allow == 0) error->one(FLERR,"No angles allowed with this atom style"); if ((atom->ndihedrals || atom->ndihedraltypes) && atom->avec->dihedrals_allow == 0) error->one(FLERR,"No dihedrals allowed with this atom style"); if ((atom->nimpropers || atom->nimpropertypes) && atom->avec->impropers_allow == 0) error->one(FLERR,"No impropers allowed with this atom style"); if (atom->nbonds > 0 && atom->nbondtypes <= 0) error->one(FLERR,"Bonds defined but no bond types"); if (atom->nangles > 0 && atom->nangletypes <= 0) error->one(FLERR,"Angles defined but no angle types"); if (atom->ndihedrals > 0 && atom->ndihedraltypes <= 0) error->one(FLERR,"Dihedrals defined but no dihedral types"); if (atom->nimpropers > 0 && atom->nimpropertypes <= 0) error->one(FLERR,"Impropers defined but no improper types"); } /* ---------------------------------------------------------------------- read all atoms ------------------------------------------------------------------------- */ void ReadData::atoms() { int i,m,nchunk; bigint nread = 0; bigint natoms = atom->natoms; while (nread < natoms) { if (natoms-nread > CHUNK) nchunk = CHUNK; else nchunk = natoms-nread; if (me == 0) { char *eof; m = 0; for (i = 0; i < nchunk; i++) { eof = fgets(&buffer[m],MAXLINE,fp); if (eof == NULL) error->one(FLERR,"Unexpected end of data file"); m += strlen(&buffer[m]); } m++; } MPI_Bcast(&m,1,MPI_INT,0,world); MPI_Bcast(buffer,m,MPI_CHAR,0,world); atom->data_atoms(nchunk,buffer); nread += nchunk; } // check that all atoms were assigned correctly bigint tmp = atom->nlocal; MPI_Allreduce(&tmp,&natoms,1,MPI_LMP_BIGINT,MPI_SUM,world); if (me == 0) { if (screen) fprintf(screen," " BIGINT_FORMAT " atoms\n",natoms); if (logfile) fprintf(logfile," " BIGINT_FORMAT " atoms\n",natoms); } if (natoms != atom->natoms) error->all(FLERR,"Did not assign all atoms correctly"); // if any atom ID < 0, error // if all atom IDs = 0, tag_enable = 0 // if any atom ID > 0, error if any atom ID == 0 // not checking if atom IDs > natoms or are unique int nlocal = atom->nlocal; int *tag = atom->tag; int flag = 0; for (int i = 0; i < nlocal; i++) if (tag[i] < 0) flag = 1; int flag_all; MPI_Allreduce(&flag,&flag_all,1,MPI_INT,MPI_SUM,world); if (flag_all) error->all(FLERR,"Invalid atom ID in Atoms section of data file"); flag = 0; for (int i = 0; i < nlocal; i++) if (tag[i] > 0) flag = 1; MPI_Allreduce(&flag,&flag_all,1,MPI_INT,MPI_MAX,world); if (flag_all == 0) atom->tag_enable = 0; if (atom->tag_enable) { flag = 0; for (int i = 0; i < nlocal; i++) if (tag[i] == 0) flag = 1; MPI_Allreduce(&flag,&flag_all,1,MPI_INT,MPI_SUM,world); if (flag_all) error->all(FLERR,"Invalid atom ID in Atoms section of data file"); } // create global mapping if (atom->map_style) { atom->map_init(); atom->map_set(); } } /* ---------------------------------------------------------------------- read all velocities to find atoms, must build atom map if not a molecular system ------------------------------------------------------------------------- */ void ReadData::velocities() { int i,m,nchunk; int mapflag = 0; if (atom->map_style == 0) { mapflag = 1; atom->map_style = 1; atom->map_init(); atom->map_set(); } bigint nread = 0; bigint natoms = atom->natoms; while (nread < natoms) { if (natoms-nread > CHUNK) nchunk = CHUNK; else nchunk = natoms-nread; if (me == 0) { char *eof; m = 0; for (i = 0; i < nchunk; i++) { eof = fgets(&buffer[m],MAXLINE,fp); if (eof == NULL) error->one(FLERR,"Unexpected end of data file"); m += strlen(&buffer[m]); } m++; } MPI_Bcast(&m,1,MPI_INT,0,world); MPI_Bcast(buffer,m,MPI_CHAR,0,world); atom->data_vels(nchunk,buffer); nread += nchunk; } if (mapflag) { atom->map_delete(); atom->map_style = 0; } if (me == 0) { if (screen) fprintf(screen," " BIGINT_FORMAT " velocities\n",natoms); if (logfile) fprintf(logfile," " BIGINT_FORMAT " velocities\n",natoms); } } /* ---------------------------------------------------------------------- read all bonus data to find atoms, must build atom map if not a molecular system ------------------------------------------------------------------------- */ -void ReadData::bonus(bigint nbonus, AtomVec *ptr, char *type) +void ReadData::bonus(bigint nbonus, AtomVec *ptr, const char *type) { int i,m,nchunk; int mapflag = 0; if (atom->map_style == 0) { mapflag = 1; atom->map_style = 1; atom->map_init(); atom->map_set(); } bigint nread = 0; bigint natoms = nbonus; while (nread < natoms) { if (natoms-nread > CHUNK) nchunk = CHUNK; else nchunk = natoms-nread; if (me == 0) { char *eof; m = 0; for (i = 0; i < nchunk; i++) { eof = fgets(&buffer[m],MAXLINE,fp); if (eof == NULL) error->one(FLERR,"Unexpected end of data file"); m += strlen(&buffer[m]); } m++; } MPI_Bcast(&m,1,MPI_INT,0,world); MPI_Bcast(buffer,m,MPI_CHAR,0,world); atom->data_bonus(nchunk,buffer,ptr); nread += nchunk; } if (mapflag) { atom->map_delete(); atom->map_style = 0; } if (me == 0) { if (screen) fprintf(screen," " BIGINT_FORMAT " %s\n",natoms,type); if (logfile) fprintf(logfile," " BIGINT_FORMAT " %s\n",natoms,type); } } /* ---------------------------------------------------------------------- */ void ReadData::bonds() { int i,m,nchunk; bigint nread = 0; bigint nbonds = atom->nbonds; while (nread < nbonds) { nchunk = MIN(nbonds-nread,CHUNK); if (me == 0) { char *eof; m = 0; for (i = 0; i < nchunk; i++) { eof = fgets(&buffer[m],MAXLINE,fp); if (eof == NULL) error->one(FLERR,"Unexpected end of data file"); m += strlen(&buffer[m]); } m++; } MPI_Bcast(&m,1,MPI_INT,0,world); MPI_Bcast(buffer,m,MPI_CHAR,0,world); atom->data_bonds(nchunk,buffer); nread += nchunk; } // check that bonds were assigned correctly int nlocal = atom->nlocal; bigint sum; bigint n = 0; for (i = 0; i < nlocal; i++) n += atom->num_bond[i]; MPI_Allreduce(&n,&sum,1,MPI_LMP_BIGINT,MPI_SUM,world); int factor = 1; if (!force->newton_bond) factor = 2; if (me == 0) { if (screen) fprintf(screen," " BIGINT_FORMAT " bonds\n",sum/factor); if (logfile) fprintf(logfile," " BIGINT_FORMAT " bonds\n",sum/factor); } if (sum != factor*atom->nbonds) error->all(FLERR,"Bonds assigned incorrectly"); } /* ---------------------------------------------------------------------- */ void ReadData::angles() { int i,m,nchunk; bigint nread = 0; bigint nangles = atom->nangles; while (nread < nangles) { nchunk = MIN(nangles-nread,CHUNK); if (me == 0) { char *eof; m = 0; for (i = 0; i < nchunk; i++) { eof = fgets(&buffer[m],MAXLINE,fp); if (eof == NULL) error->one(FLERR,"Unexpected end of data file"); m += strlen(&buffer[m]); } m++; } MPI_Bcast(&m,1,MPI_INT,0,world); MPI_Bcast(buffer,m,MPI_CHAR,0,world); atom->data_angles(nchunk,buffer); nread += nchunk; } // check that ang int nlocal = atom->nlocal; bigint sum; bigint n = 0; for (i = 0; i < nlocal; i++) n += atom->num_angle[i]; MPI_Allreduce(&n,&sum,1,MPI_LMP_BIGINT,MPI_SUM,world); int factor = 1; if (!force->newton_bond) factor = 3; if (me == 0) { if (screen) fprintf(screen," " BIGINT_FORMAT " angles\n",sum/factor); if (logfile) fprintf(logfile," " BIGINT_FORMAT " angles\n",sum/factor); } if (sum != factor*atom->nangles) error->all(FLERR,"Angles assigned incorrectly"); } /* ---------------------------------------------------------------------- */ void ReadData::dihedrals() { int i,m,nchunk; bigint nread = 0; bigint ndihedrals = atom->ndihedrals; while (nread < ndihedrals) { nchunk = MIN(ndihedrals-nread,CHUNK); if (me == 0) { char *eof; m = 0; for (i = 0; i < nchunk; i++) { eof = fgets(&buffer[m],MAXLINE,fp); if (eof == NULL) error->one(FLERR,"Unexpected end of data file"); m += strlen(&buffer[m]); } m++; } MPI_Bcast(&m,1,MPI_INT,0,world); MPI_Bcast(buffer,m,MPI_CHAR,0,world); atom->data_dihedrals(nchunk,buffer); nread += nchunk; } // check that dihedrals were assigned correctly int nlocal = atom->nlocal; bigint sum; bigint n = 0; for (i = 0; i < nlocal; i++) n += atom->num_dihedral[i]; MPI_Allreduce(&n,&sum,1,MPI_LMP_BIGINT,MPI_SUM,world); int factor = 1; if (!force->newton_bond) factor = 4; if (me == 0) { if (screen) fprintf(screen," " BIGINT_FORMAT " dihedrals\n",sum/factor); if (logfile) fprintf(logfile," " BIGINT_FORMAT " dihedrals\n",sum/factor); } if (sum != factor*atom->ndihedrals) error->all(FLERR,"Dihedrals assigned incorrectly"); } /* ---------------------------------------------------------------------- */ void ReadData::impropers() { int i,m,nchunk; bigint nread = 0; bigint nimpropers = atom->nimpropers; while (nread < nimpropers) { nchunk = MIN(nimpropers-nread,CHUNK); if (me == 0) { char *eof; m = 0; for (i = 0; i < nchunk; i++) { eof = fgets(&buffer[m],MAXLINE,fp); if (eof == NULL) error->one(FLERR,"Unexpected end of data file"); m += strlen(&buffer[m]); } m++; } MPI_Bcast(&m,1,MPI_INT,0,world); MPI_Bcast(buffer,m,MPI_CHAR,0,world); atom->data_impropers(nchunk,buffer); nread += nchunk; } // check that impropers were assigned correctly int nlocal = atom->nlocal; bigint sum; bigint n = 0; for (i = 0; i < nlocal; i++) n += atom->num_improper[i]; MPI_Allreduce(&n,&sum,1,MPI_LMP_BIGINT,MPI_SUM,world); int factor = 1; if (!force->newton_bond) factor = 4; if (me == 0) { if (screen) fprintf(screen," " BIGINT_FORMAT " impropers\n",sum/factor); if (logfile) fprintf(logfile," " BIGINT_FORMAT " impropers\n",sum/factor); } if (sum != factor*atom->nimpropers) error->all(FLERR,"Impropers assigned incorrectly"); } /* ---------------------------------------------------------------------- */ void ReadData::mass() { int i,m; char *buf = new char[atom->ntypes*MAXLINE]; char *original = buf; if (me == 0) { char *eof; m = 0; for (i = 0; i < atom->ntypes; i++) { eof = fgets(&buf[m],MAXLINE,fp); if (eof == NULL) error->one(FLERR,"Unexpected end of data file"); m += strlen(&buf[m]); buf[m-1] = '\0'; } } MPI_Bcast(&m,1,MPI_INT,0,world); MPI_Bcast(buf,m,MPI_CHAR,0,world); for (i = 0; i < atom->ntypes; i++) { atom->set_mass(buf); buf += strlen(buf) + 1; } delete [] original; } /* ---------------------------------------------------------------------- */ void ReadData::paircoeffs() { int i,m; char *buf = new char[atom->ntypes*MAXLINE]; char *original = buf; if (me == 0) { char *eof; m = 0; for (i = 0; i < atom->ntypes; i++) { eof = fgets(&buf[m],MAXLINE,fp); if (eof == NULL) error->one(FLERR,"Unexpected end of data file"); m += strlen(&buf[m]); buf[m-1] = '\0'; } } MPI_Bcast(&m,1,MPI_INT,0,world); MPI_Bcast(buf,m,MPI_CHAR,0,world); for (i = 0; i < atom->ntypes; i++) { m = strlen(buf) + 1; parse_coeffs(buf,NULL,1); force->pair->coeff(narg,arg); buf += m; } delete [] original; } /* ---------------------------------------------------------------------- */ void ReadData::bondcoeffs() { int i,m; char *buf = new char[atom->nbondtypes*MAXLINE]; char *original = buf; if (me == 0) { char *eof; m = 0; for (i = 0; i < atom->nbondtypes; i++) { eof = fgets(&buf[m],MAXLINE,fp); if (eof == NULL) error->one(FLERR,"Unexpected end of data file"); m += strlen(&buf[m]); buf[m-1] = '\0'; } } MPI_Bcast(&m,1,MPI_INT,0,world); MPI_Bcast(buf,m,MPI_CHAR,0,world); for (i = 0; i < atom->nbondtypes; i++) { m = strlen(buf) + 1; parse_coeffs(buf,NULL,0); force->bond->coeff(narg,arg); buf += m; } delete [] original; } /* ---------------------------------------------------------------------- */ void ReadData::anglecoeffs(int which) { int i,m; char *buf = new char[atom->nangletypes*MAXLINE]; char *original = buf; if (me == 0) { char *eof; m = 0; for (i = 0; i < atom->nangletypes; i++) { eof = fgets(&buf[m],MAXLINE,fp); if (eof == NULL) error->one(FLERR,"Unexpected end of data file"); m += strlen(&buf[m]); buf[m-1] = '\0'; } } MPI_Bcast(&m,1,MPI_INT,0,world); MPI_Bcast(buf,m,MPI_CHAR,0,world); for (i = 0; i < atom->nangletypes; i++) { m = strlen(buf) + 1; if (which == 0) parse_coeffs(buf,NULL,0); else if (which == 1) parse_coeffs(buf,"bb",0); else if (which == 2) parse_coeffs(buf,"ba",0); force->angle->coeff(narg,arg); buf += m; } delete [] original; } /* ---------------------------------------------------------------------- */ void ReadData::dihedralcoeffs(int which) { int i,m; char *buf = new char[atom->ndihedraltypes*MAXLINE]; char *original = buf; if (me == 0) { char *eof; m = 0; for (i = 0; i < atom->ndihedraltypes; i++) { eof = fgets(&buf[m],MAXLINE,fp); if (eof == NULL) error->one(FLERR,"Unexpected end of data file"); m += strlen(&buf[m]); buf[m-1] = '\0'; } } MPI_Bcast(&m,1,MPI_INT,0,world); MPI_Bcast(buf,m,MPI_CHAR,0,world); for (i = 0; i < atom->ndihedraltypes; i++) { m = strlen(buf) + 1; if (which == 0) parse_coeffs(buf,NULL,0); else if (which == 1) parse_coeffs(buf,"mbt",0); else if (which == 2) parse_coeffs(buf,"ebt",0); else if (which == 3) parse_coeffs(buf,"at",0); else if (which == 4) parse_coeffs(buf,"aat",0); else if (which == 5) parse_coeffs(buf,"bb13",0); force->dihedral->coeff(narg,arg); buf += m; } delete [] original; } /* ---------------------------------------------------------------------- */ void ReadData::impropercoeffs(int which) { int i,m; char *buf = new char[atom->nimpropertypes*MAXLINE]; char *original = buf; if (me == 0) { char *eof; m = 0; for (i = 0; i < atom->nimpropertypes; i++) { eof = fgets(&buf[m],MAXLINE,fp); if (eof == NULL) error->one(FLERR,"Unexpected end of data file"); m += strlen(&buf[m]); buf[m-1] = '\0'; } } MPI_Bcast(&m,1,MPI_INT,0,world); MPI_Bcast(buf,m,MPI_CHAR,0,world); for (i = 0; i < atom->nimpropertypes; i++) { m = strlen(buf) + 1; if (which == 0) parse_coeffs(buf,NULL,0); else if (which == 1) parse_coeffs(buf,"aa",0); force->improper->coeff(narg,arg); buf += m; } delete [] original; } /* ---------------------------------------------------------------------- proc 0 scans the data file for topology maximums ------------------------------------------------------------------------- */ void ReadData::scan(int &bond_per_atom, int &angle_per_atom, int &dihedral_per_atom, int &improper_per_atom) { int i,tmp1,tmp2,atom1,atom2,atom3,atom4; char *eof; if (atom->natoms > MAXSMALLINT) error->all(FLERR,"Molecular data file has too many atoms"); // customize for new sections int natoms = static_cast (atom->natoms); bond_per_atom = angle_per_atom = dihedral_per_atom = improper_per_atom = 0; int ellipsoid_flag = 0; int line_flag = 0; int tri_flag = 0; // customize for new sections // allocate topology counting vector // initially, array length = 1 to natoms // will grow via reallocate() if atom IDs > natoms int cmax = natoms + 1; int *count; memory->create(count,cmax,"read_data:count"); while (strlen(keyword)) { if (strcmp(keyword,"Masses") == 0) skip_lines(atom->ntypes); else if (strcmp(keyword,"Atoms") == 0) skip_lines(natoms); else if (strcmp(keyword,"Velocities") == 0) skip_lines(natoms); else if (strcmp(keyword,"Ellipsoids") == 0) { if (!avec_ellipsoid) error->all(FLERR,"Invalid data file section: Ellipsoids"); ellipsoid_flag = 1; skip_lines(nellipsoids); } else if (strcmp(keyword,"Lines") == 0) { if (!avec_line) error->all(FLERR,"Invalid data file section: Lines"); line_flag = 1; skip_lines(nlines); } else if (strcmp(keyword,"Triangles") == 0) { if (!avec_tri) error->all(FLERR,"Invalid data file section: Triangles"); tri_flag = 1; skip_lines(ntris); } else if (strcmp(keyword,"Pair Coeffs") == 0) { if (force->pair == NULL) error->all(FLERR,"Must define pair_style before Pair Coeffs"); skip_lines(atom->ntypes); } else if (strcmp(keyword,"Bond Coeffs") == 0) { if (atom->avec->bonds_allow == 0) error->all(FLERR,"Invalid data file section: Bond Coeffs"); if (force->bond == NULL) error->all(FLERR,"Must define bond_style before Bond Coeffs"); skip_lines(atom->nbondtypes); } else if (strcmp(keyword,"Angle Coeffs") == 0) { if (atom->avec->angles_allow == 0) error->all(FLERR,"Invalid data file section: Angle Coeffs"); if (force->angle == NULL) error->all(FLERR,"Must define angle_style before Angle Coeffs"); skip_lines(atom->nangletypes); } else if (strcmp(keyword,"Dihedral Coeffs") == 0) { skip_lines(atom->ndihedraltypes); if (atom->avec->dihedrals_allow == 0) error->all(FLERR,"Invalid data file section: Dihedral Coeffs"); if (force->dihedral == NULL) error->all(FLERR,"Must define dihedral_style before Dihedral Coeffs"); } else if (strcmp(keyword,"Improper Coeffs") == 0) { if (atom->avec->impropers_allow == 0) error->all(FLERR,"Invalid data file section: Improper Coeffs"); if (force->improper == NULL) error->all(FLERR,"Must define improper_style before Improper Coeffs"); skip_lines(atom->nimpropertypes); } else if (strcmp(keyword,"BondBond Coeffs") == 0) { if (atom->avec->angles_allow == 0) error->all(FLERR,"Invalid data file section: BondBond Coeffs"); if (force->angle == NULL) error->all(FLERR,"Must define angle_style before BondBond Coeffs"); skip_lines(atom->nangletypes); } else if (strcmp(keyword,"BondAngle Coeffs") == 0) { if (atom->avec->angles_allow == 0) error->all(FLERR,"Invalid data file section: BondAngle Coeffs"); if (force->angle == NULL) error->all(FLERR,"Must define angle_style before BondAngle Coeffs"); skip_lines(atom->nangletypes); } else if (strcmp(keyword,"MiddleBondTorsion Coeffs") == 0) { if (atom->avec->dihedrals_allow == 0) error->all(FLERR,"Invalid data file section: MiddleBondTorsion Coeffs"); if (force->dihedral == NULL) error->all(FLERR, "Must define dihedral_style before " "MiddleBondTorsion Coeffs"); skip_lines(atom->ndihedraltypes); } else if (strcmp(keyword,"EndBondTorsion Coeffs") == 0) { if (atom->avec->dihedrals_allow == 0) error->all(FLERR,"Invalid data file section: EndBondTorsion Coeffs"); if (force->dihedral == NULL) error->all(FLERR, "Must define dihedral_style before EndBondTorsion Coeffs"); skip_lines(atom->ndihedraltypes); } else if (strcmp(keyword,"AngleTorsion Coeffs") == 0) { if (atom->avec->dihedrals_allow == 0) error->all(FLERR,"Invalid data file section: AngleTorsion Coeffs"); if (force->dihedral == NULL) error->all(FLERR, "Must define dihedral_style before AngleTorsion Coeffs"); skip_lines(atom->ndihedraltypes); } else if (strcmp(keyword,"AngleAngleTorsion Coeffs") == 0) { if (atom->avec->dihedrals_allow == 0) error->all(FLERR,"Invalid data file section: AngleAngleTorsion Coeffs"); if (force->dihedral == NULL) error->all(FLERR, "Must define dihedral_style before " "AngleAngleTorsion Coeffs"); skip_lines(atom->ndihedraltypes); } else if (strcmp(keyword,"BondBond13 Coeffs") == 0) { if (atom->avec->dihedrals_allow == 0) error->all(FLERR,"Invalid data file section: BondBond13 Coeffs"); if (force->dihedral == NULL) error->all(FLERR,"Must define dihedral_style before BondBond13 Coeffs"); skip_lines(atom->ndihedraltypes); } else if (strcmp(keyword,"AngleAngle Coeffs") == 0) { if (atom->avec->impropers_allow == 0) error->all(FLERR,"Invalid data file section: AngleAngle Coeffs"); if (force->improper == NULL) error->all(FLERR,"Must define improper_style before AngleAngle Coeffs"); skip_lines(atom->nimpropertypes); } else if (strcmp(keyword,"Bonds") == 0) { for (i = 1; i < cmax; i++) count[i] = 0; if (force->newton_bond) for (i = 0; i < atom->nbonds; i++) { eof = fgets(line,MAXLINE,fp); if (eof == NULL) error->one(FLERR,"Unexpected end of data file"); sscanf(line,"%d %d %d %d",&tmp1,&tmp2,&atom1,&atom2); if (atom1 >= cmax) cmax = reallocate(&count,cmax,atom1); count[atom1]++; } else for (i = 0; i < atom->nbonds; i++) { eof = fgets(line,MAXLINE,fp); if (eof == NULL) error->one(FLERR,"Unexpected end of data file"); sscanf(line,"%d %d %d %d",&tmp1,&tmp2,&atom1,&atom2); int amax = MAX(atom1,atom2); if (amax >= cmax) cmax = reallocate(&count,cmax,amax); count[atom1]++; count[atom2]++; } for (i = 1; i < cmax; i++) bond_per_atom = MAX(bond_per_atom,count[i]); if (screen) fprintf(screen," %d = max bonds/atom\n",bond_per_atom); if (logfile) fprintf(logfile," %d = max bonds/atom\n",bond_per_atom); } else if (strcmp(keyword,"Angles") == 0) { for (i = 1; i < cmax; i++) count[i] = 0; if (force->newton_bond) for (i = 0; i < atom->nangles; i++) { eof = fgets(line,MAXLINE,fp); if (eof == NULL) error->one(FLERR,"Unexpected end of data file"); sscanf(line,"%d %d %d %d %d",&tmp1,&tmp2,&atom1,&atom2,&atom3); if (atom2 >= cmax) cmax = reallocate(&count,cmax,atom2); count[atom2]++; } else for (i = 0; i < atom->nangles; i++) { eof = fgets(line,MAXLINE,fp); if (eof == NULL) error->one(FLERR,"Unexpected end of data file"); sscanf(line,"%d %d %d %d %d",&tmp1,&tmp2,&atom1,&atom2,&atom3); int amax = MAX(atom1,atom2); amax = MAX(amax,atom3); if (amax >= cmax) cmax = reallocate(&count,cmax,amax); count[atom1]++; count[atom2]++; count[atom3]++; } for (i = 1; i < cmax; i++) angle_per_atom = MAX(angle_per_atom,count[i]); if (screen) fprintf(screen," %d = max angles/atom\n",angle_per_atom); if (logfile) fprintf(logfile," %d = max angles/atom\n",angle_per_atom); } else if (strcmp(keyword,"Dihedrals") == 0) { for (i = 1; i < cmax; i++) count[i] = 0; if (force->newton_bond) for (i = 0; i < atom->ndihedrals; i++) { eof = fgets(line,MAXLINE,fp); if (eof == NULL) error->one(FLERR,"Unexpected end of data file"); sscanf(line,"%d %d %d %d %d %d", &tmp1,&tmp2,&atom1,&atom2,&atom3,&atom4); if (atom2 >= cmax) cmax = reallocate(&count,cmax,atom2); count[atom2]++; } else for (i = 0; i < atom->ndihedrals; i++) { eof = fgets(line,MAXLINE,fp); if (eof == NULL) error->one(FLERR,"Unexpected end of data file"); sscanf(line,"%d %d %d %d %d %d", &tmp1,&tmp2,&atom1,&atom2,&atom3,&atom4); int amax = MAX(atom1,atom2); amax = MAX(amax,atom3); amax = MAX(amax,atom4); if (amax >= cmax) cmax = reallocate(&count,cmax,amax); count[atom1]++; count[atom2]++; count[atom3]++; count[atom4]++; } for (i = 1; i < cmax; i++) dihedral_per_atom = MAX(dihedral_per_atom,count[i]); if (screen) fprintf(screen," %d = max dihedrals/atom\n",dihedral_per_atom); if (logfile) fprintf(logfile," %d = max dihedrals/atom\n",dihedral_per_atom); } else if (strcmp(keyword,"Impropers") == 0) { for (i = 1; i < cmax; i++) count[i] = 0; if (force->newton_bond) for (i = 0; i < atom->nimpropers; i++) { eof = fgets(line,MAXLINE,fp); if (eof == NULL) error->one(FLERR,"Unexpected end of data file"); sscanf(line,"%d %d %d %d %d %d", &tmp1,&tmp2,&atom1,&atom2,&atom3,&atom4); if (atom2 >= cmax) cmax = reallocate(&count,cmax,atom2); count[atom2]++; } else for (i = 0; i < atom->nimpropers; i++) { eof = fgets(line,MAXLINE,fp); if (eof == NULL) error->one(FLERR,"Unexpected end of data file"); sscanf(line,"%d %d %d %d %d %d", &tmp1,&tmp2,&atom1,&atom2,&atom3,&atom4); int amax = MAX(atom1,atom2); amax = MAX(amax,atom3); amax = MAX(amax,atom4); if (amax >= cmax) cmax = reallocate(&count,cmax,amax); count[atom1]++; count[atom2]++; count[atom3]++; count[atom4]++; } for (i = 1; i < cmax; i++) improper_per_atom = MAX(improper_per_atom,count[i]); if (screen) fprintf(screen," %d = max impropers/atom\n",improper_per_atom); if (logfile) fprintf(logfile," %d = max impropers/atom\n",improper_per_atom); } else { char str[128]; sprintf(str,"Unknown identifier in data file: %s",keyword); error->one(FLERR,str); } parse_keyword(0,0); } // free topology counting vector memory->destroy(count); // error check that topology was specified in file if ((atom->nbonds && !bond_per_atom) || (atom->nangles && !angle_per_atom) || (atom->ndihedrals && !dihedral_per_atom) || (atom->nimpropers && !improper_per_atom)) error->one(FLERR,"Needed topology not in data file"); // customize for new sections // error check that Bonus sections were speficied in file if (nellipsoids && !ellipsoid_flag) error->one(FLERR,"Needed bonus data not in data file"); if (nlines && !line_flag) error->one(FLERR,"Needed bonus data not in data file"); if (ntris && !tri_flag) error->one(FLERR,"Needed bonus data not in data file"); } /* ---------------------------------------------------------------------- reallocate the count vector from cmax to amax+1 and return new length zero new locations ------------------------------------------------------------------------- */ int ReadData::reallocate(int **pcount, int cmax, int amax) { int *count = *pcount; memory->grow(count,amax+1,"read_data:count"); for (int i = cmax; i <= amax; i++) count[i] = 0; *pcount = count; return amax+1; } /* ---------------------------------------------------------------------- proc 0 opens data file test if gzipped ------------------------------------------------------------------------- */ void ReadData::open(char *file) { compressed = 0; char *suffix = file + strlen(file) - 3; if (suffix > file && strcmp(suffix,".gz") == 0) compressed = 1; if (!compressed) fp = fopen(file,"r"); else { #ifdef LAMMPS_GZIP char gunzip[128]; sprintf(gunzip,"gunzip -c %s",file); fp = popen(gunzip,"r"); #else error->one(FLERR,"Cannot open gzipped file"); #endif } if (fp == NULL) { char str[128]; sprintf(str,"Cannot open file %s",file); error->one(FLERR,str); } } /* ---------------------------------------------------------------------- grab next keyword read lines until one is non-blank keyword is all text on line w/out leading & trailing white space read one additional line (assumed blank) if any read hits EOF, set keyword to empty if first = 1, line variable holds non-blank line that ended header if flag = 0, only proc 0 is calling so no bcast else flag = 1, bcast keyword line to all procs ------------------------------------------------------------------------- */ void ReadData::parse_keyword(int first, int flag) { int eof = 0; // proc 0 reads upto non-blank line plus 1 following line // eof is set to 1 if any read hits end-of-file if (me == 0) { if (!first) { if (fgets(line,MAXLINE,fp) == NULL) eof = 1; } while (eof == 0 && strspn(line," \t\n\r") == strlen(line)) { if (fgets(line,MAXLINE,fp) == NULL) eof = 1; } if (fgets(buffer,MAXLINE,fp) == NULL) eof = 1; } // if eof, set keyword empty and return if (flag) MPI_Bcast(&eof,1,MPI_INT,0,world); if (eof) { keyword[0] = '\0'; return; } // bcast keyword line to all procs if (flag) { int n; if (me == 0) n = strlen(line) + 1; MPI_Bcast(&n,1,MPI_INT,0,world); MPI_Bcast(line,n,MPI_CHAR,0,world); } // copy non-whitespace portion of line into keyword int start = strspn(line," \t\n\r"); int stop = strlen(line) - 1; while (line[stop] == ' ' || line[stop] == '\t' || line[stop] == '\n' || line[stop] == '\r') stop--; line[stop+1] = '\0'; strcpy(keyword,&line[start]); } /* ---------------------------------------------------------------------- proc 0 reads N lines from file ------------------------------------------------------------------------- */ void ReadData::skip_lines(int n) { char *eof; for (int i = 0; i < n; i++) eof = fgets(line,MAXLINE,fp); if (eof == NULL) error->one(FLERR,"Unexpected end of data file"); } /* ---------------------------------------------------------------------- parse a line of coeffs into words, storing them in narg,arg trim anything from '#' onward word strings remain in line, are not copied if addstr != NULL, add addstr as extra arg for class2 angle/dihedral/improper if 2nd word starts with letter, then is hybrid style, add addstr after it else add addstr before 2nd word if dupflag, duplicate 1st word, so pair_coeff "2" becomes "2 2" ------------------------------------------------------------------------- */ -void ReadData::parse_coeffs(char *line, char *addstr, int dupflag) +void ReadData::parse_coeffs(char *line, const char *addstr, int dupflag) { char *ptr; if (ptr = strchr(line,'#')) *ptr = '\0'; narg = 0; char *word = strtok(line," \t\n\r\f"); while (word) { if (narg == maxarg) { maxarg += DELTA; arg = (char **) memory->srealloc(arg,maxarg*sizeof(char *),"read_data:arg"); } - if (addstr && narg == 1 && !islower(word[0])) arg[narg++] = addstr; + if (addstr && narg == 1 && !islower(word[0])) arg[narg++] = (char *) addstr; arg[narg++] = word; - if (addstr && narg == 2 && islower(word[0])) arg[narg++] = addstr; + if (addstr && narg == 2 && islower(word[0])) arg[narg++] = (char *) addstr; if (dupflag && narg == 1) arg[narg++] = word; word = strtok(NULL," \t\n\r\f"); } } diff --git a/src/read_data.h b/src/read_data.h index 6426054a4..9ef79f706 100644 --- a/src/read_data.h +++ b/src/read_data.h @@ -1,390 +1,390 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ #ifdef COMMAND_CLASS CommandStyle(read_data,ReadData) #else #ifndef LMP_READ_DATA_H #define LMP_READ_DATA_H #include "stdio.h" #include "pointers.h" namespace LAMMPS_NS { class ReadData : protected Pointers { public: ReadData(class LAMMPS *); ~ReadData(); void command(int, char **); private: int me; char *line,*keyword,*buffer; FILE *fp; int narg,maxarg,compressed; char **arg; bigint nellipsoids; class AtomVecEllipsoid *avec_ellipsoid; bigint nlines; class AtomVecLine *avec_line; bigint ntris; class AtomVecTri *avec_tri; void open(char *); void scan(int &, int &, int &, int &); int reallocate(int **, int, int); void header(int); void parse_keyword(int, int); void skip_lines(int); - void parse_coeffs(char *, char *, int); + void parse_coeffs(char *, const char *, int); void atoms(); void velocities(); - void bonus(bigint, class AtomVec *, char *); + void bonus(bigint, class AtomVec *, const char *); void bonds(); void angles(); void dihedrals(); void impropers(); void mass(); void paircoeffs(); void bondcoeffs(); void anglecoeffs(int); void dihedralcoeffs(int); void impropercoeffs(int); }; } #endif #endif /* ERROR/WARNING messages: E: Illegal ... command Self-explanatory. Check the input script syntax and compare to the documentation for the command. You can use -echo screen as a command-line option when running LAMMPS to see the offending line. E: Cannot read_data after simulation box is defined The read_data command cannot be used after a read_data, read_restart, or create_box command. E: Cannot run 2d simulation with nonperiodic Z dimension Use the boundary command to make the z dimension periodic in order to run a 2d simulation. E: Must read Atoms before Velocities The Atoms section of a data file must come before a Velocities section. E: Invalid data file section: Ellipsoids UNDOCUMENTED E: Must read Atoms before Ellipsoids UNDOCUMENTED E: Invalid data file section: Lines UNDOCUMENTED E: Must read Atoms before Lines UNDOCUMENTED E: Invalid data file section: Triangles UNDOCUMENTED E: Must read Atoms before Triangles UNDOCUMENTED E: Invalid data file section: Bonds Atom style does not allow bonds. E: Must read Atoms before Bonds The Atoms section of a data file must come before a Bonds section. E: Invalid data file section: Angles Atom style does not allow angles. E: Must read Atoms before Angles The Atoms section of a data file must come before an Angles section. E: Invalid data file section: Dihedrals Atom style does not allow dihedrals. E: Must read Atoms before Dihedrals The Atoms section of a data file must come before a Dihedrals section. E: Invalid data file section: Impropers Atom style does not allow impropers. E: Must read Atoms before Impropers The Atoms section of a data file must come before an Impropers section. E: Must define pair_style before Pair Coeffs Must use a pair_style command before reading a data file that defines Pair Coeffs. E: Invalid data file section: Bond Coeffs Atom style does not allow bonds. E: Must define bond_style before Bond Coeffs Must use a bond_style command before reading a data file that defines Bond Coeffs. E: Invalid data file section: Angle Coeffs Atom style does not allow angles. E: Must define angle_style before Angle Coeffs Must use an angle_style command before reading a data file that defines Angle Coeffs. E: Invalid data file section: Dihedral Coeffs Atom style does not allow dihedrals. E: Must define dihedral_style before Dihedral Coeffs Must use a dihedral_style command before reading a data file that defines Dihedral Coeffs. E: Invalid data file section: Improper Coeffs Atom style does not allow impropers. E: Must define improper_style before Improper Coeffs Must use an improper_style command before reading a data file that defines Improper Coeffs. E: Invalid data file section: BondBond Coeffs Atom style does not allow angles. E: Must define angle_style before BondBond Coeffs Must use an angle_style command before reading a data file that defines Angle Coeffs. E: Invalid data file section: BondAngle Coeffs Atom style does not allow angles. E: Must define angle_style before BondAngle Coeffs Must use an angle_style command before reading a data file that defines Angle Coeffs. E: Invalid data file section: MiddleBondTorsion Coeffs Atom style does not allow dihedrals. E: Must define dihedral_style before MiddleBondTorsion Coeffs Must use a dihedral_style command before reading a data file that defines MiddleBondTorsion Coeffs. E: Invalid data file section: EndBondTorsion Coeffs Atom style does not allow dihedrals. E: Must define dihedral_style before EndBondTorsion Coeffs Must use a dihedral_style command before reading a data file that defines EndBondTorsion Coeffs. E: Invalid data file section: AngleTorsion Coeffs Atom style does not allow dihedrals. E: Must define dihedral_style before AngleTorsion Coeffs Must use a dihedral_style command before reading a data file that defines AngleTorsion Coeffs. E: Invalid data file section: AngleAngleTorsion Coeffs Atom style does not allow dihedrals. E: Must define dihedral_style before AngleAngleTorsion Coeffs Must use a dihedral_style command before reading a data file that defines AngleAngleTorsion Coeffs. E: Invalid data file section: BondBond13 Coeffs Atom style does not allow dihedrals. E: Must define dihedral_style before BondBond13 Coeffs Must use a dihedral_style command before reading a data file that defines BondBond13 Coeffs. E: Invalid data file section: AngleAngle Coeffs Atom style does not allow impropers. E: Must define improper_style before AngleAngle Coeffs Must use an improper_style command before reading a data file that defines AngleAngle Coeffs. E: Unknown identifier in data file: %s A section of the data file cannot be read by LAMMPS. E: No atoms in data file The header of the data file indicated that atoms would be included, but they were not present. E: Unexpected end of data file LAMMPS hit the end of the data file while attempting to read a section. Something is wrong with the format of the data file. E: No ellipsoids allowed with this atom style UNDOCUMENTED E: No lines allowed with this atom style UNDOCUMENTED E: No triangles allowed with this atom style UNDOCUMENTED E: System in data file is too big See the setting for bigint in the src/lmptype.h file. E: No bonds allowed with this atom style Self-explanatory. Check data file. E: No angles allowed with this atom style Self-explanatory. Check data file. E: No dihedrals allowed with this atom style Self-explanatory. Check data file. E: No impropers allowed with this atom style Self-explanatory. Check data file. E: Bonds defined but no bond types The data file header lists bonds but no bond types. E: Angles defined but no angle types The data file header lists angles but no angle types. E: Dihedrals defined but no dihedral types The data file header lists dihedrals but no dihedral types. E: Impropers defined but no improper types The data file header lists improper but no improper types. E: Did not assign all atoms correctly Atoms read in from a data file were not assigned correctly to processors. This is likely due to some atom coordinates being outside a non-periodic simulation box. E: Invalid atom ID in Atoms section of data file Atom IDs must be positive integers. E: Bonds assigned incorrectly Bonds read in from the data file were not assigned correctly to atoms. This means there is something invalid about the topology definitions. E: Angles assigned incorrectly Angles read in from the data file were not assigned correctly to atoms. This means there is something invalid about the topology definitions. E: Dihedrals assigned incorrectly Dihedrals read in from the data file were not assigned correctly to atoms. This means there is something invalid about the topology definitions. E: Impropers assigned incorrectly Impropers read in from the data file were not assigned correctly to atoms. This means there is something invalid about the topology definitions. E: Molecular data file has too many atoms These kids of data files are currently limited to a number of atoms that fits in a 32-bit integer. E: Needed topology not in data file The header of the data file indicated that bonds or angles or dihedrals or impropers would be included, but they were not present. E: Needed bonus data not in data file UNDOCUMENTED E: Cannot open gzipped file LAMMPS is attempting to open a gzipped version of the specified file but was unsuccessful. Check that the path and name are correct. E: Cannot open file %s The specified file cannot be opened. Check that the path and name are correct. */ diff --git a/src/thermo.cpp b/src/thermo.cpp index 57cfd4d45..7dadacd8a 100644 --- a/src/thermo.cpp +++ b/src/thermo.cpp @@ -1,1932 +1,1932 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ #include "lmptype.h" #include "mpi.h" #include "math.h" #include "stdlib.h" #include "string.h" #include "thermo.h" #include "atom.h" #include "update.h" #include "comm.h" #include "domain.h" #include "lattice.h" #include "modify.h" #include "fix.h" #include "compute.h" #include "input.h" #include "variable.h" #include "force.h" #include "pair.h" #include "bond.h" #include "angle.h" #include "dihedral.h" #include "improper.h" #include "kspace.h" #include "output.h" #include "timer.h" #include "math_const.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace MathConst; // customize a new keyword by adding to this list: // step, elapsed, elaplong, dt, cpu, tpcpu, spcpu // atoms, temp, press, pe, ke, etotal, enthalpy // evdwl, ecoul, epair, ebond, eangle, edihed, eimp, emol, elong, etail // vol, lx, ly, lz, xlo, xhi, ylo, yhi, zlo, zhi, xy, xz, yz, xlat, ylat, zlat // pxx, pyy, pzz, pxy, pxz, pyz // fmax, fnorm // cella, cellb, cellc, cellalpha, cellbeta, cellgamma // customize a new thermo style by adding a DEFINE to this list #define ONE "step temp epair emol etotal press" #define MULTI "etotal ke temp pe ebond eangle edihed eimp evdwl ecoul elong press" enum{IGNORE,WARN,ERROR}; // same as write_restart.cpp enum{ONELINE,MULTILINE}; enum{INT,FLOAT,BIGINT}; enum{SCALAR,VECTOR,ARRAY}; #define INVOKED_SCALAR 1 #define INVOKED_VECTOR 2 #define INVOKED_ARRAY 4 #define MAXLINE 8192 // make this 4x longer than Input::MAXLINE #define DELTA 8 /* ---------------------------------------------------------------------- */ Thermo::Thermo(LAMMPS *lmp, int narg, char **arg) : Pointers(lmp) { MPI_Comm_rank(world,&me); int n = strlen(arg[0]) + 1; style = new char[n]; strcpy(style,arg[0]); // set thermo_modify defaults modified = 0; normuserflag = 0; lineflag = ONELINE; lostflag = ERROR; lostbefore = 0; flushflag = 0; // set style and corresponding lineflag // custom style builds its own line of keywords // customize a new thermo style by adding to if statement line = new char[MAXLINE]; if (strcmp(style,"one") == 0) { strcpy(line,ONE); } else if (strcmp(style,"multi") == 0) { strcpy(line,MULTI); lineflag = MULTILINE; } else if (strcmp(style,"custom") == 0) { if (narg == 1) error->all(FLERR,"Illegal thermo style custom command"); line[0] = '\0'; for (int iarg = 1; iarg < narg; iarg++) { strcat(line,arg[iarg]); strcat(line," "); } line[strlen(line)-1] = '\0'; } else error->all(FLERR,"Illegal thermo style command"); // ptrs, flags, IDs for compute objects thermo may use or create temperature = NULL; pressure = NULL; pe = NULL; index_temp = index_press_scalar = index_press_vector = index_pe = -1; id_temp = (char *) "thermo_temp"; id_press = (char *) "thermo_press"; id_pe = (char *) "thermo_pe"; // count fields in line // allocate per-field memory // process line of keywords nfield_initial = atom->count_words(line); allocate(); parse_fields(line); // format strings - char *bigint_format = BIGINT_FORMAT; + char *bigint_format = (char *) BIGINT_FORMAT; char *fformat_multi = (char *) "---------------- Step %%8%s ----- " "CPU = %%11.4f (sec) ----------------"; sprintf(format_multi,fformat_multi,&bigint_format[1]); format_float_one_def = (char *) "%12.8g"; format_float_multi_def = (char *) "%14.4f"; format_int_one_def = (char *) "%8d"; format_int_multi_def = (char *) "%14d"; sprintf(format_bigint_one_def,"%%8%s",&bigint_format[1]); sprintf(format_bigint_multi_def,"%%14%s",&bigint_format[1]); format_float_user = NULL; format_int_user = NULL; format_bigint_user = NULL; } /* ---------------------------------------------------------------------- */ Thermo::~Thermo() { delete [] style; delete [] line; deallocate(); // format strings delete [] format_float_user; delete [] format_int_user; delete [] format_bigint_user; } /* ---------------------------------------------------------------------- */ void Thermo::init() { int i,n; // set normvalue to default setting unless user has specified it if (normuserflag) normvalue = normuser; else if (strcmp(update->unit_style,"lj") == 0) normvalue = 1; else normvalue = 0; // add Volume field if volume changes and not style = custom // this check must come after domain init, so box_change is set nfield = nfield_initial; if (domain->box_change && strcmp(style,"custom") != 0) addfield("Volume",&Thermo::compute_vol,FLOAT); // set format string for each field // include keyword if lineflag = MULTILINE // add '/n' every 3 values if lineflag = MULTILINE // add trailing '/n' to last value char *ptr; for (i = 0; i < nfield; i++) { format[i][0] = '\0'; if (lineflag == MULTILINE && i % 3 == 0) strcat(format[i],"\n"); if (format_user[i]) ptr = format_user[i]; else if (vtype[i] == FLOAT) { if (format_float_user) ptr = format_float_user; else if (lineflag == ONELINE) ptr = format_float_one_def; else if (lineflag == MULTILINE) ptr = format_float_multi_def; } else if (vtype[i] == INT) { if (format_int_user) ptr = format_int_user; else if (lineflag == ONELINE) ptr = format_int_one_def; else if (lineflag == MULTILINE) ptr = format_int_multi_def; } else if (vtype[i] == BIGINT) { if (format_bigint_user) ptr = format_bigint_user; else if (lineflag == ONELINE) ptr = format_bigint_one_def; else if (lineflag == MULTILINE) ptr = format_bigint_multi_def; } n = strlen(format[i]); if (lineflag == ONELINE) sprintf(&format[i][n],"%s ",ptr); else sprintf(&format[i][n],"%-8s = %s ",keyword[i],ptr); if (i == nfield-1) strcat(format[i],"\n"); } // find current ptr for each Compute ID // cudable = 0 if any compute used by Thermo is non-CUDA cudable = 1; int icompute; for (i = 0; i < ncompute; i++) { icompute = modify->find_compute(id_compute[i]); if (icompute < 0) error->all(FLERR,"Could not find thermo compute ID"); computes[i] = modify->compute[icompute]; cudable = cudable && computes[i]->cudable; } // find current ptr for each Fix ID // check that fix frequency is acceptable with thermo output frequency int ifix; for (i = 0; i < nfix; i++) { ifix = modify->find_fix(id_fix[i]); if (ifix < 0) error->all(FLERR,"Could not find thermo fix ID"); fixes[i] = modify->fix[ifix]; if (output->thermo_every % fixes[i]->global_freq) error->all(FLERR,"Thermo and fix not computed at compatible times"); } // find current ptr for each Variable ID int ivariable; for (i = 0; i < nvariable; i++) { ivariable = input->variable->find(id_variable[i]); if (ivariable < 0) error->all(FLERR,"Could not find thermo custom variable name"); variables[i] = ivariable; } // set ptrs to keyword-specific Compute objects if (index_temp >= 0) temperature = computes[index_temp]; if (index_press_scalar >= 0) pressure = computes[index_press_scalar]; if (index_press_vector >= 0) pressure = computes[index_press_vector]; if (index_pe >= 0) pe = computes[index_pe]; } /* ---------------------------------------------------------------------- */ void Thermo::header() { if (lineflag == MULTILINE) return; int loc = 0; for (int i = 0; i < nfield; i++) loc += sprintf(&line[loc],"%s ",keyword[i]); sprintf(&line[loc],"\n"); if (me == 0) { if (screen) fprintf(screen,line); if (logfile) fprintf(logfile,line); } } /* ---------------------------------------------------------------------- */ void Thermo::compute(int flag) { int i; firststep = flag; bigint ntimestep = update->ntimestep; // check for lost atoms // turn off normflag if natoms = 0 to avoid divide by 0 natoms = lost_check(); if (natoms == 0) normflag = 0; else normflag = normvalue; // invoke Compute methods needed for thermo keywords // which = 0 is global scalar, which = 1 is global vector for (i = 0; i < ncompute; i++) if (compute_which[i] == SCALAR) { if (!(computes[i]->invoked_flag & INVOKED_SCALAR)) { computes[i]->compute_scalar(); computes[i]->invoked_flag |= INVOKED_SCALAR; } } else if (compute_which[i] == VECTOR) { if (!(computes[i]->invoked_flag & INVOKED_VECTOR)) { computes[i]->compute_vector(); computes[i]->invoked_flag |= INVOKED_VECTOR; } } else if (compute_which[i] == ARRAY) { if (!(computes[i]->invoked_flag & INVOKED_ARRAY)) { computes[i]->compute_array(); computes[i]->invoked_flag |= INVOKED_ARRAY; } } // if lineflag = MULTILINE, prepend step/cpu header line int loc = 0; if (lineflag == MULTILINE) { double cpu; if (flag) cpu = timer->elapsed(TIME_LOOP); else cpu = 0.0; loc = sprintf(&line[loc],format_multi,ntimestep,cpu); } // add each thermo value to line with its specific format for (ifield = 0; ifield < nfield; ifield++) { (this->*vfunc[ifield])(); if (vtype[ifield] == FLOAT) loc += sprintf(&line[loc],format[ifield],dvalue); else if (vtype[ifield] == INT) loc += sprintf(&line[loc],format[ifield],ivalue); else if (vtype[ifield] == BIGINT) { loc += sprintf(&line[loc],format[ifield],bivalue); } } // kludge for RedStorm timing issue // if (ntimestep == 100) return; // print line to screen and logfile if (me == 0) { if (screen) fprintf(screen,line); if (logfile) { fprintf(logfile,line); if (flushflag) fflush(logfile); } } } /* ---------------------------------------------------------------------- check for lost atoms, return current number of atoms ------------------------------------------------------------------------- */ bigint Thermo::lost_check() { // ntotal = current # of atoms bigint ntotal; bigint nblocal = atom->nlocal; MPI_Allreduce(&nblocal,&ntotal,1,MPI_LMP_BIGINT,MPI_SUM,world); if (ntotal < 0 || ntotal > MAXBIGINT) error->all(FLERR,"Too many total atoms"); if (ntotal == atom->natoms) return ntotal; // if not checking or already warned, just return // reset total atom count if (lostflag == IGNORE) return ntotal; if (lostflag == WARN && lostbefore == 1) { atom->natoms = ntotal; return ntotal; } // error message if (lostflag == ERROR) { char str[64]; sprintf(str, "Lost atoms: original " BIGINT_FORMAT " current " BIGINT_FORMAT, atom->natoms,ntotal); error->all(FLERR,str); } // warning message char str[64]; sprintf(str, "Lost atoms: original " BIGINT_FORMAT " current " BIGINT_FORMAT, atom->natoms,ntotal); if (me == 0) error->warning(FLERR,str,0); // reset total atom count atom->natoms = ntotal; lostbefore = 1; return ntotal; } /* ---------------------------------------------------------------------- modify thermo parameters ------------------------------------------------------------------------- */ void Thermo::modify_params(int narg, char **arg) { if (narg == 0) error->all(FLERR,"Illegal thermo_modify command"); modified = 1; int iarg = 0; while (iarg < narg) { if (strcmp(arg[iarg],"every") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal thermo_modify command"); if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) { delete [] output->var_thermo; int n = strlen(&arg[iarg+1][2]) + 1; output->var_thermo = new char[n]; strcpy(output->var_thermo,&arg[iarg+1][2]); } else error->all(FLERR,"Illegal thermo_modify command"); output->thermo_every = 0; iarg += 2; } else if (strcmp(arg[iarg],"temp") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal thermo_modify command"); if (index_temp < 0) error->all(FLERR,"Thermo style does not use temp"); delete [] id_compute[index_temp]; int n = strlen(arg[iarg+1]) + 1; id_compute[index_temp] = new char[n]; strcpy(id_compute[index_temp],arg[iarg+1]); int icompute = modify->find_compute(arg[iarg+1]); if (icompute < 0) error->all(FLERR,"Could not find thermo_modify temperature ID"); temperature = modify->compute[icompute]; if (temperature->tempflag == 0) error->all(FLERR,"Thermo_modify temperature ID does not " "compute temperature"); if (temperature->igroup != 0 && comm->me == 0) error->warning(FLERR,"Temperature for thermo pressure is not for group all"); // reset id_temp of pressure to new temperature ID // either pressure currently being used by thermo or "thermo_press" if (index_press_scalar >= 0) { icompute = modify->find_compute(id_compute[index_press_scalar]); if (icompute < 0) error->all(FLERR,"Pressure ID for thermo does not exist"); } else if (index_press_vector >= 0) { icompute = modify->find_compute(id_compute[index_press_vector]); if (icompute < 0) error->all(FLERR,"Pressure ID for thermo does not exist"); } else icompute = modify->find_compute((char *) "thermo_press"); modify->compute[icompute]->reset_extra_compute_fix(arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"press") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal thermo_modify command"); if (index_press_scalar < 0 && index_press_vector < 0) error->all(FLERR,"Thermo style does not use press"); if (index_press_scalar >= 0) { delete [] id_compute[index_press_scalar]; int n = strlen(arg[iarg+1]) + 1; id_compute[index_press_scalar] = new char[n]; strcpy(id_compute[index_press_scalar],arg[iarg+1]); } if (index_press_vector >= 0) { delete [] id_compute[index_press_vector]; int n = strlen(arg[iarg+1]) + 1; id_compute[index_press_vector] = new char[n]; strcpy(id_compute[index_press_vector],arg[iarg+1]); } int icompute = modify->find_compute(arg[iarg+1]); if (icompute < 0) error->all(FLERR,"Could not find thermo_modify pressure ID"); pressure = modify->compute[icompute]; if (pressure->pressflag == 0) error->all(FLERR,"Thermo_modify pressure ID does not compute pressure"); iarg += 2; } else if (strcmp(arg[iarg],"lost") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal thermo_modify command"); if (strcmp(arg[iarg+1],"ignore") == 0) lostflag = IGNORE; else if (strcmp(arg[iarg+1],"warn") == 0) lostflag = WARN; else if (strcmp(arg[iarg+1],"error") == 0) lostflag = ERROR; else error->all(FLERR,"Illegal thermo_modify command"); iarg += 2; } else if (strcmp(arg[iarg],"norm") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal thermo_modify command"); normuserflag = 1; if (strcmp(arg[iarg+1],"no") == 0) normuser = 0; else if (strcmp(arg[iarg+1],"yes") == 0) normuser = 1; else error->all(FLERR,"Illegal thermo_modify command"); iarg += 2; } else if (strcmp(arg[iarg],"flush") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal thermo_modify command"); if (strcmp(arg[iarg+1],"no") == 0) flushflag = 0; else if (strcmp(arg[iarg+1],"yes") == 0) flushflag = 1; else error->all(FLERR,"Illegal thermo_modify command"); iarg += 2; } else if (strcmp(arg[iarg],"line") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal thermo_modify command"); if (strcmp(arg[iarg+1],"one") == 0) lineflag = ONELINE; else if (strcmp(arg[iarg+1],"multi") == 0) lineflag = MULTILINE; else error->all(FLERR,"Illegal thermo_modify command"); iarg += 2; } else if (strcmp(arg[iarg],"format") == 0) { if (iarg+3 > narg) error->all(FLERR,"Illegal thermo_modify command"); if (strcmp(arg[iarg+1],"int") == 0) { if (format_int_user) delete [] format_int_user; int n = strlen(arg[iarg+2]) + 1; format_int_user = new char[n]; strcpy(format_int_user,arg[iarg+2]); if (format_bigint_user) delete [] format_bigint_user; n = strlen(format_int_user) + 3; format_bigint_user = new char[n]; char *ptr = strchr(format_int_user,'d'); if (ptr == NULL) error->all(FLERR,"Thermo_modify int format does not contain d character"); *ptr = '\0'; sprintf(format_bigint_user,"%s%s%s",format_int_user, BIGINT_FORMAT,ptr+1); *ptr = 'd'; } else if (strcmp(arg[iarg+1],"float") == 0) { if (format_float_user) delete [] format_float_user; int n = strlen(arg[iarg+2]) + 1; format_float_user = new char[n]; strcpy(format_float_user,arg[iarg+2]); } else { int i = atoi(arg[iarg+1]) - 1; if (i < 0 || i >= nfield_initial) error->all(FLERR,"Illegal thermo_modify command"); if (format_user[i]) delete [] format_user[i]; int n = strlen(arg[iarg+2]) + 1; format_user[i] = new char[n]; strcpy(format_user[i],arg[iarg+2]); } iarg += 3; } else error->all(FLERR,"Illegal thermo_modify command"); } } /* ---------------------------------------------------------------------- allocate all per-field memory ------------------------------------------------------------------------- */ void Thermo::allocate() { // n = specified fields + Volume field (added at run time) int n = nfield_initial + 1; keyword = new char*[n]; for (int i = 0; i < n; i++) keyword[i] = new char[32]; vfunc = new FnPtr[n]; vtype = new int[n]; format = new char*[n]; for (int i = 0; i < n; i++) format[i] = new char[32]; format_user = new char*[n]; for (int i = 0; i < n; i++) format_user[i] = NULL; field2index = new int[n]; argindex1 = new int[n]; argindex2 = new int[n]; // factor of 3 is max number of computes a single field can add ncompute = 0; id_compute = new char*[3*n]; compute_which = new int[3*n]; computes = new Compute*[3*n]; nfix = 0; id_fix = new char*[n]; fixes = new Fix*[n]; nvariable = 0; id_variable = new char*[n]; variables = new int[n]; } /* ---------------------------------------------------------------------- deallocate all per-field memory ------------------------------------------------------------------------- */ void Thermo::deallocate() { int n = nfield_initial + 1; for (int i = 0; i < n; i++) delete [] keyword[i]; delete [] keyword; delete [] vfunc; delete [] vtype; for (int i = 0; i < n; i++) delete [] format[i]; delete [] format; for (int i = 0; i < n; i++) delete [] format_user[i]; delete [] format_user; delete [] field2index; delete [] argindex1; delete [] argindex2; for (int i = 0; i < ncompute; i++) delete [] id_compute[i]; delete [] id_compute; delete [] compute_which; delete [] computes; for (int i = 0; i < nfix; i++) delete [] id_fix[i]; delete [] id_fix; delete [] fixes; for (int i = 0; i < nvariable; i++) delete [] id_variable[i]; delete [] id_variable; delete [] variables; } /* ---------------------------------------------------------------------- parse list of thermo keywords from str set compute flags (temp, press, pe, etc) ------------------------------------------------------------------------- */ void Thermo::parse_fields(char *str) { nfield = 0; // customize a new keyword by adding to if statement char *word = strtok(str," \0"); while (word) { if (strcmp(word,"step") == 0) { addfield("Step",&Thermo::compute_step,BIGINT); } else if (strcmp(word,"elapsed") == 0) { addfield("Elapsed",&Thermo::compute_elapsed,BIGINT); } else if (strcmp(word,"elaplong") == 0) { addfield("Elaplong",&Thermo::compute_elapsed_long,BIGINT); } else if (strcmp(word,"dt") == 0) { addfield("Dt",&Thermo::compute_dt,FLOAT); } else if (strcmp(word,"cpu") == 0) { addfield("CPU",&Thermo::compute_cpu,FLOAT); } else if (strcmp(word,"tpcpu") == 0) { addfield("T/CPU",&Thermo::compute_tpcpu,FLOAT); } else if (strcmp(word,"spcpu") == 0) { addfield("S/CPU",&Thermo::compute_spcpu,FLOAT); } else if (strcmp(word,"atoms") == 0) { addfield("Atoms",&Thermo::compute_atoms,BIGINT); } else if (strcmp(word,"temp") == 0) { addfield("Temp",&Thermo::compute_temp,FLOAT); index_temp = add_compute(id_temp,SCALAR); } else if (strcmp(word,"press") == 0) { addfield("Press",&Thermo::compute_press,FLOAT); index_press_scalar = add_compute(id_press,SCALAR); } else if (strcmp(word,"pe") == 0) { addfield("PotEng",&Thermo::compute_pe,FLOAT); index_pe = add_compute(id_pe,SCALAR); } else if (strcmp(word,"ke") == 0) { addfield("KinEng",&Thermo::compute_ke,FLOAT); index_temp = add_compute(id_temp,SCALAR); } else if (strcmp(word,"etotal") == 0) { addfield("TotEng",&Thermo::compute_etotal,FLOAT); index_temp = add_compute(id_temp,SCALAR); index_pe = add_compute(id_pe,SCALAR); } else if (strcmp(word,"enthalpy") == 0) { addfield("Enthalpy",&Thermo::compute_enthalpy,FLOAT); index_temp = add_compute(id_temp,SCALAR); index_press_scalar = add_compute(id_press,SCALAR); index_pe = add_compute(id_pe,SCALAR); } else if (strcmp(word,"evdwl") == 0) { addfield("E_vdwl",&Thermo::compute_evdwl,FLOAT); index_pe = add_compute(id_pe,SCALAR); } else if (strcmp(word,"ecoul") == 0) { addfield("E_coul",&Thermo::compute_ecoul,FLOAT); index_pe = add_compute(id_pe,SCALAR); } else if (strcmp(word,"epair") == 0) { addfield("E_pair",&Thermo::compute_epair,FLOAT); index_pe = add_compute(id_pe,SCALAR); } else if (strcmp(word,"ebond") == 0) { addfield("E_bond",&Thermo::compute_ebond,FLOAT); index_pe = add_compute(id_pe,SCALAR); } else if (strcmp(word,"eangle") == 0) { addfield("E_angle",&Thermo::compute_eangle,FLOAT); index_pe = add_compute(id_pe,SCALAR); } else if (strcmp(word,"edihed") == 0) { addfield("E_dihed",&Thermo::compute_edihed,FLOAT); index_pe = add_compute(id_pe,SCALAR); } else if (strcmp(word,"eimp") == 0) { addfield("E_impro",&Thermo::compute_eimp,FLOAT); index_pe = add_compute(id_pe,SCALAR); } else if (strcmp(word,"emol") == 0) { addfield("E_mol",&Thermo::compute_emol,FLOAT); index_pe = add_compute(id_pe,SCALAR); } else if (strcmp(word,"elong") == 0) { addfield("E_long",&Thermo::compute_elong,FLOAT); index_pe = add_compute(id_pe,SCALAR); } else if (strcmp(word,"etail") == 0) { addfield("E_tail",&Thermo::compute_etail,FLOAT); index_pe = add_compute(id_pe,SCALAR); } else if (strcmp(word,"vol") == 0) { addfield("Volume",&Thermo::compute_vol,FLOAT); } else if (strcmp(word,"lx") == 0) { addfield("Lx",&Thermo::compute_lx,FLOAT); } else if (strcmp(word,"ly") == 0) { addfield("Ly",&Thermo::compute_ly,FLOAT); } else if (strcmp(word,"lz") == 0) { addfield("Lz",&Thermo::compute_lz,FLOAT); } else if (strcmp(word,"xlo") == 0) { addfield("Xlo",&Thermo::compute_xlo,FLOAT); } else if (strcmp(word,"xhi") == 0) { addfield("Xhi",&Thermo::compute_xhi,FLOAT); } else if (strcmp(word,"ylo") == 0) { addfield("Ylo",&Thermo::compute_ylo,FLOAT); } else if (strcmp(word,"yhi") == 0) { addfield("Yhi",&Thermo::compute_yhi,FLOAT); } else if (strcmp(word,"zlo") == 0) { addfield("Zlo",&Thermo::compute_zlo,FLOAT); } else if (strcmp(word,"zhi") == 0) { addfield("Zhi",&Thermo::compute_zhi,FLOAT); } else if (strcmp(word,"xy") == 0) { addfield("Xy",&Thermo::compute_xy,FLOAT); } else if (strcmp(word,"xz") == 0) { addfield("Xz",&Thermo::compute_xz,FLOAT); } else if (strcmp(word,"yz") == 0) { addfield("Yz",&Thermo::compute_yz,FLOAT); } else if (strcmp(word,"xlat") == 0) { if (domain->lattice == NULL) error->all(FLERR,"Thermo keyword requires lattice be defined"); addfield("Xlat",&Thermo::compute_xlat,FLOAT); } else if (strcmp(word,"ylat") == 0) { if (domain->lattice == NULL) error->all(FLERR,"Thermo keyword requires lattice be defined"); addfield("Ylat",&Thermo::compute_ylat,FLOAT); } else if (strcmp(word,"zlat") == 0) { if (domain->lattice == NULL) error->all(FLERR,"Thermo keyword requires lattice be defined"); addfield("Zlat",&Thermo::compute_zlat,FLOAT); } else if (strcmp(word,"pxx") == 0) { addfield("Pxx",&Thermo::compute_pxx,FLOAT); index_press_vector = add_compute(id_press,VECTOR); } else if (strcmp(word,"pyy") == 0) { addfield("Pyy",&Thermo::compute_pyy,FLOAT); index_press_vector = add_compute(id_press,VECTOR); } else if (strcmp(word,"pzz") == 0) { addfield("Pzz",&Thermo::compute_pzz,FLOAT); index_press_vector = add_compute(id_press,VECTOR); } else if (strcmp(word,"pxy") == 0) { addfield("Pxy",&Thermo::compute_pxy,FLOAT); index_press_vector = add_compute(id_press,VECTOR); } else if (strcmp(word,"pxz") == 0) { addfield("Pxz",&Thermo::compute_pxz,FLOAT); index_press_vector = add_compute(id_press,VECTOR); } else if (strcmp(word,"pyz") == 0) { addfield("Pyz",&Thermo::compute_pyz,FLOAT); index_press_vector = add_compute(id_press,VECTOR); } else if (strcmp(word,"fmax") == 0) { addfield("Fmax",&Thermo::compute_fmax,FLOAT); } else if (strcmp(word,"fnorm") == 0) { addfield("Fnorm",&Thermo::compute_fnorm,FLOAT); } else if (strcmp(word,"cella") == 0) { addfield("Cella",&Thermo::compute_cella,FLOAT); } else if (strcmp(word,"cellb") == 0) { addfield("Cellb",&Thermo::compute_cellb,FLOAT); } else if (strcmp(word,"cellc") == 0) { addfield("Cellc",&Thermo::compute_cellc,FLOAT); } else if (strcmp(word,"cellalpha") == 0) { addfield("CellAlpha",&Thermo::compute_cellalpha,FLOAT); } else if (strcmp(word,"cellbeta") == 0) { addfield("CellBeta",&Thermo::compute_cellbeta,FLOAT); } else if (strcmp(word,"cellgamma") == 0) { addfield("CellGamma",&Thermo::compute_cellgamma,FLOAT); // compute value = c_ID, fix value = f_ID, variable value = v_ID // count trailing [] and store int arguments // copy = at most 8 chars of ID to pass to addfield } else if ((strncmp(word,"c_",2) == 0) || (strncmp(word,"f_",2) == 0) || (strncmp(word,"v_",2) == 0)) { int n = strlen(word); char *id = new char[n]; strcpy(id,&word[2]); char copy[9]; strncpy(copy,id,8); copy[8] = '\0'; // parse zero or one or two trailing brackets from ID // argindex1,argindex2 = int inside each bracket pair, 0 if no bracket char *ptr = strchr(id,'['); if (ptr == NULL) argindex1[nfield] = 0; else { *ptr = '\0'; argindex1[nfield] = input->variable->int_between_brackets(ptr); ptr++; if (*ptr == '[') { argindex2[nfield] = input->variable->int_between_brackets(ptr); ptr++; } else argindex2[nfield] = 0; } if (word[0] == 'c') { n = modify->find_compute(id); if (n < 0) error->all(FLERR,"Could not find thermo custom compute ID"); if (argindex1[nfield] == 0 && modify->compute[n]->scalar_flag == 0) error->all(FLERR,"Thermo compute does not compute scalar"); if (argindex1[nfield] > 0 && argindex2[nfield] == 0) { if (modify->compute[n]->vector_flag == 0) error->all(FLERR,"Thermo compute does not compute vector"); if (argindex1[nfield] > modify->compute[n]->size_vector) error->all(FLERR,"Thermo compute vector is accessed out-of-range"); } if (argindex1[nfield] > 0 && argindex2[nfield] > 0) { if (modify->compute[n]->array_flag == 0) error->all(FLERR,"Thermo compute does not compute array"); if (argindex1[nfield] > modify->compute[n]->size_array_rows || argindex2[nfield] > modify->compute[n]->size_array_cols) error->all(FLERR,"Thermo compute array is accessed out-of-range"); } if (argindex1[nfield] == 0) field2index[nfield] = add_compute(id,SCALAR); else if (argindex2[nfield] == 0) field2index[nfield] = add_compute(id,VECTOR); else field2index[nfield] = add_compute(id,ARRAY); addfield(copy,&Thermo::compute_compute,FLOAT); } else if (word[0] == 'f') { n = modify->find_fix(id); if (n < 0) error->all(FLERR,"Could not find thermo custom fix ID"); if (argindex1[nfield] == 0 && modify->fix[n]->scalar_flag == 0) error->all(FLERR,"Thermo fix does not compute scalar"); if (argindex1[nfield] > 0 && argindex2[nfield] == 0) { if (modify->fix[n]->vector_flag == 0) error->all(FLERR,"Thermo fix does not compute vector"); if (argindex1[nfield] > modify->fix[n]->size_vector) error->all(FLERR,"Thermo fix vector is accessed out-of-range"); } if (argindex1[nfield] > 0 && argindex2[nfield] > 0) { if (modify->fix[n]->array_flag == 0) error->all(FLERR,"Thermo fix does not compute array"); if (argindex1[nfield] > modify->fix[n]->size_array_rows || argindex2[nfield] > modify->fix[n]->size_array_cols) error->all(FLERR,"Thermo fix array is accessed out-of-range"); } field2index[nfield] = add_fix(id); addfield(copy,&Thermo::compute_fix,FLOAT); } else if (word[0] == 'v') { n = input->variable->find(id); if (n < 0) error->all(FLERR,"Could not find thermo custom variable name"); if (input->variable->equalstyle(n) == 0) error->all(FLERR,"Thermo custom variable is not equal-style variable"); if (argindex1[nfield]) error->all(FLERR,"Thermo custom variable cannot be indexed"); field2index[nfield] = add_variable(id); addfield(copy,&Thermo::compute_variable,FLOAT); } delete [] id; } else error->all(FLERR,"Invalid keyword in thermo_style custom command"); word = strtok(NULL," \0"); } } /* ---------------------------------------------------------------------- add field to list of quantities to print ------------------------------------------------------------------------- */ void Thermo::addfield(const char *key, FnPtr func, int typeflag) { strcpy(keyword[nfield],key); vfunc[nfield] = func; vtype[nfield] = typeflag; nfield++; } /* ---------------------------------------------------------------------- add compute ID to list of Compute objects to call return location of where this Compute is in list if already in list with same which, do not add, just return index ------------------------------------------------------------------------- */ int Thermo::add_compute(const char *id, int which) { int icompute; for (icompute = 0; icompute < ncompute; icompute++) if ((strcmp(id,id_compute[icompute]) == 0) && which == compute_which[icompute]) break; if (icompute < ncompute) return icompute; int n = strlen(id) + 1; id_compute[ncompute] = new char[n]; strcpy(id_compute[ncompute],id); compute_which[ncompute] = which; ncompute++; return ncompute-1; } /* ---------------------------------------------------------------------- add fix ID to list of Fix objects to call ------------------------------------------------------------------------- */ int Thermo::add_fix(const char *id) { int n = strlen(id) + 1; id_fix[nfix] = new char[n]; strcpy(id_fix[nfix],id); nfix++; return nfix-1; } /* ---------------------------------------------------------------------- add variable ID to list of Variables to evaluate ------------------------------------------------------------------------- */ int Thermo::add_variable(const char *id) { int n = strlen(id) + 1; id_variable[nvariable] = new char[n]; strcpy(id_variable[nvariable],id); nvariable++; return nvariable-1; } /* ---------------------------------------------------------------------- compute a single thermodyanmic value, word is any keyword in custom list called when a variable is evaluated by Variable class return value as double in answer return 0 if str is recoginzed keyword, 1 if unrecognized customize a new keyword by adding to if statement ------------------------------------------------------------------------- */ int Thermo::evaluate_keyword(char *word, double *answer) { // invoke a lo-level thermo routine to compute the variable value // if keyword requires a compute, error if thermo doesn't use the compute // if inbetween runs and needed compute is not current, error // if in middle of run and needed compute is not current, invoke it // for keywords that use pe indirectly (evdwl, ebond, etc): // check if energy was tallied on this timestep and set pe->invoked_flag // this will trigger next timestep for energy tallying via addstep() if (strcmp(word,"step") == 0) { compute_step(); dvalue = bivalue; } else if (strcmp(word,"elapsed") == 0) { if (update->whichflag == 0) error->all(FLERR,"This variable thermo keyword cannot be used between runs"); compute_elapsed(); dvalue = bivalue; } else if (strcmp(word,"elaplong") == 0) { if (update->whichflag == 0) error->all(FLERR,"This variable thermo keyword cannot be used between runs"); compute_elapsed_long(); dvalue = bivalue; } else if (strcmp(word,"dt") == 0) { compute_dt(); } else if (strcmp(word,"cpu") == 0) { if (update->whichflag == 0) error->all(FLERR,"This variable thermo keyword cannot be used between runs"); compute_cpu(); } else if (strcmp(word,"tpcpu") == 0) { if (update->whichflag == 0) error->all(FLERR,"This variable thermo keyword cannot be used between runs"); compute_tpcpu(); } else if (strcmp(word,"spcpu") == 0) { if (update->whichflag == 0) error->all(FLERR,"This variable thermo keyword cannot be used between runs"); compute_spcpu(); } else if (strcmp(word,"atoms") == 0) { compute_atoms(); dvalue = bivalue; } else if (strcmp(word,"temp") == 0) { if (!temperature) error->all(FLERR,"Thermo keyword in variable requires " "thermo to use/init temp"); if (update->whichflag == 0) { if (temperature->invoked_scalar != update->ntimestep) error->all(FLERR,"Compute used in variable thermo keyword between runs " "is not current"); } else if (!(temperature->invoked_flag & INVOKED_SCALAR)) { temperature->compute_scalar(); temperature->invoked_flag |= INVOKED_SCALAR; } compute_temp(); } else if (strcmp(word,"press") == 0) { if (!pressure) error->all(FLERR,"Thermo keyword in variable requires " "thermo to use/init press"); if (update->whichflag == 0) { if (pressure->invoked_scalar != update->ntimestep) error->all(FLERR,"Compute used in variable thermo keyword between runs " "is not current"); } else if (!(pressure->invoked_flag & INVOKED_SCALAR)) { pressure->compute_scalar(); pressure->invoked_flag |= INVOKED_SCALAR; } compute_press(); } else if (strcmp(word,"pe") == 0) { if (!pe) error->all(FLERR,"Thermo keyword in variable requires thermo to use/init pe"); if (update->whichflag == 0) { if (pe->invoked_scalar != update->ntimestep) error->all(FLERR,"Compute used in variable thermo keyword between runs " "is not current"); } else if (!(pe->invoked_flag & INVOKED_SCALAR)) { pe->compute_scalar(); pe->invoked_flag |= INVOKED_SCALAR; } compute_pe(); } else if (strcmp(word,"ke") == 0) { if (!temperature) error->all(FLERR,"Thermo keyword in variable requires " "thermo to use/init temp"); if (update->whichflag == 0) { if (temperature->invoked_scalar != update->ntimestep) error->all(FLERR,"Compute used in variable thermo keyword between runs " "is not current"); } else if (!(temperature->invoked_flag & INVOKED_SCALAR)) { temperature->compute_scalar(); temperature->invoked_flag |= INVOKED_SCALAR; } compute_ke(); } else if (strcmp(word,"etotal") == 0) { if (!pe) error->all(FLERR,"Thermo keyword in variable requires thermo to use/init pe"); if (update->whichflag == 0) { if (pe->invoked_scalar != update->ntimestep) error->all(FLERR,"Compute used in variable thermo keyword between runs " "is not current"); } else if (!(pe->invoked_flag & INVOKED_SCALAR)) { pe->compute_scalar(); pe->invoked_flag |= INVOKED_SCALAR; } if (!temperature) error->all(FLERR,"Thermo keyword in variable requires " "thermo to use/init temp"); if (update->whichflag == 0) { if (temperature->invoked_scalar != update->ntimestep) error->all(FLERR,"Compute used in variable thermo keyword between runs " "is not current"); } else if (!(temperature->invoked_flag & INVOKED_SCALAR)) { temperature->compute_scalar(); temperature->invoked_flag |= INVOKED_SCALAR; } compute_etotal(); } else if (strcmp(word,"enthalpy") == 0) { if (!pe) error->all(FLERR,"Thermo keyword in variable requires thermo to use/init pe"); if (update->whichflag == 0) { if (pe->invoked_scalar != update->ntimestep) error->all(FLERR,"Compute used in variable thermo keyword between runs " "is not current"); } else if (!(pe->invoked_flag & INVOKED_SCALAR)) { pe->compute_scalar(); pe->invoked_flag |= INVOKED_SCALAR; } if (!temperature) error->all(FLERR,"Thermo keyword in variable requires " "thermo to use/init temp"); if (update->whichflag == 0) { if (temperature->invoked_scalar != update->ntimestep) error->all(FLERR,"Compute used in variable thermo keyword between runs " "is not current"); } else if (!(temperature->invoked_flag & INVOKED_SCALAR)) { temperature->compute_scalar(); temperature->invoked_flag |= INVOKED_SCALAR; } if (!pressure) error->all(FLERR,"Thermo keyword in variable requires " "thermo to use/init press"); if (update->whichflag == 0) { if (pressure->invoked_scalar != update->ntimestep) error->all(FLERR,"Compute used in variable thermo keyword between runs " "is not current"); } else if (!(pressure->invoked_flag & INVOKED_SCALAR)) { pressure->compute_scalar(); pressure->invoked_flag |= INVOKED_SCALAR; } compute_enthalpy(); } else if (strcmp(word,"evdwl") == 0) { if (update->eflag_global != update->ntimestep) error->all(FLERR,"Energy was not tallied on needed timestep"); if (!pe) error->all(FLERR,"Thermo keyword in variable requires thermo to use/init pe"); pe->invoked_flag |= INVOKED_SCALAR; compute_evdwl(); } else if (strcmp(word,"ecoul") == 0) { if (update->eflag_global != update->ntimestep) error->all(FLERR,"Energy was not tallied on needed timestep"); if (!pe) error->all(FLERR,"Thermo keyword in variable requires thermo to use/init pe"); pe->invoked_flag |= INVOKED_SCALAR; compute_ecoul(); } else if (strcmp(word,"epair") == 0) { if (update->eflag_global != update->ntimestep) error->all(FLERR,"Energy was not tallied on needed timestep"); if (!pe) error->all(FLERR,"Thermo keyword in variable requires thermo to use/init pe"); pe->invoked_flag |= INVOKED_SCALAR; compute_epair(); } else if (strcmp(word,"ebond") == 0) { if (update->eflag_global != update->ntimestep) error->all(FLERR,"Energy was not tallied on needed timestep"); if (!pe) error->all(FLERR,"Thermo keyword in variable requires thermo to use/init pe"); pe->invoked_flag |= INVOKED_SCALAR; compute_ebond(); } else if (strcmp(word,"eangle") == 0) { if (update->eflag_global != update->ntimestep) error->all(FLERR,"Energy was not tallied on needed timestep"); if (!pe) error->all(FLERR,"Thermo keyword in variable requires thermo to use/init pe"); pe->invoked_flag |= INVOKED_SCALAR; compute_eangle(); } else if (strcmp(word,"edihed") == 0) { if (update->eflag_global != update->ntimestep) error->all(FLERR,"Energy was not tallied on needed timestep"); if (!pe) error->all(FLERR,"Thermo keyword in variable requires thermo to use/init pe"); pe->invoked_flag |= INVOKED_SCALAR; compute_edihed(); } else if (strcmp(word,"eimp") == 0) { if (update->eflag_global != update->ntimestep) error->all(FLERR,"Energy was not tallied on needed timestep"); if (!pe) error->all(FLERR,"Thermo keyword in variable requires thermo to use/init pe"); pe->invoked_flag |= INVOKED_SCALAR; compute_eimp(); } else if (strcmp(word,"emol") == 0) { if (update->eflag_global != update->ntimestep) error->all(FLERR,"Energy was not tallied on needed timestep"); if (!pe) error->all(FLERR,"Thermo keyword in variable requires thermo to use/init pe"); pe->invoked_flag |= INVOKED_SCALAR; compute_emol(); } else if (strcmp(word,"elong") == 0) { if (update->eflag_global != update->ntimestep) error->all(FLERR,"Energy was not tallied on needed timestep"); if (!pe) error->all(FLERR,"Thermo keyword in variable requires thermo to use/init pe"); pe->invoked_flag |= INVOKED_SCALAR; compute_elong(); } else if (strcmp(word,"etail") == 0) { if (update->eflag_global != update->ntimestep) error->all(FLERR,"Energy was not tallied on needed timestep"); if (!pe) error->all(FLERR,"Thermo keyword in variable requires thermo to use/init pe"); pe->invoked_flag |= INVOKED_SCALAR; compute_etail(); } else if (strcmp(word,"vol") == 0) compute_vol(); else if (strcmp(word,"lx") == 0) compute_lx(); else if (strcmp(word,"ly") == 0) compute_ly(); else if (strcmp(word,"lz") == 0) compute_lz(); else if (strcmp(word,"xlo") == 0) compute_xlo(); else if (strcmp(word,"xhi") == 0) compute_xhi(); else if (strcmp(word,"ylo") == 0) compute_ylo(); else if (strcmp(word,"yhi") == 0) compute_yhi(); else if (strcmp(word,"zlo") == 0) compute_zlo(); else if (strcmp(word,"zhi") == 0) compute_zhi(); else if (strcmp(word,"xy") == 0) compute_xy(); else if (strcmp(word,"xz") == 0) compute_xz(); else if (strcmp(word,"yz") == 0) compute_yz(); else if (strcmp(word,"xlat") == 0) { if (domain->lattice == NULL) error->all(FLERR,"Thermo keyword in variable requires lattice be defined"); compute_xlat(); } else if (strcmp(word,"ylat") == 0) { if (domain->lattice == NULL) error->all(FLERR,"Thermo keyword in variable requires lattice be defined"); compute_ylat(); } else if (strcmp(word,"zlat") == 0) { if (domain->lattice == NULL) error->all(FLERR,"Thermo keyword in variable requires lattice be defined"); compute_zlat(); } else if (strcmp(word,"pxx") == 0) { if (!pressure) error->all(FLERR,"Thermo keyword in variable requires " "thermo to use/init press"); if (update->whichflag == 0) { if (pressure->invoked_vector != update->ntimestep) error->all(FLERR,"Compute used in variable thermo keyword between runs " "is not current"); } else if (!(pressure->invoked_flag & INVOKED_VECTOR)) { pressure->compute_vector(); pressure->invoked_flag |= INVOKED_VECTOR; } compute_pxx(); } else if (strcmp(word,"pyy") == 0) { if (!pressure) error->all(FLERR,"Thermo keyword in variable requires " "thermo to use/init press"); if (update->whichflag == 0) { if (pressure->invoked_vector != update->ntimestep) error->all(FLERR,"Compute used in variable thermo keyword between runs " "is not current"); } else if (!(pressure->invoked_flag & INVOKED_VECTOR)) { pressure->compute_vector(); pressure->invoked_flag |= INVOKED_VECTOR; } compute_pyy(); } else if (strcmp(word,"pzz") == 0) { if (!pressure) error->all(FLERR,"Thermo keyword in variable requires " "thermo to use/init press"); if (update->whichflag == 0) { if (pressure->invoked_vector != update->ntimestep) error->all(FLERR,"Compute used in variable thermo keyword between runs " "is not current"); } else if (!(pressure->invoked_flag & INVOKED_VECTOR)) { pressure->compute_vector(); pressure->invoked_flag |= INVOKED_VECTOR; } compute_pzz(); } else if (strcmp(word,"pxy") == 0) { if (!pressure) error->all(FLERR,"Thermo keyword in variable requires " "thermo to use/init press"); if (update->whichflag == 0) { if (pressure->invoked_vector != update->ntimestep) error->all(FLERR,"Compute used in variable thermo keyword between runs " "is not current"); } else if (!(pressure->invoked_flag & INVOKED_VECTOR)) { pressure->compute_vector(); pressure->invoked_flag |= INVOKED_VECTOR; } compute_pxy(); } else if (strcmp(word,"pxz") == 0) { if (!pressure) error->all(FLERR,"Thermo keyword in variable requires " "thermo to use/init press"); if (update->whichflag == 0) { if (pressure->invoked_vector != update->ntimestep) error->all(FLERR,"Compute used in variable thermo keyword between runs " "is not current"); } else if (!(pressure->invoked_flag & INVOKED_VECTOR)) { pressure->compute_vector(); pressure->invoked_flag |= INVOKED_VECTOR; } compute_pxz(); } else if (strcmp(word,"pyz") == 0) { if (!pressure) error->all(FLERR,"Thermo keyword in variable requires " "thermo to use/init press"); if (update->whichflag == 0) { if (pressure->invoked_vector != update->ntimestep) error->all(FLERR,"Compute used in variable thermo keyword between runs " "is not current"); } else if (!(pressure->invoked_flag & INVOKED_VECTOR)) { pressure->compute_vector(); pressure->invoked_flag |= INVOKED_VECTOR; } compute_pyz(); } else if (strcmp(word,"fmax") == 0) compute_fmax(); else if (strcmp(word,"fnorm") == 0) compute_fnorm(); else if (strcmp(word,"cella") == 0) compute_cella(); else if (strcmp(word,"cellb") == 0) compute_cellb(); else if (strcmp(word,"cellc") == 0) compute_cellc(); else if (strcmp(word,"cellalpha") == 0) compute_cellalpha(); else if (strcmp(word,"cellbeta") == 0) compute_cellbeta(); else if (strcmp(word,"cellgamma") == 0) compute_cellgamma(); else return 1; *answer = dvalue; return 0; } /* ---------------------------------------------------------------------- extraction of Compute, Fix, Variable results compute/fix are normalized by atoms if returning extensive value variable value is not normalized (formula should normalize if desired) ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */ void Thermo::compute_compute() { int m = field2index[ifield]; Compute *compute = computes[m]; if (compute_which[m] == SCALAR) { dvalue = compute->scalar; if (normflag && compute->extscalar) dvalue /= natoms; } else if (compute_which[m] == VECTOR) { dvalue = compute->vector[argindex1[ifield]-1]; if (normflag) { if (compute->extvector == 0) return; else if (compute->extvector == 1) dvalue /= natoms; else if (compute->extlist[argindex1[ifield]-1]) dvalue /= natoms; } } else { dvalue = compute->array[argindex1[ifield]-1][argindex2[ifield]-1]; if (normflag && compute->extarray) dvalue /= natoms; } } /* ---------------------------------------------------------------------- */ void Thermo::compute_fix() { int m = field2index[ifield]; Fix *fix = fixes[m]; if (argindex1[ifield] == 0) { dvalue = fix->compute_scalar(); if (normflag && fix->extscalar) dvalue /= natoms; } else if (argindex2[ifield] == 0) { dvalue = fix->compute_vector(argindex1[ifield]-1); if (normflag) { if (fix->extvector == 0) return; else if (fix->extvector == 1) dvalue /= natoms; else if (fix->extlist[argindex1[ifield]-1]) dvalue /= natoms; } } else { dvalue = fix->compute_array(argindex1[ifield]-1,argindex2[ifield]-1); if (normflag && fix->extarray) dvalue /= natoms; } } /* ---------------------------------------------------------------------- */ void Thermo::compute_variable() { dvalue = input->variable->compute_equal(variables[field2index[ifield]]); } /* ---------------------------------------------------------------------- one method for every keyword thermo can output called by compute() or evaluate_keyword() compute will have already been called set ivalue/dvalue/bivalue if value is int/double/bigint customize a new keyword by adding a method ------------------------------------------------------------------------- */ void Thermo::compute_step() { bivalue = update->ntimestep; } /* ---------------------------------------------------------------------- */ void Thermo::compute_elapsed() { bivalue = update->ntimestep - update->firststep; } /* ---------------------------------------------------------------------- */ void Thermo::compute_elapsed_long() { bivalue = update->ntimestep - update->beginstep; } /* ---------------------------------------------------------------------- */ void Thermo::compute_dt() { dvalue = update->dt; } /* ---------------------------------------------------------------------- */ void Thermo::compute_cpu() { if (firststep == 0) dvalue = 0.0; else dvalue = timer->elapsed(TIME_LOOP); } /* ---------------------------------------------------------------------- */ void Thermo::compute_tpcpu() { double new_cpu; double new_time = update->ntimestep * update->dt; if (firststep == 0) { new_cpu = 0.0; dvalue = 0.0; } else { new_cpu = timer->elapsed(TIME_LOOP); double cpu_diff = new_cpu - last_tpcpu; double time_diff = new_time - last_time; if (time_diff > 0.0 && cpu_diff > 0.0) dvalue = time_diff/cpu_diff; else dvalue = 0.0; } last_time = new_time; last_tpcpu = new_cpu; } /* ---------------------------------------------------------------------- */ void Thermo::compute_spcpu() { double new_cpu; int new_step = update->ntimestep; if (firststep == 0) { new_cpu = 0.0; dvalue = 0.0; } else { new_cpu = timer->elapsed(TIME_LOOP); double cpu_diff = new_cpu - last_spcpu; int step_diff = new_step - last_step; if (cpu_diff > 0.0) dvalue = step_diff/cpu_diff; else dvalue = 0.0; } last_step = new_step; last_spcpu = new_cpu; } /* ---------------------------------------------------------------------- */ void Thermo::compute_atoms() { bivalue = natoms; } /* ---------------------------------------------------------------------- */ void Thermo::compute_temp() { dvalue = temperature->scalar; } /* ---------------------------------------------------------------------- */ void Thermo::compute_press() { dvalue = pressure->scalar; } /* ---------------------------------------------------------------------- */ void Thermo::compute_pe() { dvalue = pe->scalar; if (normflag) dvalue /= natoms; } /* ---------------------------------------------------------------------- */ void Thermo::compute_ke() { dvalue = temperature->scalar; dvalue *= 0.5 * temperature->dof * force->boltz; if (normflag) dvalue /= natoms; } /* ---------------------------------------------------------------------- */ void Thermo::compute_etotal() { compute_pe(); double ke = temperature->scalar; ke *= 0.5 * temperature->dof * force->boltz; if (normflag) ke /= natoms; dvalue += ke; } /* ---------------------------------------------------------------------- */ void Thermo::compute_enthalpy() { compute_etotal(); double etmp = dvalue; compute_vol(); double vtmp = dvalue; if (normflag) vtmp /= natoms; compute_press(); double ptmp = dvalue; dvalue = etmp + ptmp*vtmp/(force->nktv2p); } /* ---------------------------------------------------------------------- */ void Thermo::compute_evdwl() { double tmp = 0.0; if (force->pair) tmp += force->pair->eng_vdwl; MPI_Allreduce(&tmp,&dvalue,1,MPI_DOUBLE,MPI_SUM,world); if (force->pair && force->pair->tail_flag) { double volume = domain->xprd * domain->yprd * domain->zprd; dvalue += force->pair->etail / volume; } if (normflag) dvalue /= natoms; } /* ---------------------------------------------------------------------- */ void Thermo::compute_ecoul() { double tmp = 0.0; if (force->pair) tmp += force->pair->eng_coul; MPI_Allreduce(&tmp,&dvalue,1,MPI_DOUBLE,MPI_SUM,world); if (normflag) dvalue /= natoms; } /* ---------------------------------------------------------------------- */ void Thermo::compute_epair() { double tmp = 0.0; if (force->pair) tmp += force->pair->eng_vdwl + force->pair->eng_coul; MPI_Allreduce(&tmp,&dvalue,1,MPI_DOUBLE,MPI_SUM,world); if (force->kspace) dvalue += force->kspace->energy; if (force->pair && force->pair->tail_flag) { double volume = domain->xprd * domain->yprd * domain->zprd; dvalue += force->pair->etail / volume; } if (normflag) dvalue /= natoms; } /* ---------------------------------------------------------------------- */ void Thermo::compute_ebond() { if (force->bond) { double tmp = force->bond->energy; MPI_Allreduce(&tmp,&dvalue,1,MPI_DOUBLE,MPI_SUM,world); if (normflag) dvalue /= natoms; } else dvalue = 0.0; } /* ---------------------------------------------------------------------- */ void Thermo::compute_eangle() { if (force->angle) { double tmp = force->angle->energy; MPI_Allreduce(&tmp,&dvalue,1,MPI_DOUBLE,MPI_SUM,world); if (normflag) dvalue /= natoms; } else dvalue = 0.0; } /* ---------------------------------------------------------------------- */ void Thermo::compute_edihed() { if (force->dihedral) { double tmp = force->dihedral->energy; MPI_Allreduce(&tmp,&dvalue,1,MPI_DOUBLE,MPI_SUM,world); if (normflag) dvalue /= natoms; } else dvalue = 0.0; } /* ---------------------------------------------------------------------- */ void Thermo::compute_eimp() { if (force->improper) { double tmp = force->improper->energy; MPI_Allreduce(&tmp,&dvalue,1,MPI_DOUBLE,MPI_SUM,world); if (normflag) dvalue /= natoms; } else dvalue = 0.0; } /* ---------------------------------------------------------------------- */ void Thermo::compute_emol() { double tmp = 0.0; if (atom->molecular) { if (force->bond) tmp += force->bond->energy; if (force->angle) tmp += force->angle->energy; if (force->dihedral) tmp += force->dihedral->energy; if (force->improper) tmp += force->improper->energy; MPI_Allreduce(&tmp,&dvalue,1,MPI_DOUBLE,MPI_SUM,world); if (normflag) dvalue /= natoms; } else dvalue = 0.0; } /* ---------------------------------------------------------------------- */ void Thermo::compute_elong() { if (force->kspace) { dvalue = force->kspace->energy; if (normflag) dvalue /= natoms; } else dvalue = 0.0; } /* ---------------------------------------------------------------------- */ void Thermo::compute_etail() { if (force->pair && force->pair->tail_flag) { double volume = domain->xprd * domain->yprd * domain->zprd; dvalue = force->pair->etail / volume; if (normflag) dvalue /= natoms; } else dvalue = 0.0; } /* ---------------------------------------------------------------------- */ void Thermo::compute_vol() { if (domain->dimension == 3) dvalue = domain->xprd * domain->yprd * domain->zprd; else dvalue = domain->xprd * domain->yprd; } /* ---------------------------------------------------------------------- */ void Thermo::compute_lx() { dvalue = domain->xprd; } /* ---------------------------------------------------------------------- */ void Thermo::compute_ly() { dvalue = domain->yprd; } /* ---------------------------------------------------------------------- */ void Thermo::compute_lz() { dvalue = domain->zprd; } /* ---------------------------------------------------------------------- */ void Thermo::compute_xlo() { dvalue = domain->boxlo[0]; } /* ---------------------------------------------------------------------- */ void Thermo::compute_xhi() { dvalue = domain->boxhi[0]; } /* ---------------------------------------------------------------------- */ void Thermo::compute_ylo() { dvalue = domain->boxlo[1]; } /* ---------------------------------------------------------------------- */ void Thermo::compute_yhi() { dvalue = domain->boxhi[1]; } /* ---------------------------------------------------------------------- */ void Thermo::compute_zlo() { dvalue = domain->boxlo[2]; } /* ---------------------------------------------------------------------- */ void Thermo::compute_zhi() { dvalue = domain->boxhi[2]; } /* ---------------------------------------------------------------------- */ void Thermo::compute_xy() { dvalue = domain->xy; } /* ---------------------------------------------------------------------- */ void Thermo::compute_xz() { dvalue = domain->xz; } /* ---------------------------------------------------------------------- */ void Thermo::compute_yz() { dvalue = domain->yz; } /* ---------------------------------------------------------------------- */ void Thermo::compute_xlat() { dvalue = domain->lattice->xlattice; } /* ---------------------------------------------------------------------- */ void Thermo::compute_ylat() { dvalue = domain->lattice->ylattice; } /* ---------------------------------------------------------------------- */ void Thermo::compute_zlat() { dvalue = domain->lattice->zlattice; } /* ---------------------------------------------------------------------- */ void Thermo::compute_pxx() { dvalue = pressure->vector[0]; } /* ---------------------------------------------------------------------- */ void Thermo::compute_pyy() { dvalue = pressure->vector[1]; } /* ---------------------------------------------------------------------- */ void Thermo::compute_pzz() { dvalue = pressure->vector[2]; } /* ---------------------------------------------------------------------- */ void Thermo::compute_pxy() { dvalue = pressure->vector[3]; } /* ---------------------------------------------------------------------- */ void Thermo::compute_pxz() { dvalue = pressure->vector[4]; } /* ---------------------------------------------------------------------- */ void Thermo::compute_pyz() { dvalue = pressure->vector[5]; } /* ---------------------------------------------------------------------- */ void Thermo::compute_fmax() { double **f = atom->f; int nlocal = atom->nlocal; double max = 0.0; for (int i = 0; i < nlocal; i++) { max = MAX(max,fabs(f[i][0])); max = MAX(max,fabs(f[i][1])); max = MAX(max,fabs(f[i][2])); } double maxall; MPI_Allreduce(&max,&maxall,1,MPI_DOUBLE,MPI_MAX,world); dvalue = maxall; } /* ---------------------------------------------------------------------- */ void Thermo::compute_fnorm() { double **f = atom->f; int nlocal = atom->nlocal; double dot = 0.0; for (int i = 0; i < nlocal; i++) dot += f[i][0]*f[i][0] + f[i][1]*f[i][1] + f[i][2]*f[i][2]; double dotall; MPI_Allreduce(&dot,&dotall,1,MPI_DOUBLE,MPI_SUM,world); dvalue = sqrt(dotall); } /* ---------------------------------------------------------------------- */ void Thermo::compute_cella() { dvalue = domain->xprd; } /* ---------------------------------------------------------------------- */ void Thermo::compute_cellb() { if (!domain->triclinic) dvalue = domain->yprd; else { double* h = domain->h; dvalue = sqrt(h[1]*h[1]+h[5]*h[5]); } } /* ---------------------------------------------------------------------- */ void Thermo::compute_cellc() { if (!domain->triclinic) dvalue = domain->zprd; else { double* h = domain->h; dvalue = sqrt(h[2]*h[2]+h[3]*h[3]+h[4]*h[4]); } } /* ---------------------------------------------------------------------- */ void Thermo::compute_cellalpha() { if (!domain->triclinic) dvalue = 90.0; else { // Cos(alpha) = (xy.xz + ly.yz)/(b.c) double* h = domain->h; double cosalpha = (h[5]*h[4]+h[1]*h[3])/ sqrt((h[1]*h[1]+h[5]*h[5])*(h[2]*h[2]+h[3]*h[3]+h[4]*h[4])); dvalue = acos(cosalpha)*180.0/MY_PI; } } /* ---------------------------------------------------------------------- */ void Thermo::compute_cellbeta() { if (!domain->triclinic) dvalue = 90.0; else { // Cos(beta) = xz/c double* h = domain->h; double cosbeta = h[4]/sqrt(h[2]*h[2]+h[3]*h[3]+h[4]*h[4]); dvalue = acos(cosbeta)*180.0/MY_PI; } } /* ---------------------------------------------------------------------- */ void Thermo::compute_cellgamma() { if (!domain->triclinic) dvalue = 90.0; else { // Cos(gamma) = xy/b double* h = domain->h; double cosgamma = h[5]/sqrt(h[1]*h[1]+h[5]*h[5]); dvalue = acos(cosgamma)*180.0/MY_PI; } } diff --git a/src/velocity.cpp b/src/velocity.cpp index ef95a873a..eb46bc0f6 100644 --- a/src/velocity.cpp +++ b/src/velocity.cpp @@ -1,796 +1,796 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ #include "lmptype.h" #include "mpi.h" #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "velocity.h" #include "atom.h" #include "update.h" #include "domain.h" #include "lattice.h" #include "input.h" #include "variable.h" #include "force.h" #include "modify.h" #include "compute.h" #include "compute_temp.h" #include "random_park.h" #include "group.h" #include "comm.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; enum{CREATE,SET,SCALE,RAMP,ZERO}; enum{ALL,LOCAL,GEOM}; enum{NONE,CONSTANT,EQUAL,ATOM}; #define WARMUP 100 #define SMALL 0.001 /* ---------------------------------------------------------------------- */ Velocity::Velocity(LAMMPS *lmp) : Pointers(lmp) {} /* ---------------------------------------------------------------------- */ void Velocity::command(int narg, char **arg) { if (narg < 2) error->all(FLERR,"Illegal velocity command"); if (domain->box_exist == 0) error->all(FLERR,"Velocity command before simulation box is defined"); if (atom->natoms == 0) error->all(FLERR,"Velocity command with no atoms existing"); // atom masses must all be set atom->check_mass(); // identify group igroup = group->find(arg[0]); if (igroup == -1) error->all(FLERR,"Could not find velocity group ID"); groupbit = group->bitmask[igroup]; // identify style if (strcmp(arg[1],"create") == 0) style = CREATE; else if (strcmp(arg[1],"set") == 0) style = SET; else if (strcmp(arg[1],"scale") == 0) style = SCALE; else if (strcmp(arg[1],"ramp") == 0) style = RAMP; else if (strcmp(arg[1],"zero") == 0) style = ZERO; else error->all(FLERR,"Illegal velocity command"); // set defaults temperature = NULL; dist_flag = 0; sum_flag = 0; momentum_flag = 1; rotation_flag = 0; loop_flag = ALL; scale_flag = 1; // read options from end of input line // change defaults as options specify if (style == CREATE) options(narg-4,&arg[4]); else if (style == SET) options(narg-5,&arg[5]); else if (style == SCALE) options(narg-3,&arg[3]); else if (style == RAMP) options(narg-8,&arg[8]); else if (style == ZERO) options(narg-3,&arg[3]); // initialize velocities based on style // create() invoked differently, so can be called externally if (style == CREATE) { double t_desired = atof(arg[2]); int seed = atoi(arg[3]); create(t_desired,seed); } else if (style == SET) set(narg-2,&arg[2]); else if (style == SCALE) scale(narg-2,&arg[2]); else if (style == RAMP) ramp(narg-2,&arg[2]); else if (style == ZERO) zero(narg-2,&arg[2]); } /* ---------------------------------------------------------------------- initialization of defaults before calling velocity methods externaly ------------------------------------------------------------------------- */ -void Velocity::init_external(char *extgroup) +void Velocity::init_external(const char *extgroup) { igroup = group->find(extgroup); if (igroup == -1) error->all(FLERR,"Could not find velocity group ID"); groupbit = group->bitmask[igroup]; temperature = NULL; dist_flag = 0; sum_flag = 0; momentum_flag = 1; rotation_flag = 0; loop_flag = ALL; scale_flag = 1; } /* ---------------------------------------------------------------------- */ void Velocity::create(double t_desired, int seed) { int i; if (seed <= 0) error->all(FLERR,"Illegal velocity create command"); // if temperature = NULL, create a new ComputeTemp with the velocity group int tflag = 0; if (temperature == NULL) { char **arg = new char*[3]; arg[0] = (char *) "velocity_temp"; arg[1] = group->names[igroup]; arg[2] = (char *) "temp"; temperature = new ComputeTemp(lmp,3,arg); tflag = 1; delete [] arg; } // initialize temperature computation // warn if groups don't match if (igroup != temperature->igroup && comm->me == 0) error->warning(FLERR,"Mismatch between velocity and compute groups"); temperature->init(); // store a copy of current velocities double **v = atom->v; int nlocal = atom->nlocal; double **vhold; memory->create(vhold,nlocal,3,"velocity:vnew"); for (i = 0; i < nlocal; i++) { vhold[i][0] = v[i][0]; vhold[i][1] = v[i][1]; vhold[i][2] = v[i][2]; } // create new velocities, in uniform or gaussian distribution // loop option determines looping style, ALL is default // ALL = loop over all natoms, only set those I own via atom->map // cannot do this if atom IDs do not span 1-Natoms (some were deleted) // will produce same V, independent of P, if atoms were read-in // will NOT produce same V, independent of P, if used create_atoms // LOCAL = only loop over my atoms, adjust RNG to be proc-specific // will never produce same V, independent of P // GEOM = only loop over my atoms // choose RNG for each atom based on its xyz coord (geometry) // via random->reset() // will always produce same V, independent of P // adjust by factor for atom mass // for 2d, set Vz to 0.0 double *rmass = atom->rmass; double *mass = atom->mass; int *type = atom->type; int *mask = atom->mask; int dimension = domain->dimension; int m; double vx,vy,vz,factor; RanPark *random; if (loop_flag == ALL) { // create an atom map if one doesn't exist already int mapflag = 0; if (atom->map_style == 0) { mapflag = 1; atom->map_style = 1; atom->nghost = 0; atom->map_init(); atom->map_set(); } // error check if (atom->natoms > MAXSMALLINT) error->all(FLERR,"Too big a problem to use velocity create loop all"); if (atom->tag_enable == 0) error->all(FLERR,"Cannot use velocity create loop all unless atoms have IDs"); if (atom->tag_consecutive() == 0) error->all(FLERR,"Atom IDs must be consecutive for velocity create loop all"); // loop over all atoms in system // generate RNGs for all atoms, only assign to ones I own // use either per-type mass or per-atom rmass random = new RanPark(lmp,seed); int natoms = static_cast (atom->natoms); for (i = 1; i <= natoms; i++) { if (dist_flag == 0) { vx = random->uniform(); vy = random->uniform(); vz = random->uniform(); } else { vx = random->gaussian(); vy = random->gaussian(); vz = random->gaussian(); } m = atom->map(i); if (m >= 0 && m < nlocal) { if (mask[m] & groupbit) { if (rmass) factor = 1.0/sqrt(rmass[m]); else factor = 1.0/sqrt(mass[type[m]]); v[m][0] = vx * factor; v[m][1] = vy * factor; if (dimension == 3) v[m][2] = vz * factor; else v[m][2] = 0.0; } } } // delete temporary atom map if (mapflag) { atom->map_delete(); atom->map_style = 0; } } else if (loop_flag == LOCAL) { random = new RanPark(lmp,seed + comm->me); for (i = 0; i < WARMUP; i++) random->uniform(); for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { if (dist_flag == 0) { vx = random->uniform(); vy = random->uniform(); vz = random->uniform(); } else { vx = random->gaussian(); vy = random->gaussian(); vz = random->gaussian(); } if (rmass) factor = 1.0/sqrt(rmass[i]); else factor = 1.0/sqrt(mass[type[i]]); v[i][0] = vx * factor; v[i][1] = vy * factor; if (dimension == 3) v[i][2] = vz * factor; else v[i][2] = 0.0; } } } else if (loop_flag == GEOM) { random = new RanPark(lmp,1); double **x = atom->x; for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { random->reset(seed,x[i]); if (dist_flag == 0) { vx = random->uniform(); vy = random->uniform(); vz = random->uniform(); } else { vx = random->gaussian(); vy = random->gaussian(); vz = random->gaussian(); } if (rmass) factor = 1.0/sqrt(rmass[i]); else factor = 1.0/sqrt(mass[type[i]]); v[i][0] = vx * factor; v[i][1] = vy * factor; if (dimension == 3) v[i][2] = vz * factor; else v[i][2] = 0.0; } } } // apply momentum and rotation zeroing if (momentum_flag) zero_momentum(); if (rotation_flag) zero_rotation(); // scale temp to desired value double t = temperature->compute_scalar(); rescale(t,t_desired); // if sum_flag set, add back in previous velocities if (sum_flag) { for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { v[i][0] += vhold[i][0]; v[i][1] += vhold[i][1]; v[i][2] += vhold[i][2]; } } } // free local memory // if temperature was created, delete it memory->destroy(vhold); delete random; if (tflag) delete temperature; } /* ---------------------------------------------------------------------- */ void Velocity::set(int narg, char **arg) { int xstyle,ystyle,zstyle,varflag; double vx,vy,vz; char *xstr,*ystr,*zstr; int xvar,yvar,zvar; // parse 3 args xstyle = ystyle = zstyle = CONSTANT; xstr = ystr = zstr = NULL; if (strstr(arg[0],"v_") == arg[0]) { int n = strlen(&arg[0][2]) + 1; xstr = new char[n]; strcpy(xstr,&arg[0][2]); } else if (strcmp(arg[0],"NULL") == 0) xstyle = NONE; else vx = atof(arg[0]); if (strstr(arg[1],"v_") == arg[1]) { int n = strlen(&arg[1][2]) + 1; ystr = new char[n]; strcpy(ystr,&arg[1][2]); } else if (strcmp(arg[1],"NULL") == 0) ystyle = NONE; else vy = atof(arg[1]); if (strstr(arg[2],"v_") == arg[2]) { int n = strlen(&arg[2][2]) + 1; zstr = new char[n]; strcpy(zstr,&arg[2][2]); } else if (strcmp(arg[2],"NULL") == 0) zstyle = NONE; else vz = atof(arg[2]); // set and apply scale factors xscale = yscale = zscale = 1.0; if (xstyle && !xstr) { if (scale_flag && domain->lattice == NULL) error->all(FLERR,"Use of velocity with undefined lattice"); if (scale_flag) xscale = domain->lattice->xlattice; vx *= xscale; } if (ystyle && !ystr) { if (scale_flag && domain->lattice == NULL) error->all(FLERR,"Use of velocity with undefined lattice"); if (scale_flag) yscale = domain->lattice->ylattice; vy *= yscale; } if (zstyle && !zstr) { if (scale_flag && domain->lattice == NULL) error->all(FLERR,"Use of velocity with undefined lattice"); if (scale_flag) zscale = domain->lattice->zlattice; vz *= zscale; } // check variables if (xstr) { xvar = input->variable->find(xstr); if (xvar < 0) error->all(FLERR,"Variable name for velocity set does not exist"); if (input->variable->equalstyle(xvar)) xstyle = EQUAL; else if (input->variable->atomstyle(xvar)) xstyle = ATOM; else error->all(FLERR,"Variable for velocity set is invalid style"); } if (ystr) { yvar = input->variable->find(ystr); if (yvar < 0) error->all(FLERR,"Variable name for velocity set does not exist"); if (input->variable->equalstyle(yvar)) ystyle = EQUAL; else if (input->variable->atomstyle(yvar)) ystyle = ATOM; else error->all(FLERR,"Variable for velocity set is invalid style"); } if (zstr) { zvar = input->variable->find(zstr); if (zvar < 0) error->all(FLERR,"Variable name for velocity set does not exist"); if (input->variable->equalstyle(zvar)) zstyle = EQUAL; else if (input->variable->atomstyle(zvar)) zstyle = ATOM; else error->all(FLERR,"Variable for velocity set is invalid style"); } if (xstyle == ATOM || ystyle == ATOM || zstyle == ATOM) varflag = ATOM; else if (xstyle == EQUAL || ystyle == EQUAL || zstyle == EQUAL) varflag = EQUAL; else varflag = CONSTANT; // error check for 2d models if (domain->dimension == 2) { if (zstyle == CONSTANT && vz != 0.0) error->all(FLERR,"Cannot set non-zero z velocity for 2d simulation"); if (zstyle == EQUAL || zstyle == ATOM) error->all(FLERR,"Cannot set variable z velocity for 2d simulation"); } // allocate vfield array if necessary double **vfield = NULL; if (varflag == ATOM) memory->create(vfield,atom->nlocal,3,"velocity:vfield"); // set velocities via constants double **v = atom->v; int *mask = atom->mask; int nlocal = atom->nlocal; if (varflag == CONSTANT) { for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { if (sum_flag == 0) { if (xstyle) v[i][0] = vx; if (ystyle) v[i][1] = vy; if (zstyle) v[i][2] = vz; } else { if (xstyle) v[i][0] += vx; if (ystyle) v[i][1] += vy; if (zstyle) v[i][2] += vz; } } } // set velocities via variables } else { if (xstyle == EQUAL) vx = input->variable->compute_equal(xvar); else if (xstyle == ATOM && vfield) input->variable->compute_atom(xvar,igroup,&vfield[0][0],3,0); if (ystyle == EQUAL) vy = input->variable->compute_equal(yvar); else if (ystyle == ATOM && vfield) input->variable->compute_atom(yvar,igroup,&vfield[0][1],3,0); if (zstyle == EQUAL) vz = input->variable->compute_equal(zvar); else if (zstyle == ATOM && vfield) input->variable->compute_atom(zvar,igroup,&vfield[0][2],3,0); for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { if (sum_flag == 0) { if (xstyle == ATOM) v[i][0] = vfield[i][0]; else if (xstyle) v[i][0] = vx; if (ystyle == ATOM) v[i][1] = vfield[i][1]; else if (ystyle) v[i][1] = vy; if (zstyle == ATOM) v[i][2] = vfield[i][2]; else if (zstyle) v[i][2] = vz; } else { if (xstyle == ATOM) v[i][0] += vfield[i][0]; else if (xstyle) v[i][0] += vx; if (ystyle == ATOM) v[i][1] += vfield[i][1]; else if (ystyle) v[i][1] += vy; if (zstyle == ATOM) v[i][2] += vfield[i][2]; else if (zstyle) v[i][2] += vz; } } } // clean up delete [] xstr; delete [] ystr; delete [] zstr; memory->destroy(vfield); } /* ---------------------------------------------------------------------- rescale velocities of a group after computing its temperature ------------------------------------------------------------------------- */ void Velocity::scale(int narg, char **arg) { double t_desired = atof(arg[0]); // if temperature = NULL, create a new ComputeTemp with the velocity group int tflag = 0; if (temperature == NULL) { char **arg = new char*[3]; arg[0] = (char *) "velocity_temp"; arg[1] = group->names[igroup]; arg[2] = (char *) "temp"; temperature = new ComputeTemp(lmp,3,arg); tflag = 1; delete [] arg; } // initialize temperature computation // warn if groups don't match if (igroup != temperature->igroup && comm->me == 0) error->warning(FLERR,"Mismatch between velocity and compute groups"); temperature->init(); // scale temp to desired value double t = temperature->compute_scalar(); rescale(t,t_desired); // if temperature was created, delete it if (tflag) delete temperature; } /* ---------------------------------------------------------------------- apply a ramped set of velocities ------------------------------------------------------------------------- */ void Velocity::ramp(int narg, char **arg) { // set scale factors if (scale_flag && domain->lattice == NULL) error->all(FLERR,"Use of velocity with undefined lattice"); if (scale_flag) { xscale = domain->lattice->xlattice; yscale = domain->lattice->ylattice; zscale = domain->lattice->zlattice; } else xscale = yscale = zscale = 1.0; // parse args int v_dim; if (strcmp(arg[0],"vx") == 0) v_dim = 0; else if (strcmp(arg[0],"vy") == 0) v_dim = 1; else if (strcmp(arg[0],"vz") == 0) v_dim = 2; else error->all(FLERR,"Illegal velocity command"); if (v_dim == 2 && domain->dimension == 2) error->all(FLERR,"Velocity ramp in z for a 2d problem"); double v_lo,v_hi; if (v_dim == 0) { v_lo = xscale*atof(arg[1]); v_hi = xscale*atof(arg[2]); } else if (v_dim == 1) { v_lo = yscale*atof(arg[1]); v_hi = yscale*atof(arg[2]); } else if (v_dim == 2) { v_lo = zscale*atof(arg[1]); v_hi = zscale*atof(arg[2]); } int coord_dim; if (strcmp(arg[3],"x") == 0) coord_dim = 0; else if (strcmp(arg[3],"y") == 0) coord_dim = 1; else if (strcmp(arg[3],"z") == 0) coord_dim = 2; else error->all(FLERR,"Illegal velocity command"); double coord_lo,coord_hi; if (coord_dim == 0) { coord_lo = xscale*atof(arg[4]); coord_hi = xscale*atof(arg[5]); } else if (coord_dim == 1) { coord_lo = yscale*atof(arg[4]); coord_hi = yscale*atof(arg[5]); } else if (coord_dim == 2) { coord_lo = zscale*atof(arg[4]); coord_hi = zscale*atof(arg[5]); } // vramp = ramped velocity component for v_dim // add or set based on sum_flag double **x = atom->x; double **v = atom->v; int *mask = atom->mask; int nlocal = atom->nlocal; double fraction,vramp; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { fraction = (x[i][coord_dim] - coord_lo) / (coord_hi - coord_lo); fraction = MAX(fraction,0.0); fraction = MIN(fraction,1.0); vramp = v_lo + fraction*(v_hi - v_lo); if (sum_flag) v[i][v_dim] += vramp; else v[i][v_dim] = vramp; } } /* ---------------------------------------------------------------------- zero linear or angular momentum of a group ------------------------------------------------------------------------- */ void Velocity::zero(int narg, char **arg) { if (strcmp(arg[0],"linear") == 0) zero_momentum(); else if (strcmp(arg[0],"angular") == 0) zero_rotation(); else error->all(FLERR,"Illegal velocity command"); } /* ---------------------------------------------------------------------- rescale velocities of group atoms to t_new from t_old ------------------------------------------------------------------------- */ void Velocity::rescale(double t_old, double t_new) { if (t_old == 0.0) error->all(FLERR,"Attempting to rescale a 0.0 temperature"); double factor = sqrt(t_new/t_old); double **v = atom->v; int *mask = atom->mask; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { v[i][0] *= factor; v[i][1] *= factor; v[i][2] *= factor; } } /* ---------------------------------------------------------------------- zero the linear momentum of a group of atoms by adjusting v by -Vcm ------------------------------------------------------------------------- */ void Velocity::zero_momentum() { // cannot have 0 atoms in group if (group->count(igroup) == 0) error->all(FLERR,"Cannot zero momentum of 0 atoms"); // compute velocity of center-of-mass of group double masstotal = group->mass(igroup); double vcm[3]; group->vcm(igroup,masstotal,vcm); // adjust velocities by vcm to zero linear momentum double **v = atom->v; int *mask = atom->mask; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { v[i][0] -= vcm[0]; v[i][1] -= vcm[1]; v[i][2] -= vcm[2]; } } /* ---------------------------------------------------------------------- zero the angular momentum of a group of atoms by adjusting v by -(w x r) ------------------------------------------------------------------------- */ void Velocity::zero_rotation() { int i; // cannot have 0 atoms in group if (group->count(igroup) == 0) error->all(FLERR,"Cannot zero momentum of 0 atoms"); // compute omega (angular velocity) of group around center-of-mass double xcm[3],angmom[3],inertia[3][3],omega[3]; double masstotal = group->mass(igroup); group->xcm(igroup,masstotal,xcm); group->angmom(igroup,xcm,angmom); group->inertia(igroup,xcm,inertia); group->omega(angmom,inertia,omega); // adjust velocities to zero omega // vnew_i = v_i - w x r_i // must use unwrapped coords to compute r_i correctly double **x = atom->x; double **v = atom->v; int *mask = atom->mask; int *image = atom->image; int nlocal = atom->nlocal; int xbox,ybox,zbox; double dx,dy,dz; double xprd = domain->xprd; double yprd = domain->yprd; double zprd = domain->zprd; for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) { xbox = (image[i] & 1023) - 512; ybox = (image[i] >> 10 & 1023) - 512; zbox = (image[i] >> 20) - 512; dx = (x[i][0] + xbox*xprd) - xcm[0]; dy = (x[i][1] + ybox*yprd) - xcm[1]; dz = (x[i][2] + zbox*zprd) - xcm[2]; v[i][0] -= omega[1]*dz - omega[2]*dy; v[i][1] -= omega[2]*dx - omega[0]*dz; v[i][2] -= omega[0]*dy - omega[1]*dx; } } /* ---------------------------------------------------------------------- parse optional parameters at end of velocity input line ------------------------------------------------------------------------- */ void Velocity::options(int narg, char **arg) { if (narg < 0) error->all(FLERR,"Illegal velocity command"); int iarg = 0; while (iarg < narg) { if (strcmp(arg[iarg],"dist") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal velocity command"); if (strcmp(arg[iarg+1],"uniform") == 0) dist_flag = 0; else if (strcmp(arg[iarg+1],"gaussian") == 0) dist_flag = 1; else error->all(FLERR,"Illegal velocity command"); iarg += 2; } else if (strcmp(arg[iarg],"sum") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal velocity command"); if (strcmp(arg[iarg+1],"no") == 0) sum_flag = 0; else if (strcmp(arg[iarg+1],"yes") == 0) sum_flag = 1; else error->all(FLERR,"Illegal velocity command"); iarg += 2; } else if (strcmp(arg[iarg],"mom") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal velocity command"); if (strcmp(arg[iarg+1],"no") == 0) momentum_flag = 0; else if (strcmp(arg[iarg+1],"yes") == 0) momentum_flag = 1; else error->all(FLERR,"Illegal velocity command"); iarg += 2; } else if (strcmp(arg[iarg],"rot") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal velocity command"); if (strcmp(arg[iarg+1],"no") == 0) rotation_flag = 0; else if (strcmp(arg[iarg+1],"yes") == 0) rotation_flag = 1; else error->all(FLERR,"Illegal velocity command"); iarg += 2; } else if (strcmp(arg[iarg],"temp") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal velocity command"); int icompute; for (icompute = 0; icompute < modify->ncompute; icompute++) if (strcmp(arg[iarg+1],modify->compute[icompute]->id) == 0) break; if (icompute == modify->ncompute) error->all(FLERR,"Could not find velocity temperature ID"); temperature = modify->compute[icompute]; if (temperature->tempflag == 0) error->all(FLERR,"Velocity temperature ID does not compute temperature"); iarg += 2; } else if (strcmp(arg[iarg],"loop") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal velocity command"); if (strcmp(arg[iarg+1],"all") == 0) loop_flag = ALL; else if (strcmp(arg[iarg+1],"local") == 0) loop_flag = LOCAL; else if (strcmp(arg[iarg+1],"geom") == 0) loop_flag = GEOM; else error->all(FLERR,"Illegal velocity command"); iarg += 2; } else if (strcmp(arg[iarg],"units") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal velocity command"); if (strcmp(arg[iarg+1],"box") == 0) scale_flag = 0; else if (strcmp(arg[iarg+1],"lattice") == 0) scale_flag = 1; else error->all(FLERR,"Illegal velocity command"); iarg += 2; } else error->all(FLERR,"Illegal velocity command"); } } diff --git a/src/velocity.h b/src/velocity.h index 251c366ce..c64043394 100644 --- a/src/velocity.h +++ b/src/velocity.h @@ -1,140 +1,140 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ #ifdef COMMAND_CLASS CommandStyle(velocity,Velocity) #else #ifndef LMP_VELOCITY_H #define LMP_VELOCITY_H #include "pointers.h" namespace LAMMPS_NS { class Velocity : protected Pointers { public: Velocity(class LAMMPS *); void command(int, char **); - void init_external(char *); + void init_external(const char *); void options(int, char **); void create(double, int); private: int igroup,groupbit; int style; int dist_flag,sum_flag,momentum_flag,rotation_flag,loop_flag,scale_flag; double xscale,yscale,zscale; class Compute *temperature; void set(int, char **); void scale(int, char **); void ramp(int, char **); void zero(int, char **); void rescale(double, double); void zero_momentum(); void zero_rotation(); }; } #endif #endif /* ERROR/WARNING messages: E: Illegal ... command Self-explanatory. Check the input script syntax and compare to the documentation for the command. You can use -echo screen as a command-line option when running LAMMPS to see the offending line. E: Velocity command before simulation box is defined The velocity command cannot be used before a read_data, read_restart, or create_box command. E: Velocity command with no atoms existing A velocity command has been used, but no atoms yet exist. E: Could not find velocity group ID A group ID used in the velocity command does not exist. W: Mismatch between velocity and compute groups The temperature computation used by the velocity command will not be on the same group of atoms that velocities are being set for. E: Too big a problem to use velocity create loop all The system size must fit in a 32-bit integer to use this option. E: Cannot use velocity create loop all unless atoms have IDs Atoms in the simulation to do not have IDs, so this style of velocity creation cannot be performed. E: Atom IDs must be consecutive for velocity create loop all Self-explanatory. E: Use of velocity with undefined lattice If scale = lattice (the default) for the velocity set or velocity ramp command, then a lattice must first be defined via the lattice command. E: Variable name for velocity set does not exist Self-explanatory. E: Variable for velocity set is invalid style Only atom-style variables can be used. E: Cannot set non-zero z velocity for 2d simulation Self-explanatory. E: Cannot set variable z velocity for 2d simulation Self-explanatory. E: Velocity ramp in z for a 2d problem Self-explanatory. E: Attempting to rescale a 0.0 temperature Cannot rescale a temperature that is already 0.0. E: Cannot zero momentum of 0 atoms The collection of atoms for which momentum is being computed has no atoms. E: Could not find velocity temperature ID The compute ID needed by the velocity command to compute temperature does not exist. E: Velocity temperature ID does not compute temperature The compute ID given to the velocity command must compute temperature. */