diff --git a/src/ASPHERE/pair_gayberne.cpp b/src/ASPHERE/pair_gayberne.cpp index 4aae7177d..bdff7a5cd 100644 --- a/src/ASPHERE/pair_gayberne.cpp +++ b/src/ASPHERE/pair_gayberne.cpp @@ -1,953 +1,953 @@ /* ---------------------------------------------------------------------- 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 #include #include #include #include "pair_gayberne.h" #include "math_extra.h" #include "atom.h" #include "atom_vec_ellipsoid.h" #include "comm.h" #include "force.h" #include "neighbor.h" #include "neigh_list.h" #include "integrate.h" #include "citeme.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; static const char cite_pair_gayberne[] = "pair gayberne command:\n\n" "@Article{Brown09,\n" " author = {W. M. Brown, M. K. Petersen, S. J. Plimpton, and G. S. Grest},\n" " title = {Liquid crystal nanodroplets in solution},\n" " journal = {J.~Chem.~Phys.},\n" " year = 2009,\n" " volume = 130,\n" " pages = {044901}\n" "}\n\n"; /* ---------------------------------------------------------------------- */ PairGayBerne::PairGayBerne(LAMMPS *lmp) : Pair(lmp) { if (lmp->citeme) lmp->citeme->add(cite_pair_gayberne); single_enable = 0; writedata = 1; } /* ---------------------------------------------------------------------- free all arrays ------------------------------------------------------------------------- */ PairGayBerne::~PairGayBerne() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(form); memory->destroy(epsilon); memory->destroy(sigma); memory->destroy(shape1); memory->destroy(shape2); memory->destroy(well); memory->destroy(cut); memory->destroy(lj1); memory->destroy(lj2); memory->destroy(lj3); memory->destroy(lj4); memory->destroy(offset); delete [] lshape; delete [] setwell; } } /* ---------------------------------------------------------------------- */ void PairGayBerne::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double evdwl,one_eng,rsq,r2inv,r6inv,forcelj,factor_lj; double fforce[3],ttor[3],rtor[3],r12[3]; double a1[3][3],b1[3][3],g1[3][3],a2[3][3],b2[3][3],g2[3][3],temp[3][3]; int *ilist,*jlist,*numneigh,**firstneigh; double *iquat,*jquat; evdwl = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; AtomVecEllipsoid::Bonus *bonus = avec->bonus; int *ellipsoid = atom->ellipsoid; double **x = atom->x; double **f = atom->f; double **tor = atom->torque; 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]; itype = type[i]; if (form[itype][itype] == ELLIPSE_ELLIPSE) { iquat = bonus[ellipsoid[i]].quat; MathExtra::quat_to_mat_trans(iquat,a1); MathExtra::diag_times3(well[itype],a1,temp); MathExtra::transpose_times3(a1,temp,b1); MathExtra::diag_times3(shape2[itype],a1,temp); MathExtra::transpose_times3(a1,temp,g1); } jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; factor_lj = special_lj[sbmask(j)]; j &= NEIGHMASK; // r12 = center to center vector r12[0] = x[j][0]-x[i][0]; r12[1] = x[j][1]-x[i][1]; r12[2] = x[j][2]-x[i][2]; rsq = MathExtra::dot3(r12,r12); jtype = type[j]; // compute if less than cutoff if (rsq < cutsq[itype][jtype]) { switch (form[itype][jtype]) { case SPHERE_SPHERE: r2inv = 1.0/rsq; r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); forcelj *= -r2inv; if (eflag) one_eng = r6inv*(r6inv*lj3[itype][jtype]-lj4[itype][jtype]) - offset[itype][jtype]; fforce[0] = r12[0]*forcelj; fforce[1] = r12[1]*forcelj; fforce[2] = r12[2]*forcelj; ttor[0] = ttor[1] = ttor[2] = 0.0; rtor[0] = rtor[1] = rtor[2] = 0.0; break; case SPHERE_ELLIPSE: jquat = bonus[ellipsoid[j]].quat; MathExtra::quat_to_mat_trans(jquat,a2); MathExtra::diag_times3(well[jtype],a2,temp); MathExtra::transpose_times3(a2,temp,b2); MathExtra::diag_times3(shape2[jtype],a2,temp); MathExtra::transpose_times3(a2,temp,g2); one_eng = gayberne_lj(j,i,a2,b2,g2,r12,rsq,fforce,rtor); ttor[0] = ttor[1] = ttor[2] = 0.0; break; case ELLIPSE_SPHERE: one_eng = gayberne_lj(i,j,a1,b1,g1,r12,rsq,fforce,ttor); rtor[0] = rtor[1] = rtor[2] = 0.0; break; default: jquat = bonus[ellipsoid[j]].quat; MathExtra::quat_to_mat_trans(jquat,a2); MathExtra::diag_times3(well[jtype],a2,temp); MathExtra::transpose_times3(a2,temp,b2); MathExtra::diag_times3(shape2[jtype],a2,temp); MathExtra::transpose_times3(a2,temp,g2); one_eng = gayberne_analytic(i,j,a1,a2,b1,b2,g1,g2,r12,rsq, fforce,ttor,rtor); break; } fforce[0] *= factor_lj; fforce[1] *= factor_lj; fforce[2] *= factor_lj; ttor[0] *= factor_lj; ttor[1] *= factor_lj; ttor[2] *= factor_lj; f[i][0] += fforce[0]; f[i][1] += fforce[1]; f[i][2] += fforce[2]; tor[i][0] += ttor[0]; tor[i][1] += ttor[1]; tor[i][2] += ttor[2]; if (newton_pair || j < nlocal) { rtor[0] *= factor_lj; rtor[1] *= factor_lj; rtor[2] *= factor_lj; f[j][0] -= fforce[0]; f[j][1] -= fforce[1]; f[j][2] -= fforce[2]; tor[j][0] += rtor[0]; tor[j][1] += rtor[1]; tor[j][2] += rtor[2]; } if (eflag) evdwl = factor_lj*one_eng; if (evflag) ev_tally_xyz(i,j,nlocal,newton_pair, evdwl,0.0,fforce[0],fforce[1],fforce[2], -r12[0],-r12[1],-r12[2]); } } } if (vflag_fdotr) virial_fdotr_compute(); } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairGayBerne::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(form,n+1,n+1,"pair:form"); memory->create(epsilon,n+1,n+1,"pair:epsilon"); memory->create(sigma,n+1,n+1,"pair:sigma"); memory->create(shape1,n+1,3,"pair:shape1"); memory->create(shape2,n+1,3,"pair:shape2"); memory->create(well,n+1,3,"pair:well"); memory->create(cut,n+1,n+1,"pair:cut"); 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"); lshape = new double[n+1]; setwell = new int[n+1]; for (int i = 1; i <= n; i++) setwell[i] = 0; } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairGayBerne::settings(int narg, char **arg) { if (narg != 4) error->all(FLERR,"Illegal pair_style command"); gamma = force->numeric(FLERR,arg[0]); upsilon = force->numeric(FLERR,arg[1])/2.0; mu = force->numeric(FLERR,arg[2]); cut_global = force->numeric(FLERR,arg[3]); // 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 PairGayBerne::coeff(int narg, char **arg) { if (narg < 10 || narg > 11) 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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(FLERR,arg[2]); double sigma_one = force->numeric(FLERR,arg[3]); double eia_one = force->numeric(FLERR,arg[4]); double eib_one = force->numeric(FLERR,arg[5]); double eic_one = force->numeric(FLERR,arg[6]); double eja_one = force->numeric(FLERR,arg[7]); double ejb_one = force->numeric(FLERR,arg[8]); double ejc_one = force->numeric(FLERR,arg[9]); double cut_one = cut_global; if (narg == 11) cut_one = force->numeric(FLERR,arg[10]); 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; if (eia_one != 0.0 || eib_one != 0.0 || eic_one != 0.0) { well[i][0] = pow(eia_one,-1.0/mu); well[i][1] = pow(eib_one,-1.0/mu); well[i][2] = pow(eic_one,-1.0/mu); if (eia_one == eib_one && eib_one == eic_one) setwell[i] = 2; else setwell[i] = 1; } if (eja_one != 0.0 || ejb_one != 0.0 || ejc_one != 0.0) { well[j][0] = pow(eja_one,-1.0/mu); well[j][1] = pow(ejb_one,-1.0/mu); well[j][2] = pow(ejc_one,-1.0/mu); if (eja_one == ejb_one && ejb_one == ejc_one) setwell[j] = 2; else setwell[j] = 1; } setflag[i][j] = 1; count++; } } if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairGayBerne::init_style() { avec = (AtomVecEllipsoid *) atom->style_match("ellipsoid"); if (!avec) error->all(FLERR,"Pair gayberne requires atom style ellipsoid"); neighbor->request(this,instance_me); // per-type shape precalculations // require that atom shapes are identical within each type // if shape = 0 for point particle, set shape = 1 as required by Gay-Berne for (int i = 1; i <= atom->ntypes; i++) { if (!atom->shape_consistency(i,shape1[i][0],shape1[i][1],shape1[i][2])) error->all(FLERR, "Pair gayberne requires atoms with same type have same shape"); if (shape1[i][0] == 0.0) shape1[i][0] = shape1[i][1] = shape1[i][2] = 1.0; shape2[i][0] = shape1[i][0]*shape1[i][0]; shape2[i][1] = shape1[i][1]*shape1[i][1]; shape2[i][2] = shape1[i][2]*shape1[i][2]; lshape[i] = (shape1[i][0]*shape1[i][1]+shape1[i][2]*shape1[i][2]) * sqrt(shape1[i][0]*shape1[i][1]); } } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairGayBerne::init_one(int i, int j) { if (setwell[i] == 0 || setwell[j] == 0) error->all(FLERR,"Pair gayberne epsilon a,b,c coeffs are not all set"); 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; int ishape = 0; if (shape1[i][0] != shape1[i][1] || shape1[i][0] != shape1[i][2] || shape1[i][1] != shape1[i][2]) ishape = 1; if (setwell[i] == 1) ishape = 1; int jshape = 0; if (shape1[j][0] != shape1[j][1] || shape1[j][0] != shape1[j][2] || shape1[j][1] != shape1[j][2]) jshape = 1; if (setwell[j] == 1) jshape = 1; if (ishape == 0 && jshape == 0) form[i][i] = form[j][j] = form[i][j] = form[j][i] = SPHERE_SPHERE; else if (ishape == 0) { form[i][i] = SPHERE_SPHERE; form[j][j] = ELLIPSE_ELLIPSE; form[i][j] = SPHERE_ELLIPSE; form[j][i] = ELLIPSE_SPHERE; } else if (jshape == 0) { form[j][j] = SPHERE_SPHERE; form[i][i] = ELLIPSE_ELLIPSE; form[j][i] = SPHERE_ELLIPSE; form[i][j] = ELLIPSE_SPHERE; } else form[i][i] = form[j][j] = form[i][j] = form[j][i] = ELLIPSE_ELLIPSE; epsilon[j][i] = epsilon[i][j]; sigma[j][i] = sigma[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]; return cut[i][j]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairGayBerne::write_restart(FILE *fp) { write_restart_settings(fp); int i,j; for (i = 1; i <= atom->ntypes; i++) { fwrite(&setwell[i],sizeof(int),1,fp); if (setwell[i]) fwrite(&well[i][0],sizeof(double),3,fp); 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 PairGayBerne::read_restart(FILE *fp) { read_restart_settings(fp); allocate(); int i,j; int me = comm->me; for (i = 1; i <= atom->ntypes; i++) { if (me == 0) fread(&setwell[i],sizeof(int),1,fp); MPI_Bcast(&setwell[i],1,MPI_INT,0,world); if (setwell[i]) { if (me == 0) fread(&well[i][0],sizeof(double),3,fp); MPI_Bcast(&well[i][0],3,MPI_DOUBLE,0,world); } 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 PairGayBerne::write_restart_settings(FILE *fp) { fwrite(&gamma,sizeof(double),1,fp); fwrite(&upsilon,sizeof(double),1,fp); fwrite(&mu,sizeof(double),1,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 PairGayBerne::read_restart_settings(FILE *fp) { int me = comm->me; if (me == 0) { fread(&gamma,sizeof(double),1,fp); fread(&upsilon,sizeof(double),1,fp); fread(&mu,sizeof(double),1,fp); fread(&cut_global,sizeof(double),1,fp); fread(&offset_flag,sizeof(int),1,fp); fread(&mix_flag,sizeof(int),1,fp); } MPI_Bcast(&gamma,1,MPI_DOUBLE,0,world); MPI_Bcast(&upsilon,1,MPI_DOUBLE,0,world); MPI_Bcast(&mu,1,MPI_DOUBLE,0,world); 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); } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void PairGayBerne::write_data(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) fprintf(fp,"%d %g %g %g %g %g %g %g %g\n",i, epsilon[i][i],sigma[i][i], pow(well[i][0],-mu),pow(well[i][1],-mu),pow(well[i][2],-mu), pow(well[i][0],-mu),pow(well[i][1],-mu),pow(well[i][2],-mu)); } /* ---------------------------------------------------------------------- proc 0 writes all pairs to data file ------------------------------------------------------------------------- */ void PairGayBerne::write_data_all(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) fprintf(fp,"%d %d %g %g %g %g %g %g %g %g %g\n",i,j, epsilon[i][i],sigma[i][i], pow(well[i][0],-mu),pow(well[i][1],-mu),pow(well[i][2],-mu), pow(well[j][0],-mu),pow(well[j][1],-mu),pow(well[j][2],-mu), cut[i][j]); } /* ---------------------------------------------------------------------- compute analytic energy, force (fforce), and torque (ttor & rtor) based on rotation matrices a and precomputed matrices b and g if newton is off, rtor is not calculated for ghost atoms ------------------------------------------------------------------------- */ double PairGayBerne::gayberne_analytic(const int i,const int j,double a1[3][3], double a2[3][3], double b1[3][3], double b2[3][3], double g1[3][3], double g2[3][3], double *r12, const double rsq, double *fforce, double *ttor, double *rtor) { double tempv[3], tempv2[3]; double temp[3][3]; double temp1,temp2,temp3; int *type = atom->type; int newton_pair = force->newton_pair; int nlocal = atom->nlocal; double r12hat[3]; MathExtra::normalize3(r12,r12hat); double r = sqrt(rsq); // compute distance of closest approach double g12[3][3]; MathExtra::plus3(g1,g2,g12); double kappa[3]; int ierror = MathExtra::mldivide3(g12,r12,kappa); if (ierror) error->all(FLERR,"Bad matrix inversion in mldivide3"); // tempv = G12^-1*r12hat tempv[0] = kappa[0]/r; tempv[1] = kappa[1]/r; tempv[2] = kappa[2]/r; double sigma12 = MathExtra::dot3(r12hat,tempv); sigma12 = pow(0.5*sigma12,-0.5); double h12 = r-sigma12; // energy // compute u_r double varrho = sigma[type[i]][type[j]]/(h12+gamma*sigma[type[i]][type[j]]); double varrho6 = pow(varrho,6.0); double varrho12 = varrho6*varrho6; double u_r = 4.0*epsilon[type[i]][type[j]]*(varrho12-varrho6); // compute eta_12 double eta = 2.0*lshape[type[i]]*lshape[type[j]]; double det_g12 = MathExtra::det3(g12); eta = pow(eta/det_g12,upsilon); // compute chi_12 double b12[3][3]; double iota[3]; MathExtra::plus3(b1,b2,b12); ierror = MathExtra::mldivide3(b12,r12,iota); if (ierror) error->all(FLERR,"Bad matrix inversion in mldivide3"); // tempv = G12^-1*r12hat tempv[0] = iota[0]/r; tempv[1] = iota[1]/r; tempv[2] = iota[2]/r; double chi = MathExtra::dot3(r12hat,tempv); chi = pow(chi*2.0,mu); // force // compute dUr/dr temp1 = (2.0*varrho12*varrho-varrho6*varrho)/sigma[type[i]][type[j]]; temp1 = temp1*24.0*epsilon[type[i]][type[j]]; double u_slj = temp1*pow(sigma12,3.0)/2.0; double dUr[3]; temp2 = MathExtra::dot3(kappa,r12hat); double uslj_rsq = u_slj/rsq; dUr[0] = temp1*r12hat[0]+uslj_rsq*(kappa[0]-temp2*r12hat[0]); dUr[1] = temp1*r12hat[1]+uslj_rsq*(kappa[1]-temp2*r12hat[1]); dUr[2] = temp1*r12hat[2]+uslj_rsq*(kappa[2]-temp2*r12hat[2]); // compute dChi_12/dr double dchi[3]; temp1 = MathExtra::dot3(iota,r12hat); temp2 = -4.0/rsq*mu*pow(chi,(mu-1.0)/mu); dchi[0] = temp2*(iota[0]-temp1*r12hat[0]); dchi[1] = temp2*(iota[1]-temp1*r12hat[1]); dchi[2] = temp2*(iota[2]-temp1*r12hat[2]); temp1 = -eta*u_r; temp2 = eta*chi; fforce[0] = temp1*dchi[0]-temp2*dUr[0]; fforce[1] = temp1*dchi[1]-temp2*dUr[1]; fforce[2] = temp1*dchi[2]-temp2*dUr[2]; // torque for particle 1 and 2 // compute dUr tempv[0] = -uslj_rsq*kappa[0]; tempv[1] = -uslj_rsq*kappa[1]; tempv[2] = -uslj_rsq*kappa[2]; MathExtra::vecmat(kappa,g1,tempv2); MathExtra::cross3(tempv,tempv2,dUr); double dUr2[3]; if (newton_pair || j < nlocal) { MathExtra::vecmat(kappa,g2,tempv2); MathExtra::cross3(tempv,tempv2,dUr2); } // compute d_chi MathExtra::vecmat(iota,b1,tempv); MathExtra::cross3(tempv,iota,dchi); temp1 = -4.0/rsq; dchi[0] *= temp1; dchi[1] *= temp1; dchi[2] *= temp1; double dchi2[3]; if (newton_pair || j < nlocal) { MathExtra::vecmat(iota,b2,tempv); MathExtra::cross3(tempv,iota,dchi2); dchi2[0] *= temp1; dchi2[1] *= temp1; dchi2[2] *= temp1; } // compute d_eta double deta[3]; deta[0] = deta[1] = deta[2] = 0.0; compute_eta_torque(g12,a1,shape2[type[i]],temp); temp1 = -eta*upsilon; for (int m = 0; m < 3; m++) { for (int y = 0; y < 3; y++) tempv[y] = temp1*temp[m][y]; MathExtra::cross3(a1[m],tempv,tempv2); deta[0] += tempv2[0]; deta[1] += tempv2[1]; deta[2] += tempv2[2]; } // compute d_eta for particle 2 double deta2[3]; if (newton_pair || j < nlocal) { deta2[0] = deta2[1] = deta2[2] = 0.0; compute_eta_torque(g12,a2,shape2[type[j]],temp); for (int m = 0; m < 3; m++) { for (int y = 0; y < 3; y++) tempv[y] = temp1*temp[m][y]; MathExtra::cross3(a2[m],tempv,tempv2); deta2[0] += tempv2[0]; deta2[1] += tempv2[1]; deta2[2] += tempv2[2]; } } // torque temp1 = u_r*eta; temp2 = u_r*chi; temp3 = chi*eta; ttor[0] = (temp1*dchi[0]+temp2*deta[0]+temp3*dUr[0]) * -1.0; ttor[1] = (temp1*dchi[1]+temp2*deta[1]+temp3*dUr[1]) * -1.0; ttor[2] = (temp1*dchi[2]+temp2*deta[2]+temp3*dUr[2]) * -1.0; if (newton_pair || j < nlocal) { rtor[0] = (temp1*dchi2[0]+temp2*deta2[0]+temp3*dUr2[0]) * -1.0; rtor[1] = (temp1*dchi2[1]+temp2*deta2[1]+temp3*dUr2[1]) * -1.0; rtor[2] = (temp1*dchi2[2]+temp2*deta2[2]+temp3*dUr2[2]) * -1.0; } return temp1*chi; } /* ---------------------------------------------------------------------- compute analytic energy, force (fforce), and torque (ttor) between ellipsoid and lj particle ------------------------------------------------------------------------- */ double PairGayBerne::gayberne_lj(const int i,const int j,double a1[3][3], double b1[3][3],double g1[3][3], double *r12,const double rsq,double *fforce, double *ttor) { double tempv[3], tempv2[3]; double temp[3][3]; double temp1,temp2,temp3; int *type = atom->type; double r12hat[3]; MathExtra::normalize3(r12,r12hat); double r = sqrt(rsq); // compute distance of closest approach double g12[3][3]; g12[0][0] = g1[0][0]+shape2[type[j]][0]; g12[1][1] = g1[1][1]+shape2[type[j]][0]; g12[2][2] = g1[2][2]+shape2[type[j]][0]; g12[0][1] = g1[0][1]; g12[1][0] = g1[1][0]; g12[0][2] = g1[0][2]; g12[2][0] = g1[2][0]; g12[1][2] = g1[1][2]; g12[2][1] = g1[2][1]; double kappa[3]; int ierror = MathExtra::mldivide3(g12,r12,kappa); if (ierror) error->all(FLERR,"Bad matrix inversion in mldivide3"); // tempv = G12^-1*r12hat tempv[0] = kappa[0]/r; tempv[1] = kappa[1]/r; tempv[2] = kappa[2]/r; double sigma12 = MathExtra::dot3(r12hat,tempv); sigma12 = pow(0.5*sigma12,-0.5); double h12 = r-sigma12; // energy // compute u_r double varrho = sigma[type[i]][type[j]]/(h12+gamma*sigma[type[i]][type[j]]); double varrho6 = pow(varrho,6.0); double varrho12 = varrho6*varrho6; double u_r = 4.0*epsilon[type[i]][type[j]]*(varrho12-varrho6); // compute eta_12 double eta = 2.0*lshape[type[i]]*lshape[type[j]]; double det_g12 = MathExtra::det3(g12); eta = pow(eta/det_g12,upsilon); // compute chi_12 double b12[3][3]; double iota[3]; b12[0][0] = b1[0][0] + well[type[j]][0]; b12[1][1] = b1[1][1] + well[type[j]][0]; b12[2][2] = b1[2][2] + well[type[j]][0]; b12[0][1] = b1[0][1]; b12[1][0] = b1[1][0]; b12[0][2] = b1[0][2]; b12[2][0] = b1[2][0]; b12[1][2] = b1[1][2]; b12[2][1] = b1[2][1]; ierror = MathExtra::mldivide3(b12,r12,iota); if (ierror) error->all(FLERR,"Bad matrix inversion in mldivide3"); // tempv = G12^-1*r12hat tempv[0] = iota[0]/r; tempv[1] = iota[1]/r; tempv[2] = iota[2]/r; double chi = MathExtra::dot3(r12hat,tempv); chi = pow(chi*2.0,mu); // force // compute dUr/dr temp1 = (2.0*varrho12*varrho-varrho6*varrho)/sigma[type[i]][type[j]]; temp1 = temp1*24.0*epsilon[type[i]][type[j]]; double u_slj = temp1*pow(sigma12,3.0)/2.0; double dUr[3]; temp2 = MathExtra::dot3(kappa,r12hat); double uslj_rsq = u_slj/rsq; dUr[0] = temp1*r12hat[0]+uslj_rsq*(kappa[0]-temp2*r12hat[0]); dUr[1] = temp1*r12hat[1]+uslj_rsq*(kappa[1]-temp2*r12hat[1]); dUr[2] = temp1*r12hat[2]+uslj_rsq*(kappa[2]-temp2*r12hat[2]); // compute dChi_12/dr double dchi[3]; temp1 = MathExtra::dot3(iota,r12hat); temp2 = -4.0/rsq*mu*pow(chi,(mu-1.0)/mu); dchi[0] = temp2*(iota[0]-temp1*r12hat[0]); dchi[1] = temp2*(iota[1]-temp1*r12hat[1]); dchi[2] = temp2*(iota[2]-temp1*r12hat[2]); temp1 = -eta*u_r; temp2 = eta*chi; fforce[0] = temp1*dchi[0]-temp2*dUr[0]; fforce[1] = temp1*dchi[1]-temp2*dUr[1]; fforce[2] = temp1*dchi[2]-temp2*dUr[2]; // torque for particle 1 and 2 // compute dUr tempv[0] = -uslj_rsq*kappa[0]; tempv[1] = -uslj_rsq*kappa[1]; tempv[2] = -uslj_rsq*kappa[2]; MathExtra::vecmat(kappa,g1,tempv2); MathExtra::cross3(tempv,tempv2,dUr); // compute d_chi MathExtra::vecmat(iota,b1,tempv); MathExtra::cross3(tempv,iota,dchi); temp1 = -4.0/rsq; dchi[0] *= temp1; dchi[1] *= temp1; dchi[2] *= temp1; // compute d_eta double deta[3]; deta[0] = deta[1] = deta[2] = 0.0; compute_eta_torque(g12,a1,shape2[type[i]],temp); temp1 = -eta*upsilon; for (int m = 0; m < 3; m++) { for (int y = 0; y < 3; y++) tempv[y] = temp1*temp[m][y]; MathExtra::cross3(a1[m],tempv,tempv2); deta[0] += tempv2[0]; deta[1] += tempv2[1]; deta[2] += tempv2[2]; } // torque temp1 = u_r*eta; temp2 = u_r*chi; temp3 = chi*eta; ttor[0] = (temp1*dchi[0]+temp2*deta[0]+temp3*dUr[0]) * -1.0; ttor[1] = (temp1*dchi[1]+temp2*deta[1]+temp3*dUr[1]) * -1.0; ttor[2] = (temp1*dchi[2]+temp2*deta[2]+temp3*dUr[2]) * -1.0; return temp1*chi; } /* ---------------------------------------------------------------------- torque contribution from eta computes trace in the last doc equation for the torque derivative code comes from symbolic solver dump m is g12, m2 is a_i, s is the shape for the particle ------------------------------------------------------------------------- */ void PairGayBerne::compute_eta_torque(double m[3][3], double m2[3][3], double *s, double ans[3][3]) { double den = m[1][0]*m[0][2]*m[2][1]-m[0][0]*m[1][2]*m[2][1]- m[0][2]*m[2][0]*m[1][1]+m[0][1]*m[2][0]*m[1][2]- m[1][0]*m[0][1]*m[2][2]+m[0][0]*m[1][1]*m[2][2]; ans[0][0] = s[0]*(m[1][2]*m[0][1]*m2[0][2]+2.0*m[1][1]*m[2][2]*m2[0][0]- m[1][1]*m2[0][2]*m[0][2]-2.0*m[1][2]*m2[0][0]*m[2][1]+ m2[0][1]*m[0][2]*m[2][1]-m2[0][1]*m[0][1]*m[2][2]- m[1][0]*m[2][2]*m2[0][1]+m[2][0]*m[1][2]*m2[0][1]+ m[1][0]*m2[0][2]*m[2][1]-m2[0][2]*m[2][0]*m[1][1])/den; ans[0][1] = s[0]*(m[0][2]*m2[0][0]*m[2][1]-m[2][2]*m2[0][0]*m[0][1]+ 2.0*m[0][0]*m[2][2]*m2[0][1]-m[0][0]*m2[0][2]*m[1][2]- 2.0*m[2][0]*m[0][2]*m2[0][1]+m2[0][2]*m[1][0]*m[0][2]- m[2][2]*m[1][0]*m2[0][0]+m[2][0]*m2[0][0]*m[1][2]+ m[2][0]*m2[0][2]*m[0][1]-m2[0][2]*m[0][0]*m[2][1])/den; ans[0][2] = s[0]*(m[0][1]*m[1][2]*m2[0][0]-m[0][2]*m2[0][0]*m[1][1]- m[0][0]*m[1][2]*m2[0][1]+m[1][0]*m[0][2]*m2[0][1]- m2[0][1]*m[0][0]*m[2][1]-m[2][0]*m[1][1]*m2[0][0]+ 2.0*m[1][1]*m[0][0]*m2[0][2]-2.0*m[1][0]*m2[0][2]*m[0][1]+ m[1][0]*m[2][1]*m2[0][0]+m[2][0]*m2[0][1]*m[0][1])/den; ans[1][0] = s[1]*(-m[1][1]*m2[1][2]*m[0][2]+2.0*m[1][1]*m[2][2]*m2[1][0]+ m[1][2]*m[0][1]*m2[1][2]-2.0*m[1][2]*m2[1][0]*m[2][1]+ m2[1][1]*m[0][2]*m[2][1]-m2[1][1]*m[0][1]*m[2][2]- m[1][0]*m[2][2]*m2[1][1]+m[2][0]*m[1][2]*m2[1][1]- m2[1][2]*m[2][0]*m[1][1]+m[1][0]*m2[1][2]*m[2][1])/den; ans[1][1] = s[1]*(m[0][2]*m2[1][0]*m[2][1]-m[0][1]*m[2][2]*m2[1][0]+ 2.0*m[2][2]*m[0][0]*m2[1][1]-m2[1][2]*m[0][0]*m[1][2]- 2.0*m[2][0]*m2[1][1]*m[0][2]-m[1][0]*m[2][2]*m2[1][0]+ m[2][0]*m[1][2]*m2[1][0]+m[1][0]*m2[1][2]*m[0][2]- m[0][0]*m2[1][2]*m[2][1]+m2[1][2]*m[0][1]*m[2][0])/den; ans[1][2] = s[1]*(m[0][1]*m[1][2]*m2[1][0]-m[0][2]*m2[1][0]*m[1][1]- m[0][0]*m[1][2]*m2[1][1]+m[1][0]*m[0][2]*m2[1][1]+ 2.0*m[1][1]*m[0][0]*m2[1][2]-m[0][0]*m2[1][1]*m[2][1]+ m[0][1]*m[2][0]*m2[1][1]-m2[1][0]*m[2][0]*m[1][1]- 2.0*m[1][0]*m[0][1]*m2[1][2]+m[1][0]*m2[1][0]*m[2][1])/den; ans[2][0] = s[2]*(-m[1][1]*m[0][2]*m2[2][2]+m[0][1]*m[1][2]*m2[2][2]+ 2.0*m[1][1]*m2[2][0]*m[2][2]-m[0][1]*m2[2][1]*m[2][2]+ m[0][2]*m[2][1]*m2[2][1]-2.0*m2[2][0]*m[2][1]*m[1][2]- m[1][0]*m2[2][1]*m[2][2]+m[1][2]*m[2][0]*m2[2][1]- m[1][1]*m[2][0]*m2[2][2]+m[2][1]*m[1][0]*m2[2][2])/den; ans[2][1] = s[2]*-(m[0][1]*m[2][2]*m2[2][0]-m[0][2]*m2[2][0]*m[2][1]- 2.0*m2[2][1]*m[0][0]*m[2][2]+m[1][2]*m2[2][2]*m[0][0]+ 2.0*m2[2][1]*m[0][2]*m[2][0]+m[1][0]*m2[2][0]*m[2][2]- m[1][0]*m[0][2]*m2[2][2]-m[1][2]*m[2][0]*m2[2][0]+ m[0][0]*m2[2][2]*m[2][1]-m2[2][2]*m[0][1]*m[2][0])/den; ans[2][2] = s[2]*(m[0][1]*m[1][2]*m2[2][0]-m[0][2]*m2[2][0]*m[1][1]- m[0][0]*m[1][2]*m2[2][1]+m[1][0]*m[0][2]*m2[2][1]- m[1][1]*m[2][0]*m2[2][0]-m[2][1]*m2[2][1]*m[0][0]+ 2.0*m[1][1]*m2[2][2]*m[0][0]+m[2][1]*m[1][0]*m2[2][0]+ m[2][0]*m[0][1]*m2[2][1]-2.0*m2[2][2]*m[1][0]*m[0][1])/den; } diff --git a/src/ASPHERE/pair_line_lj.cpp b/src/ASPHERE/pair_line_lj.cpp index aa3493ef4..4e3df473a 100644 --- a/src/ASPHERE/pair_line_lj.cpp +++ b/src/ASPHERE/pair_line_lj.cpp @@ -1,471 +1,471 @@ /* ---------------------------------------------------------------------- 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 #include #include #include #include "pair_line_lj.h" #include "atom.h" #include "atom_vec_line.h" #include "force.h" #include "neighbor.h" #include "neigh_list.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define DELTA 10000 /* ---------------------------------------------------------------------- */ PairLineLJ::PairLineLJ(LAMMPS *lmp) : Pair(lmp) { dmax = nmax = 0; discrete = NULL; dnum = dfirst = NULL; single_enable = 0; restartinfo = 0; } /* ---------------------------------------------------------------------- */ PairLineLJ::~PairLineLJ() { memory->sfree(discrete); memory->destroy(dnum); memory->destroy(dfirst); if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(subsize); memory->destroy(cut); memory->destroy(cutsub); memory->destroy(cutsubsq); memory->destroy(epsilon); memory->destroy(sigma); memory->destroy(lj1); memory->destroy(lj2); memory->destroy(lj3); memory->destroy(lj4); } } /* ---------------------------------------------------------------------- */ void PairLineLJ::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; int ni,nj,npi,npj,ifirst,jfirst; double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair; double rsq,r2inv,r6inv,term1,term2,sig,sig3,forcelj; double xi[2],xj[2],fi[2],dxi,dxj,dyi,dyj; 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; double **torque = atom->torque; int *line = atom->line; int *type = atom->type; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; int newton_pair = force->newton_pair; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // grow discrete list if necessary and initialize if (nall > nmax) { nmax = nall; memory->destroy(dnum); memory->destroy(dfirst); memory->create(dnum,nall,"pair:dnum"); memory->create(dfirst,nall,"pair:dfirst"); } for (i = 0; i < nall; i++) dnum[i] = 0; ndiscrete = 0; // 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]; if (rsq >= cutsq[itype][jtype]) continue; // line/line interactions = NxN particles evdwl = 0.0; if (line[i] >= 0 && line[j] >= 0) { if (dnum[i] == 0) discretize(i,subsize[itype]); npi = dnum[i]; ifirst = dfirst[i]; if (dnum[j] == 0) discretize(j,subsize[jtype]); npj = dnum[j]; jfirst = dfirst[j]; for (ni = 0; ni < npi; ni++) { dxi = discrete[ifirst+ni].dx; dyi = discrete[ifirst+ni].dy; for (nj = 0; nj < npj; nj++) { dxj = discrete[jfirst+nj].dx; dyj = discrete[jfirst+nj].dy; xi[0] = x[i][0] + dxi; xi[1] = x[i][1] + dyi; xj[0] = x[j][0] + dxj; xj[1] = x[j][1] + dyj; delx = xi[0] - xj[0]; dely = xi[1] - xj[1]; rsq = delx*delx + dely*dely; // skip this pair of sub-particles if outside sub cutoff if (rsq >= cutsubsq[itype][jtype]) continue; sig = sigma[itype][jtype]; sig3 = sig*sig*sig; term2 = 24.0*epsilon[itype][jtype] * sig3*sig3; term1 = 2.0 * term2 * sig3*sig3; r2inv = 1.0/rsq; r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (term1*r6inv - term2); fpair = forcelj*r2inv; if (eflag) evdwl += r6inv*(term1/12.0*r6inv-term2/6.0); fi[0] = delx*fpair; fi[1] = dely*fpair; f[i][0] += fi[0]; f[i][1] += fi[1]; torque[i][2] += dxi*fi[1] - dyi*fi[0]; if (newton_pair || j < nlocal) { f[j][0] -= fi[0]; f[j][1] -= fi[1]; torque[j][2] -= dxj*fi[1] - dyj*fi[0]; } } } // line/particle interaction = Nx1 particles // convert line into Np particles based on sigma and line length } else if (line[i] >= 0) { if (dnum[i] == 0) discretize(i,subsize[itype]); npi = dnum[i]; ifirst = dfirst[i]; for (ni = 0; ni < npi; ni++) { dxi = discrete[ifirst+ni].dx; dyi = discrete[ifirst+ni].dy; xi[0] = x[i][0] + dxi; xi[1] = x[i][1] + dyi; xj[0] = x[j][0]; xj[1] = x[j][1]; delx = xi[0] - xj[0]; dely = xi[1] - xj[1]; rsq = delx*delx + dely*dely; // skip this pair of sub-particles if outside sub cutoff if (rsq >= cutsubsq[itype][jtype]) continue; sig = sigma[itype][jtype]; sig3 = sig*sig*sig; term2 = 24.0*epsilon[itype][jtype] * sig3*sig3; term1 = 2.0 * term2 * sig3*sig3; r2inv = 1.0/rsq; r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (term1*r6inv - term2); fpair = forcelj*r2inv; if (eflag) evdwl += r6inv*(term1/12.0*r6inv-term2/6.0); fi[0] = delx*fpair; fi[1] = dely*fpair; f[i][0] += fi[0]; f[i][1] += fi[1]; torque[i][2] += dxi*fi[1] - dyi*fi[0]; if (newton_pair || j < nlocal) { f[j][0] -= fi[0]; f[j][1] -= fi[1]; } } // particle/line interaction = Nx1 particles // convert line into Np particles based on sigma and line length } else if (line[j] >= 0) { if (dnum[j] == 0) discretize(j,subsize[jtype]); npj = dnum[j]; jfirst = dfirst[j]; for (nj = 0; nj < npj; nj++) { dxj = discrete[jfirst+nj].dx; dyj = discrete[jfirst+nj].dy; xi[0] = x[i][0]; xi[1] = x[i][1]; xj[0] = x[j][0] + dxj; xj[1] = x[j][1] + dyj; delx = xi[0] - xj[0]; dely = xi[1] - xj[1]; rsq = delx*delx + dely*dely; // skip this pair of sub-particles if outside sub cutoff if (rsq >= cutsubsq[itype][jtype]) continue; sig = sigma[itype][jtype]; sig3 = sig*sig*sig; term2 = 24.0*epsilon[itype][jtype] * sig3*sig3; term1 = 2.0 * term2 * sig3*sig3; r2inv = 1.0/rsq; r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (term1*r6inv - term2); fpair = forcelj*r2inv; if (eflag) evdwl += r6inv*(term1/12.0*r6inv-term2/6.0); fi[0] = delx*fpair; fi[1] = dely*fpair; f[i][0] += fi[0]; f[i][1] += fi[1]; if (newton_pair || j < nlocal) { f[j][0] -= fi[0]; f[j][1] -= fi[1]; torque[j][2] -= dxj*fi[1] - dyj*fi[0]; } } // particle/particle interaction = 1x1 particles } else { r2inv = 1.0/rsq; r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); fpair = forcelj*r2inv; if (eflag) evdwl += r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]); 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 (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 PairLineLJ::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(subsize,n+1,"pair:subsize"); memory->create(cut,n+1,n+1,"pair:cut"); memory->create(cutsub,n+1,n+1,"pair:cutsub"); memory->create(cutsubsq,n+1,n+1,"pair:cutsubsq"); 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"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairLineLJ::settings(int narg, char **arg) { if (narg != 1) error->all(FLERR,"Illegal pair_style command"); cut_global = force->numeric(FLERR,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 PairLineLJ::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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double size_itype = force->numeric(FLERR,arg[2]); double size_jtype = force->numeric(FLERR,arg[3]); double epsilon_one = force->numeric(FLERR,arg[4]); double sigma_one = force->numeric(FLERR,arg[5]); double cutsub_one = force->numeric(FLERR,arg[6]); double cut_one = cut_global; if (narg == 8) cut_one = force->numeric(FLERR,arg[7]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { subsize[i] = size_itype; subsize[j] = size_jtype; epsilon[i][j] = epsilon_one; sigma[i][j] = sigma_one; cutsub[i][j] = cutsub_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 PairLineLJ::init_style() { avec = (AtomVecLine *) atom->style_match("line"); if (!avec) error->all(FLERR,"Pair line/lj requires atom style line"); neighbor->request(this,instance_me); } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairLineLJ::init_one(int i, int j) { if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set"); cutsubsq[i][j] = cutsub[i][j] * cutsub[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); epsilon[j][i] = epsilon[i][j]; sigma[j][i] = sigma[i][j]; cutsubsq[j][i] = cutsubsq[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]; return cut[i][j]; } /* ---------------------------------------------------------------------- discretize line segment I into N sub-particles with <= size separation store displacement dx,dy of discrete particles in Discrete list ------------------------------------------------------------------------- */ void PairLineLJ::discretize(int i, double size) { AtomVecLine::Bonus *bonus = avec->bonus; double length = bonus[atom->line[i]].length; double theta = bonus[atom->line[i]].theta; int n = static_cast (length/size) + 1; dnum[i] = n; dfirst[i] = ndiscrete; if (ndiscrete + n > dmax) { dmax += DELTA; discrete = (Discrete *) memory->srealloc(discrete,dmax*sizeof(Discrete),"pair:discrete"); } double delta; for (int m = 0; m < n; m++) { delta = -0.5 + (2*m+1)/(2.0*n); discrete[ndiscrete].dx = delta*length*cos(theta); discrete[ndiscrete].dy = delta*length*sin(theta); ndiscrete++; } } diff --git a/src/ASPHERE/pair_resquared.cpp b/src/ASPHERE/pair_resquared.cpp index 870ec9574..172516aa4 100644 --- a/src/ASPHERE/pair_resquared.cpp +++ b/src/ASPHERE/pair_resquared.cpp @@ -1,990 +1,990 @@ /* ---------------------------------------------------------------------- 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 #include #include #include #include "pair_resquared.h" #include "math_extra.h" #include "atom.h" #include "atom_vec_ellipsoid.h" #include "comm.h" #include "force.h" #include "neighbor.h" #include "neigh_list.h" #include "integrate.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ PairRESquared::PairRESquared(LAMMPS *lmp) : Pair(lmp), cr60(pow(60.0,1.0/3.0)), b_alpha(45.0/56.0) { single_enable = 0; cr60 = pow(60.0,1.0/3.0); b_alpha = 45.0/56.0; solv_f_a = 3.0/(16.0*atan(1.0)*-36.0); solv_f_r = 3.0/(16.0*atan(1.0)*2025.0); } /* ---------------------------------------------------------------------- free all arrays ------------------------------------------------------------------------- */ PairRESquared::~PairRESquared() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(form); memory->destroy(epsilon); memory->destroy(sigma); memory->destroy(shape1); memory->destroy(shape2); memory->destroy(well); memory->destroy(cut); memory->destroy(lj1); memory->destroy(lj2); memory->destroy(lj3); memory->destroy(lj4); memory->destroy(offset); delete [] lshape; delete [] setwell; } } /* ---------------------------------------------------------------------- */ void PairRESquared::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double evdwl,one_eng,rsq,r2inv,r6inv,forcelj,factor_lj; double fforce[3],ttor[3],rtor[3],r12[3]; int *ilist,*jlist,*numneigh,**firstneigh; RE2Vars wi,wj; evdwl = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; double **x = atom->x; double **f = atom->f; double **tor = atom->torque; 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]; itype = type[i]; // not a LJ sphere if (lshape[itype] != 0.0) precompute_i(i,wi); jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; factor_lj = special_lj[sbmask(j)]; j &= NEIGHMASK; // r12 = center to center vector r12[0] = x[j][0]-x[i][0]; r12[1] = x[j][1]-x[i][1]; r12[2] = x[j][2]-x[i][2]; rsq = MathExtra::dot3(r12,r12); jtype = type[j]; // compute if less than cutoff if (rsq < cutsq[itype][jtype]) { fforce[0] = fforce[1] = fforce[2] = 0.0; switch (form[itype][jtype]) { case SPHERE_SPHERE: r2inv = 1.0/rsq; r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); forcelj *= -r2inv; if (eflag) one_eng = r6inv*(r6inv*lj3[itype][jtype]-lj4[itype][jtype]) - offset[itype][jtype]; fforce[0] = r12[0]*forcelj; fforce[1] = r12[1]*forcelj; fforce[2] = r12[2]*forcelj; break; case SPHERE_ELLIPSE: precompute_i(j,wj); if (newton_pair || j < nlocal) { one_eng = resquared_lj(j,i,wj,r12,rsq,fforce,rtor,true); tor[j][0] += rtor[0]*factor_lj; tor[j][1] += rtor[1]*factor_lj; tor[j][2] += rtor[2]*factor_lj; } else one_eng = resquared_lj(j,i,wj,r12,rsq,fforce,rtor,false); break; case ELLIPSE_SPHERE: one_eng = resquared_lj(i,j,wi,r12,rsq,fforce,ttor,true); tor[i][0] += ttor[0]*factor_lj; tor[i][1] += ttor[1]*factor_lj; tor[i][2] += ttor[2]*factor_lj; break; default: precompute_i(j,wj); one_eng = resquared_analytic(i,j,wi,wj,r12,rsq,fforce,ttor,rtor); tor[i][0] += ttor[0]*factor_lj; tor[i][1] += ttor[1]*factor_lj; tor[i][2] += ttor[2]*factor_lj; if (newton_pair || j < nlocal) { tor[j][0] += rtor[0]*factor_lj; tor[j][1] += rtor[1]*factor_lj; tor[j][2] += rtor[2]*factor_lj; } break; } fforce[0] *= factor_lj; fforce[1] *= factor_lj; fforce[2] *= factor_lj; f[i][0] += fforce[0]; f[i][1] += fforce[1]; f[i][2] += fforce[2]; if (newton_pair || j < nlocal) { f[j][0] -= fforce[0]; f[j][1] -= fforce[1]; f[j][2] -= fforce[2]; } if (eflag) evdwl = factor_lj*one_eng; if (evflag) ev_tally_xyz(i,j,nlocal,newton_pair, evdwl,0.0,fforce[0],fforce[1],fforce[2], -r12[0],-r12[1],-r12[2]); } } } if (vflag_fdotr) virial_fdotr_compute(); } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairRESquared::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(form,n+1,n+1,"pair:form"); memory->create(epsilon,n+1,n+1,"pair:epsilon"); memory->create(sigma,n+1,n+1,"pair:sigma"); memory->create(shape1,n+1,3,"pair:shape1"); memory->create(shape2,n+1,3,"pair:shape2"); memory->create(well,n+1,3,"pair:well"); memory->create(cut,n+1,n+1,"pair:cut"); 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"); lshape = new double[n+1]; setwell = new int[n+1]; for (int i = 1; i <= n; i++) setwell[i] = 0; } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairRESquared::settings(int narg, char **arg) { if (narg != 1) error->all(FLERR,"Illegal pair_style command"); cut_global = force->numeric(FLERR,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 PairRESquared::coeff(int narg, char **arg) { if (narg < 10 || narg > 11) 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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(FLERR,arg[2]); double sigma_one = force->numeric(FLERR,arg[3]); double eia_one = force->numeric(FLERR,arg[4]); double eib_one = force->numeric(FLERR,arg[5]); double eic_one = force->numeric(FLERR,arg[6]); double eja_one = force->numeric(FLERR,arg[7]); double ejb_one = force->numeric(FLERR,arg[8]); double ejc_one = force->numeric(FLERR,arg[9]); double cut_one = cut_global; if (narg == 11) cut_one = force->numeric(FLERR,arg[10]); 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; if (eia_one != 0.0 || eib_one != 0.0 || eic_one != 0.0) { well[i][0] = eia_one; well[i][1] = eib_one; well[i][2] = eic_one; if (eia_one == 1.0 && eib_one == 1.0 && eic_one == 1.0) setwell[i] = 2; else setwell[i] = 1; } if (eja_one != 0.0 || ejb_one != 0.0 || ejc_one != 0.0) { well[j][0] = eja_one; well[j][1] = ejb_one; well[j][2] = ejc_one; if (eja_one == 1.0 && ejb_one == 1.0 && ejc_one == 1.0) setwell[j] = 2; else setwell[j] = 1; } setflag[i][j] = 1; count++; } } if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairRESquared::init_style() { avec = (AtomVecEllipsoid *) atom->style_match("ellipsoid"); if (!avec) error->all(FLERR,"Pair resquared requires atom style ellipsoid"); neighbor->request(this,instance_me); // per-type shape precalculations // require that atom shapes are identical within each type for (int i = 1; i <= atom->ntypes; i++) { if (!atom->shape_consistency(i,shape1[i][0],shape1[i][1],shape1[i][2])) error->all(FLERR,"Pair resquared requires atoms with same type have same shape"); if (setwell[i]) { shape2[i][0] = shape1[i][0]*shape1[i][0]; shape2[i][1] = shape1[i][1]*shape1[i][1]; shape2[i][2] = shape1[i][2]*shape1[i][2]; lshape[i] = shape1[i][0]*shape1[i][1]*shape1[i][2]; } } } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairRESquared::init_one(int i, int j) { if (setwell[i] == 0 || setwell[j] == 0) error->all(FLERR,"Pair resquared epsilon a,b,c coeffs are not all set"); int ishape = 0; if (shape1[i][0] != 0.0 && shape1[i][1] != 0.0 && shape1[i][2] != 0.0) ishape = 1; int jshape = 0; if (shape1[j][0] != 0.0 && shape1[j][1] != 0.0 && shape1[j][2] != 0.0) jshape = 1; if (ishape == 0 && jshape == 0) { form[i][j] = SPHERE_SPHERE; form[j][i] = SPHERE_SPHERE; } else if (ishape == 0) { form[i][j] = SPHERE_ELLIPSE; form[j][i] = ELLIPSE_SPHERE; } else if (jshape == 0) { form[i][j] = ELLIPSE_SPHERE; form[j][i] = SPHERE_ELLIPSE; } else { form[i][j] = ELLIPSE_ELLIPSE; form[j][i] = ELLIPSE_ELLIPSE; } // allow mixing only for LJ spheres if (setflag[i][j] == 0) { if (setflag[j][i] == 0) { if (ishape == 0 && jshape == 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]); } else error->all(FLERR, "Pair resquared epsilon and sigma coeffs are not all set"); } epsilon[i][j] = epsilon[j][i]; sigma[i][j] = sigma[j][i]; cut[i][j] = cut[j][i]; } 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; epsilon[j][i] = epsilon[i][j]; sigma[j][i] = sigma[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]; return cut[i][j]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairRESquared::write_restart(FILE *fp) { write_restart_settings(fp); int i,j; for (i = 1; i <= atom->ntypes; i++) { fwrite(&setwell[i],sizeof(int),1,fp); if (setwell[i]) fwrite(&well[i][0],sizeof(double),3,fp); 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 PairRESquared::read_restart(FILE *fp) { read_restart_settings(fp); allocate(); int i,j; int me = comm->me; for (i = 1; i <= atom->ntypes; i++) { if (me == 0) fread(&setwell[i],sizeof(int),1,fp); MPI_Bcast(&setwell[i],1,MPI_INT,0,world); if (setwell[i]) { if (me == 0) fread(&well[i][0],sizeof(double),3,fp); MPI_Bcast(&well[i][0],3,MPI_DOUBLE,0,world); } 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 PairRESquared::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 PairRESquared::read_restart_settings(FILE *fp) { int me = comm->me; if (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); } /* ---------------------------------------------------------------------- Precompute per-particle temporaries for RE-squared calculation ------------------------------------------------------------------------- */ void PairRESquared::precompute_i(const int i,RE2Vars &ws) { double aTs[3][3]; // A1'*S1^2 int *ellipsoid = atom->ellipsoid; AtomVecEllipsoid::Bonus *bonus = avec->bonus; MathExtra::quat_to_mat_trans(bonus[ellipsoid[i]].quat,ws.A); MathExtra::transpose_diag3(ws.A,well[atom->type[i]],ws.aTe); MathExtra::transpose_diag3(ws.A,shape2[atom->type[i]],aTs); MathExtra::diag_times3(shape2[atom->type[i]],ws.A,ws.sa); MathExtra::times3(aTs,ws.A,ws.gamma); MathExtra::rotation_generator_x(ws.A,ws.lA[0]); MathExtra::rotation_generator_y(ws.A,ws.lA[1]); MathExtra::rotation_generator_z(ws.A,ws.lA[2]); for (int i=0; i<3; i++) { MathExtra::times3(aTs,ws.lA[i],ws.lAtwo[i]); MathExtra::transpose_times3(ws.lA[i],ws.sa,ws.lAsa[i]); MathExtra::plus3(ws.lAsa[i],ws.lAtwo[i],ws.lAsa[i]); } } /* ---------------------------------------------------------------------- Compute the derivative of the determinant of m, using m and the derivative of m (m2) ------------------------------------------------------------------------- */ double PairRESquared::det_prime(const double m[3][3], const double m2[3][3]) { double ans; ans = m2[0][0]*m[1][1]*m[2][2] - m2[0][0]*m[1][2]*m[2][1] - m[1][0]*m2[0][1]*m[2][2] + m[1][0]*m2[0][2]*m[2][1] + m[2][0]*m2[0][1]*m[1][2] - m[2][0]*m2[0][2]*m[1][1] + m[0][0]*m2[1][1]*m[2][2] - m[0][0]*m2[1][2]*m[2][1] - m2[1][0]*m[0][1]*m[2][2] + m2[1][0]*m[0][2]*m[2][1] + m[2][0]*m[0][1]*m2[1][2] - m[2][0]*m[0][2]*m2[1][1] + m[0][0]*m[1][1]*m2[2][2] - m[0][0]*m[1][2]*m2[2][1] - m[1][0]*m[0][1]*m2[2][2] + m[1][0]*m[0][2]*m2[2][1] + m2[2][0]*m[0][1]*m[1][2] - m2[2][0]*m[0][2]*m[1][1]; return ans; } /* ---------------------------------------------------------------------- Compute the energy, force, torque for a pair (INTEGRATED-INTEGRATED) ------------------------------------------------------------------------- */ double PairRESquared::resquared_analytic(const int i, const int j, const RE2Vars &wi, const RE2Vars &wj, const double *r, const double rsq, double *fforce, double *ttor, double *rtor) { int *type = atom->type; // pair computations for energy, force, torque double z1[3],z2[3]; // A1*rhat # don't need to store double v1[3],v2[3]; // inv(S1^2)*z1 # don't need to store double sigma1,sigma2; // 1/sqrt(z1'*v1) double sigma1p2,sigma2p2; // sigma1^2 double rnorm; // L2 norm of r double rhat[3]; // r/rnorm double s[3]; // inv(gamma1+gamma2)*rhat double sigma12; // 1/sqrt(0.5*s'*rhat) double H12[3][3]; // gamma1/sigma1+gamma2/sigma2 double dH; // det(H12) double lambda; // dS1/sigma1p2+dS2/sigma2p2 double nu; // sqrt(dH/(sigma1+sigma2)) double w[3]; // inv(A1'*E1*A1+A2'*E2*A2)*rhat double h12; // rnorm-sigma12; double eta; // lambda/nu double chi; // 2*rhat'*w double sprod; // dS1*dS2 double sigh; // sigma/h12 double tprod; // eta*chi*sigh double Ua,Ur; // attractive/repulsive parts of potential // pair computations for force, torque double sec; // sigma*eta*chi double sigma1p3, sigma2p3; // sigma1^3 double vsigma1[3], vsigma2[3]; // sigma1^3*v1; double sigma12p3; // sigma12^3 double gsigma1[3][3], gsigma2[3][3]; // -gamma1/sigma1^2 double tsig1sig2; // eta/(2*(sigma1+sigma2)) double tdH; // eta/(2*dH) double teta1,teta2; // 2*eta/lambda*dS1/sigma1p3 double fourw[3]; // 4*w; double spr[3]; // 0.5*sigma12^3*s double hsec; // h12+[3,b_alpha]*sec double dspu; // 1/h12 - 1/hsec + temp double pbsu; // 3*sigma/hsec double dspr; // 7/h12-1/hsec+temp double pbsr; // b_alpha*sigma/hsec; double u[3]; // (-rhat(i)*rhat+eye(:,i))/rnorm double u1[3],u2[3]; // A1*u double dsigma1,dsigma2; // u1'*vsigma1 (force) p'*vsigma1 (tor) double dH12[3][3]; // dsigma1*gsigma1 + dsigma2*gsigma2 double ddH; // derivative of det(H12) double deta,dchi,dh12; // derivatives of eta,chi,h12 double dUr,dUa; // derivatives of Ua,Ur // pair computations for torque double fwae[3]; // -fourw'*aTe double p[3]; // lA*rhat rnorm = sqrt(rsq); rhat[0] = r[0]/rnorm; rhat[1] = r[1]/rnorm; rhat[2] = r[2]/rnorm; // energy double temp[3][3]; MathExtra::plus3(wi.gamma,wj.gamma,temp); int ierror = MathExtra::mldivide3(temp,rhat,s); if (ierror) error->all(FLERR,"Bad matrix inversion in mldivide3"); sigma12 = 1.0/sqrt(0.5*MathExtra::dot3(s,rhat)); MathExtra::matvec(wi.A,rhat,z1); MathExtra::matvec(wj.A,rhat,z2); v1[0] = z1[0]/shape2[type[i]][0]; v1[1] = z1[1]/shape2[type[i]][1]; v1[2] = z1[2]/shape2[type[i]][2]; v2[0] = z2[0]/shape2[type[j]][0]; v2[1] = z2[1]/shape2[type[j]][1]; v2[2] = z2[2]/shape2[type[j]][2]; sigma1 = 1.0/sqrt(MathExtra::dot3(z1,v1)); sigma2 = 1.0/sqrt(MathExtra::dot3(z2,v2)); H12[0][0] = wi.gamma[0][0]/sigma1+wj.gamma[0][0]/sigma2; H12[0][1] = wi.gamma[0][1]/sigma1+wj.gamma[0][1]/sigma2; H12[0][2] = wi.gamma[0][2]/sigma1+wj.gamma[0][2]/sigma2; H12[1][0] = wi.gamma[1][0]/sigma1+wj.gamma[1][0]/sigma2; H12[1][1] = wi.gamma[1][1]/sigma1+wj.gamma[1][1]/sigma2; H12[1][2] = wi.gamma[1][2]/sigma1+wj.gamma[1][2]/sigma2; H12[2][0] = wi.gamma[2][0]/sigma1+wj.gamma[2][0]/sigma2; H12[2][1] = wi.gamma[2][1]/sigma1+wj.gamma[2][1]/sigma2; H12[2][2] = wi.gamma[2][2]/sigma1+wj.gamma[2][2]/sigma2; dH=MathExtra::det3(H12); sigma1p2 = sigma1*sigma1; sigma2p2 = sigma2*sigma2; lambda = lshape[type[i]]/sigma1p2 + lshape[type[j]]/sigma2p2; nu = sqrt(dH/(sigma1+sigma2)); MathExtra::times3(wi.aTe,wi.A,temp); double temp2[3][3]; MathExtra::times3(wj.aTe,wj.A,temp2); MathExtra::plus3(temp,temp2,temp); ierror = MathExtra::mldivide3(temp,rhat,w); if (ierror) error->all(FLERR,"Bad matrix inversion in mldivide3"); h12 = rnorm-sigma12; eta = lambda/nu; chi = 2.0*MathExtra::dot3(rhat,w); sprod = lshape[type[i]] * lshape[type[j]]; sigh = sigma[type[i]][type[j]]/h12; tprod = eta*chi*sigh; double stemp = h12/2.0; Ua = (shape1[type[i]][0]+stemp)*(shape1[type[i]][1]+stemp)* (shape1[type[i]][2]+stemp)*(shape1[type[j]][0]+stemp)* (shape1[type[j]][1]+stemp)*(shape1[type[j]][2]+stemp); Ua = (1.0+3.0*tprod)*sprod/Ua; Ua = epsilon[type[i]][type[j]]*Ua/-36.0; stemp = h12/cr60; Ur = (shape1[type[i]][0]+stemp)*(shape1[type[i]][1]+stemp)* (shape1[type[i]][2]+stemp)*(shape1[type[j]][0]+stemp)* (shape1[type[j]][1]+stemp)*(shape1[type[j]][2]+stemp); Ur = (1.0+b_alpha*tprod)*sprod/Ur; Ur = epsilon[type[i]][type[j]]*Ur*pow(sigh,6.0)/2025.0; // force sec = sigma[type[i]][type[j]]*eta*chi; sigma12p3 = pow(sigma12,3.0); sigma1p3 = sigma1p2*sigma1; sigma2p3 = sigma2p2*sigma2; vsigma1[0] = -sigma1p3*v1[0]; vsigma1[1] = -sigma1p3*v1[1]; vsigma1[2] = -sigma1p3*v1[2]; vsigma2[0] = -sigma2p3*v2[0]; vsigma2[1] = -sigma2p3*v2[1]; vsigma2[2] = -sigma2p3*v2[2]; gsigma1[0][0] = -wi.gamma[0][0]/sigma1p2; gsigma1[0][1] = -wi.gamma[0][1]/sigma1p2; gsigma1[0][2] = -wi.gamma[0][2]/sigma1p2; gsigma1[1][0] = -wi.gamma[1][0]/sigma1p2; gsigma1[1][1] = -wi.gamma[1][1]/sigma1p2; gsigma1[1][2] = -wi.gamma[1][2]/sigma1p2; gsigma1[2][0] = -wi.gamma[2][0]/sigma1p2; gsigma1[2][1] = -wi.gamma[2][1]/sigma1p2; gsigma1[2][2] = -wi.gamma[2][2]/sigma1p2; gsigma2[0][0] = -wj.gamma[0][0]/sigma2p2; gsigma2[0][1] = -wj.gamma[0][1]/sigma2p2; gsigma2[0][2] = -wj.gamma[0][2]/sigma2p2; gsigma2[1][0] = -wj.gamma[1][0]/sigma2p2; gsigma2[1][1] = -wj.gamma[1][1]/sigma2p2; gsigma2[1][2] = -wj.gamma[1][2]/sigma2p2; gsigma2[2][0] = -wj.gamma[2][0]/sigma2p2; gsigma2[2][1] = -wj.gamma[2][1]/sigma2p2; gsigma2[2][2] = -wj.gamma[2][2]/sigma2p2; tsig1sig2 = eta/(2.0*(sigma1+sigma2)); tdH = eta/(2.0*dH); teta1 = 2.0*eta/lambda; teta2 = teta1*lshape[type[j]]/sigma2p3; teta1 = teta1*lshape[type[i]]/sigma1p3; fourw[0] = 4.0*w[0]; fourw[1] = 4.0*w[1]; fourw[2] = 4.0*w[2]; spr[0] = 0.5*sigma12p3*s[0]; spr[1] = 0.5*sigma12p3*s[1]; spr[2] = 0.5*sigma12p3*s[2]; stemp = 1.0/(shape1[type[i]][0]*2.0+h12)+ 1.0/(shape1[type[i]][1]*2.0+h12)+ 1.0/(shape1[type[i]][2]*2.0+h12)+ 1.0/(shape1[type[j]][0]*2.0+h12)+ 1.0/(shape1[type[j]][1]*2.0+h12)+ 1.0/(shape1[type[j]][2]*2.0+h12); hsec = h12+3.0*sec; dspu = 1.0/h12-1.0/hsec+stemp; pbsu = 3.0*sigma[type[i]][type[j]]/hsec; stemp = 1.0/(shape1[type[i]][0]*cr60+h12)+ 1.0/(shape1[type[i]][1]*cr60+h12)+ 1.0/(shape1[type[i]][2]*cr60+h12)+ 1.0/(shape1[type[j]][0]*cr60+h12)+ 1.0/(shape1[type[j]][1]*cr60+h12)+ 1.0/(shape1[type[j]][2]*cr60+h12); hsec = h12+b_alpha*sec; dspr = 7.0/h12-1.0/hsec+stemp; pbsr = b_alpha*sigma[type[i]][type[j]]/hsec; for (int i=0; i<3; i++) { u[0] = -rhat[i]*rhat[0]; u[1] = -rhat[i]*rhat[1]; u[2] = -rhat[i]*rhat[2]; u[i] += 1.0; u[0] /= rnorm; u[1] /= rnorm; u[2] /= rnorm; MathExtra::matvec(wi.A,u,u1); MathExtra::matvec(wj.A,u,u2); dsigma1=MathExtra::dot3(u1,vsigma1); dsigma2=MathExtra::dot3(u2,vsigma2); dH12[0][0] = dsigma1*gsigma1[0][0]+dsigma2*gsigma2[0][0]; dH12[0][1] = dsigma1*gsigma1[0][1]+dsigma2*gsigma2[0][1]; dH12[0][2] = dsigma1*gsigma1[0][2]+dsigma2*gsigma2[0][2]; dH12[1][0] = dsigma1*gsigma1[1][0]+dsigma2*gsigma2[1][0]; dH12[1][1] = dsigma1*gsigma1[1][1]+dsigma2*gsigma2[1][1]; dH12[1][2] = dsigma1*gsigma1[1][2]+dsigma2*gsigma2[1][2]; dH12[2][0] = dsigma1*gsigma1[2][0]+dsigma2*gsigma2[2][0]; dH12[2][1] = dsigma1*gsigma1[2][1]+dsigma2*gsigma2[2][1]; dH12[2][2] = dsigma1*gsigma1[2][2]+dsigma2*gsigma2[2][2]; ddH = det_prime(H12,dH12); deta = (dsigma1+dsigma2)*tsig1sig2; deta -= ddH*tdH; deta -= dsigma1*teta1+dsigma2*teta2; dchi = MathExtra::dot3(u,fourw); dh12 = rhat[i]+MathExtra::dot3(u,spr); dUa = pbsu*(eta*dchi+deta*chi)-dh12*dspu; dUr = pbsr*(eta*dchi+deta*chi)-dh12*dspr; fforce[i]=dUr*Ur+dUa*Ua; } // torque on i MathExtra::vecmat(fourw,wi.aTe,fwae); for (int i=0; i<3; i++) { MathExtra::matvec(wi.lA[i],rhat,p); dsigma1 = MathExtra::dot3(p,vsigma1); dH12[0][0] = wi.lAsa[i][0][0]/sigma1+dsigma1*gsigma1[0][0]; dH12[0][1] = wi.lAsa[i][0][1]/sigma1+dsigma1*gsigma1[0][1]; dH12[0][2] = wi.lAsa[i][0][2]/sigma1+dsigma1*gsigma1[0][2]; dH12[1][0] = wi.lAsa[i][1][0]/sigma1+dsigma1*gsigma1[1][0]; dH12[1][1] = wi.lAsa[i][1][1]/sigma1+dsigma1*gsigma1[1][1]; dH12[1][2] = wi.lAsa[i][1][2]/sigma1+dsigma1*gsigma1[1][2]; dH12[2][0] = wi.lAsa[i][2][0]/sigma1+dsigma1*gsigma1[2][0]; dH12[2][1] = wi.lAsa[i][2][1]/sigma1+dsigma1*gsigma1[2][1]; dH12[2][2] = wi.lAsa[i][2][2]/sigma1+dsigma1*gsigma1[2][2]; ddH = det_prime(H12,dH12); deta = tsig1sig2*dsigma1-tdH*ddH; deta -= teta1*dsigma1; double tempv[3]; MathExtra::matvec(wi.lA[i],w,tempv); dchi = -MathExtra::dot3(fwae,tempv); MathExtra::matvec(wi.lAtwo[i],spr,tempv); dh12 = -MathExtra::dot3(s,tempv); dUa = pbsu*(eta*dchi + deta*chi)-dh12*dspu; dUr = pbsr*(eta*dchi + deta*chi)-dh12*dspr; ttor[i] = -(dUa*Ua+dUr*Ur); } // torque on j if (!(force->newton_pair || j < atom->nlocal)) return Ua+Ur; MathExtra::vecmat(fourw,wj.aTe,fwae); for (int i=0; i<3; i++) { MathExtra::matvec(wj.lA[i],rhat,p); dsigma2 = MathExtra::dot3(p,vsigma2); dH12[0][0] = wj.lAsa[i][0][0]/sigma2+dsigma2*gsigma2[0][0]; dH12[0][1] = wj.lAsa[i][0][1]/sigma2+dsigma2*gsigma2[0][1]; dH12[0][2] = wj.lAsa[i][0][2]/sigma2+dsigma2*gsigma2[0][2]; dH12[1][0] = wj.lAsa[i][1][0]/sigma2+dsigma2*gsigma2[1][0]; dH12[1][1] = wj.lAsa[i][1][1]/sigma2+dsigma2*gsigma2[1][1]; dH12[1][2] = wj.lAsa[i][1][2]/sigma2+dsigma2*gsigma2[1][2]; dH12[2][0] = wj.lAsa[i][2][0]/sigma2+dsigma2*gsigma2[2][0]; dH12[2][1] = wj.lAsa[i][2][1]/sigma2+dsigma2*gsigma2[2][1]; dH12[2][2] = wj.lAsa[i][2][2]/sigma2+dsigma2*gsigma2[2][2]; ddH = det_prime(H12,dH12); deta = tsig1sig2*dsigma2-tdH*ddH; deta -= teta2*dsigma2; double tempv[3]; MathExtra::matvec(wj.lA[i],w,tempv); dchi = -MathExtra::dot3(fwae,tempv); MathExtra::matvec(wj.lAtwo[i],spr,tempv); dh12 = -MathExtra::dot3(s,tempv); dUa = pbsu*(eta*dchi + deta*chi)-dh12*dspu; dUr = pbsr*(eta*dchi + deta*chi)-dh12*dspr; rtor[i] = -(dUa*Ua+dUr*Ur); } return Ua+Ur; } /* ---------------------------------------------------------------------- Compute the energy, force, torque for a pair (INTEGRATED-LJ) ------------------------------------------------------------------------- */ double PairRESquared::resquared_lj(const int i, const int j, const RE2Vars &wi, const double *r, const double rsq, double *fforce, double *ttor, bool calc_torque) { int *type = atom->type; // pair computations for energy, force, torque double rnorm; // L2 norm of r double rhat[3]; // r/rnorm double s[3]; // inv(gamma1)*rhat double sigma12; // 1/sqrt(0.5*s'*rhat) double w[3]; // inv(A1'*E1*A1+I)*rhat double h12; // rnorm-sigma12; double chi; // 2*rhat'*w double sigh; // sigma/h12 double tprod; // chi*sigh double Ua,Ur; // attractive/repulsive parts of potential // pair computations for force, torque double sec; // sigma*chi double sigma12p3; // sigma12^3 double fourw[3]; // 4*w; double spr[3]; // 0.5*sigma12^3*s double hsec; // h12+[3,b_alpha]*sec double dspu; // 1/h12 - 1/hsec + temp double pbsu; // 3*sigma/hsec double dspr; // 7/h12-1/hsec+temp double pbsr; // b_alpha*sigma/hsec; double u[3]; // (-rhat(i)*rhat+eye(:,i))/rnorm double dchi,dh12; // derivatives of chi,h12 double dUr,dUa; // derivatives of Ua,Ur double h12p3; // h12^3 // pair computations for torque double fwae[3]; // -fourw'*aTe double p[3]; // lA*rhat // distance of closest approach correction double aTs[3][3]; // A1'*S1^2 double gamma[3][3]; // A1'*S1^2*A double lAtwo[3][3][3]; // A1'*S1^2*wi.lA double scorrect[3]; double half_sigma=sigma[type[i]][type[j]] / 2.0; scorrect[0] = shape1[type[i]][0]+half_sigma; scorrect[1] = shape1[type[i]][1]+half_sigma; scorrect[2] = shape1[type[i]][2]+half_sigma; scorrect[0] = scorrect[0] * scorrect[0] / 2.0; scorrect[1] = scorrect[1] * scorrect[1] / 2.0; scorrect[2] = scorrect[2] * scorrect[2] / 2.0; MathExtra::transpose_diag3(wi.A,scorrect,aTs); MathExtra::times3(aTs,wi.A,gamma); for (int ii=0; ii<3; ii++) MathExtra::times3(aTs,wi.lA[ii],lAtwo[ii]); rnorm=sqrt(rsq); rhat[0] = r[0]/rnorm; rhat[1] = r[1]/rnorm; rhat[2] = r[2]/rnorm; // energy int ierror = MathExtra::mldivide3(gamma,rhat,s); if (ierror) error->all(FLERR,"Bad matrix inversion in mldivide3"); sigma12 = 1.0/sqrt(0.5*MathExtra::dot3(s,rhat)); double temp[3][3]; MathExtra::times3(wi.aTe,wi.A,temp); temp[0][0] += 1.0; temp[1][1] += 1.0; temp[2][2] += 1.0; ierror = MathExtra::mldivide3(temp,rhat,w); if (ierror) error->all(FLERR,"Bad matrix inversion in mldivide3"); h12 = rnorm-sigma12; chi = 2.0*MathExtra::dot3(rhat,w); sigh = sigma[type[i]][type[j]]/h12; tprod = chi*sigh; h12p3 = pow(h12,3.0); double sigmap3 = pow(sigma[type[i]][type[j]],3.0); double stemp = h12/2.0; Ua = (shape1[type[i]][0]+stemp)*(shape1[type[i]][1]+stemp)* (shape1[type[i]][2]+stemp)*h12p3/8.0; Ua = (1.0+3.0*tprod)*lshape[type[i]]/Ua; Ua = epsilon[type[i]][type[j]]*Ua*sigmap3*solv_f_a; stemp = h12/cr60; Ur = (shape1[type[i]][0]+stemp)*(shape1[type[i]][1]+stemp)* (shape1[type[i]][2]+stemp)*h12p3/60.0; Ur = (1.0+b_alpha*tprod)*lshape[type[i]]/Ur; Ur = epsilon[type[i]][type[j]]*Ur*sigmap3*pow(sigh,6.0)*solv_f_r; // force sec = sigma[type[i]][type[j]]*chi; sigma12p3 = pow(sigma12,3.0); fourw[0] = 4.0*w[0]; fourw[1] = 4.0*w[1]; fourw[2] = 4.0*w[2]; spr[0] = 0.5*sigma12p3*s[0]; spr[1] = 0.5*sigma12p3*s[1]; spr[2] = 0.5*sigma12p3*s[2]; stemp = 1.0/(shape1[type[i]][0]*2.0+h12)+ 1.0/(shape1[type[i]][1]*2.0+h12)+ 1.0/(shape1[type[i]][2]*2.0+h12)+ 3.0/h12; hsec = h12+3.0*sec; dspu = 1.0/h12-1.0/hsec+stemp; pbsu = 3.0*sigma[type[i]][type[j]]/hsec; stemp = 1.0/(shape1[type[i]][0]*cr60+h12)+ 1.0/(shape1[type[i]][1]*cr60+h12)+ 1.0/(shape1[type[i]][2]*cr60+h12)+ 3.0/h12; hsec = h12+b_alpha*sec; dspr = 7.0/h12-1.0/hsec+stemp; pbsr = b_alpha*sigma[type[i]][type[j]]/hsec; for (int i=0; i<3; i++) { u[0] = -rhat[i]*rhat[0]; u[1] = -rhat[i]*rhat[1]; u[2] = -rhat[i]*rhat[2]; u[i] += 1.0; u[0] /= rnorm; u[1] /= rnorm; u[2] /= rnorm; dchi = MathExtra::dot3(u,fourw); dh12 = rhat[i]+MathExtra::dot3(u,spr); dUa = pbsu*dchi-dh12*dspu; dUr = pbsr*dchi-dh12*dspr; fforce[i]=dUr*Ur+dUa*Ua; } // torque on i if (calc_torque) { MathExtra::vecmat(fourw,wi.aTe,fwae); for (int i=0; i<3; i++) { MathExtra::matvec(wi.lA[i],rhat,p); double tempv[3]; MathExtra::matvec(wi.lA[i],w,tempv); dchi = -MathExtra::dot3(fwae,tempv); MathExtra::matvec(lAtwo[i],spr,tempv); dh12 = -MathExtra::dot3(s,tempv); dUa = pbsu*dchi-dh12*dspu; dUr = pbsr*dchi-dh12*dspr; ttor[i] = -(dUa*Ua+dUr*Ur); } } return Ua+Ur; } diff --git a/src/ASPHERE/pair_tri_lj.cpp b/src/ASPHERE/pair_tri_lj.cpp index ef5123dc1..773ad2d6a 100644 --- a/src/ASPHERE/pair_tri_lj.cpp +++ b/src/ASPHERE/pair_tri_lj.cpp @@ -1,646 +1,646 @@ /* ---------------------------------------------------------------------- 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 #include #include #include #include "pair_tri_lj.h" #include "math_extra.h" #include "atom.h" #include "atom_vec_tri.h" #include "force.h" #include "neighbor.h" #include "neigh_list.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define DELTA 20 /* ---------------------------------------------------------------------- */ PairTriLJ::PairTriLJ(LAMMPS *lmp) : Pair(lmp) { dmax = nmax = 0; discrete = NULL; dnum = dfirst = NULL; single_enable = 0; restartinfo = 0; } /* ---------------------------------------------------------------------- */ PairTriLJ::~PairTriLJ() { memory->sfree(discrete); memory->destroy(dnum); memory->destroy(dfirst); 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); } } /* ---------------------------------------------------------------------- */ void PairTriLJ::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; int ni,nj,npi,npj,ifirst,jfirst; double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair; double rsq,r2inv,r6inv,term1,term2,sig,sig3,forcelj; double dxi,dxj,dyi,dyj,dzi,dzj; double xi[3],xj[3],fi[3],fj[3],ti[3],tj[3],p[3][3]; double dc1[3],dc2[3],dc3[3]; int *ilist,*jlist,*numneigh,**firstneigh; evdwl = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; AtomVecTri::Bonus *bonus = avec->bonus; double **x = atom->x; double **f = atom->f; double **torque = atom->torque; int *tri = atom->tri; int *type = atom->type; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; int newton_pair = force->newton_pair; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // grow discrete list if necessary and initialize if (nall > nmax) { nmax = nall; memory->destroy(dnum); memory->destroy(dfirst); memory->create(dnum,nall,"pair:dnum"); memory->create(dfirst,nall,"pair:dfirst"); } for (i = 0; i < nall; i++) dnum[i] = 0; ndiscrete = 0; // 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]; if (rsq >= cutsq[itype][jtype]) continue; // tri/tri interactions = NxN particles // c1,c2,c3 = corner pts of triangle I or J evdwl = 0.0; if (tri[i] >= 0 && tri[j] >= 0) { if (dnum[i] == 0) { MathExtra::quat_to_mat(bonus[tri[i]].quat,p); MathExtra::matvec(p,bonus[tri[i]].c1,dc1); MathExtra::matvec(p,bonus[tri[i]].c2,dc2); MathExtra::matvec(p,bonus[tri[i]].c3,dc3); dfirst[i] = ndiscrete; discretize(i,sigma[itype][itype],dc1,dc2,dc3); dnum[i] = ndiscrete - dfirst[i]; } npi = dnum[i]; ifirst = dfirst[i]; if (dnum[j] == 0) { MathExtra::quat_to_mat(bonus[tri[j]].quat,p); MathExtra::matvec(p,bonus[tri[j]].c1,dc1); MathExtra::matvec(p,bonus[tri[j]].c2,dc2); MathExtra::matvec(p,bonus[tri[j]].c3,dc3); dfirst[j] = ndiscrete; discretize(j,sigma[jtype][jtype],dc1,dc2,dc3); dnum[j] = ndiscrete - dfirst[j]; } npj = dnum[j]; jfirst = dfirst[j]; for (ni = 0; ni < npi; ni++) { dxi = discrete[ifirst+ni].dx; dyi = discrete[ifirst+ni].dy; dzi = discrete[ifirst+ni].dz; for (nj = 0; nj < npj; nj++) { dxj = discrete[jfirst+nj].dx; dyj = discrete[jfirst+nj].dy; dzj = discrete[jfirst+nj].dz; xi[0] = x[i][0] + dxi; xi[1] = x[i][1] + dyi; xi[2] = x[i][2] + dzi; xj[0] = x[j][0] + dxj; xj[1] = x[j][1] + dyj; xj[2] = x[j][2] + dzj; delx = xi[0] - xj[0]; dely = xi[1] - xj[1]; delz = xi[2] - xj[2]; rsq = delx*delx + dely*dely + delz*delz; sig = 0.5 * (discrete[ifirst+ni].sigma+discrete[jfirst+nj].sigma); sig3 = sig*sig*sig; term2 = 24.0*epsilon[itype][jtype] * sig3*sig3; term1 = 2.0 * term2 * sig3*sig3; r2inv = 1.0/rsq; r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (term1*r6inv - term2); fpair = forcelj*r2inv; if (eflag) evdwl += r6inv*(term1/12.0*r6inv-term2/6.0); fi[0] = delx*fpair; fi[1] = dely*fpair; fi[2] = delz*fpair; f[i][0] += fi[0]; f[i][1] += fi[1]; f[i][2] += fi[2]; ti[0] = dyi*fi[2] - dzi*fi[1]; ti[1] = dzi*fi[0] - dxi*fi[2]; ti[2] = dxi*fi[1] - dyi*fi[0]; torque[i][0] += ti[0]; torque[i][1] += ti[1]; torque[i][2] += ti[2]; if (newton_pair || j < nlocal) { fj[0] = -delx*fpair; fj[1] = -dely*fpair; fj[2] = -delz*fpair; f[j][0] += fj[0]; f[j][1] += fj[1]; f[j][2] += fj[2]; tj[0] = dyj*fj[2] - dzj*fj[1]; tj[1] = dzj*fj[0] - dxj*fj[2]; tj[2] = dxj*fj[1] - dyj*fj[0]; torque[j][0] += tj[0]; torque[j][1] += tj[1]; torque[j][2] += tj[2]; } } } // tri/particle interaction = Nx1 particles // c1,c2,c3 = corner pts of triangle I } else if (tri[i] >= 0) { if (dnum[i] == 0) { MathExtra::quat_to_mat(bonus[tri[i]].quat,p); MathExtra::matvec(p,bonus[tri[i]].c1,dc1); MathExtra::matvec(p,bonus[tri[i]].c2,dc2); MathExtra::matvec(p,bonus[tri[i]].c3,dc3); dfirst[i] = ndiscrete; discretize(i,sigma[itype][itype],dc1,dc2,dc3); dnum[i] = ndiscrete - dfirst[i]; } npi = dnum[i]; ifirst = dfirst[i]; for (ni = 0; ni < npi; ni++) { dxi = discrete[ifirst+ni].dx; dyi = discrete[ifirst+ni].dy; dzi = discrete[ifirst+ni].dz; xi[0] = x[i][0] + dxi; xi[1] = x[i][1] + dyi; xi[2] = x[i][2] + dzi; xj[0] = x[j][0]; xj[1] = x[j][1]; xj[2] = x[j][2]; delx = xi[0] - xj[0]; dely = xi[1] - xj[1]; delz = xi[2] - xj[2]; rsq = delx*delx + dely*dely + delz*delz; sig = 0.5 * (discrete[ifirst+ni].sigma+sigma[jtype][jtype]); sig3 = sig*sig*sig; term2 = 24.0*epsilon[itype][jtype] * sig3*sig3; term1 = 2.0 * term2 * sig3*sig3; r2inv = 1.0/rsq; r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (term1*r6inv - term2); fpair = forcelj*r2inv; if (eflag) evdwl += r6inv*(term1/12.0*r6inv-term2/6.0); fi[0] = delx*fpair; fi[1] = dely*fpair; fi[2] = delz*fpair; f[i][0] += fi[0]; f[i][1] += fi[1]; f[i][2] += fi[2]; ti[0] = dyi*fi[2] - dzi*fi[1]; ti[1] = dzi*fi[0] - dxi*fi[2]; ti[2] = dxi*fi[1] - dyi*fi[0]; torque[i][2] += ti[0]; torque[i][1] += ti[1]; torque[i][2] += ti[2]; if (newton_pair || j < nlocal) { fj[0] = -delx*fpair; fj[1] = -dely*fpair; fj[2] = -delz*fpair; f[j][0] += fj[0]; f[j][1] += fj[1]; f[j][2] += fj[2]; } } // particle/tri interaction = Nx1 particles // c1,c2,c3 = corner pts of triangle J } else if (tri[j] >= 0) { if (dnum[j] == 0) { MathExtra::quat_to_mat(bonus[tri[j]].quat,p); MathExtra::matvec(p,bonus[tri[j]].c1,dc1); MathExtra::matvec(p,bonus[tri[j]].c2,dc2); MathExtra::matvec(p,bonus[tri[j]].c3,dc3); dfirst[j] = ndiscrete; discretize(j,sigma[jtype][jtype],dc1,dc2,dc3); dnum[j] = ndiscrete - dfirst[j]; } npj = dnum[j]; jfirst = dfirst[j]; for (nj = 0; nj < npj; nj++) { dxj = discrete[jfirst+nj].dx; dyj = discrete[jfirst+nj].dy; dzj = discrete[jfirst+nj].dz; xi[0] = x[i][0]; xi[1] = x[i][1]; xi[2] = x[i][2]; xj[0] = x[j][0] + dxj; xj[1] = x[j][1] + dyj; xj[2] = x[j][2] + dzj; delx = xi[0] - xj[0]; dely = xi[1] - xj[1]; delz = xi[2] - xj[2]; rsq = delx*delx + dely*dely + delz*delz; sig = 0.5 * (sigma[itype][itype]+discrete[jfirst+nj].sigma); sig3 = sig*sig*sig; term2 = 24.0*epsilon[itype][jtype] * sig3*sig3; term1 = 2.0 * term2 * sig3*sig3; r2inv = 1.0/rsq; r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (term1*r6inv - term2); fpair = forcelj*r2inv; if (eflag) evdwl += r6inv*(term1/12.0*r6inv-term2/6.0); fi[0] = delx*fpair; fi[1] = dely*fpair; fi[2] = delz*fpair; f[i][0] += fi[0]; f[i][1] += fi[1]; f[i][2] += fi[2]; if (newton_pair || j < nlocal) { fj[0] = -delx*fpair; fj[1] = -dely*fpair; fj[2] = -delz*fpair; f[j][0] += fj[0]; f[j][1] += fj[1]; f[j][2] += fj[2]; tj[0] = dyj*fj[2] - dzj*fj[1]; tj[1] = dzj*fj[0] - dxj*fj[2]; tj[2] = dxj*fj[1] - dyj*fj[0]; torque[j][0] += tj[0]; torque[j][1] += tj[1]; torque[j][2] += tj[2]; } } // particle/particle interaction = 1x1 particles } else { r2inv = 1.0/rsq; r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); fpair = forcelj*r2inv; if (eflag) evdwl += r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]); 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 (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 PairTriLJ::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"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairTriLJ::settings(int narg, char **arg) { if (narg != 1) error->all(FLERR,"Illegal pair_style command"); cut_global = force->numeric(FLERR,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 PairTriLJ::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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(FLERR,arg[2]); double sigma_one = force->numeric(FLERR,arg[3]); double cut_one = cut_global; if (narg == 5) cut_one = force->numeric(FLERR,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 PairTriLJ::init_style() { avec = (AtomVecTri *) atom->style_match("tri"); if (!avec) error->all(FLERR,"Pair tri/lj requires atom style tri"); neighbor->request(this,instance_me); } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairTriLJ::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); epsilon[j][i] = epsilon[i][j]; sigma[j][i] = sigma[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]; return cut[i][j]; } /* ---------------------------------------------------------------------- recursively discretize triangle I with displaced corners c1,c2,c3 into N sub-tris no more than sigma in size recurse by making 2 tris via bisecting longest side store new discrete particles in Discrete list ------------------------------------------------------------------------- */ void PairTriLJ::discretize(int i, double sigma, double *c1, double *c2, double *c3) { double centroid[3],dc1[3],dc2[3],dc3[3]; centroid[0] = (c1[0] + c2[0] + c3[0]) / 3.0; centroid[1] = (c1[1] + c2[1] + c3[1]) / 3.0; centroid[2] = (c1[2] + c2[2] + c3[2]) / 3.0; MathExtra::sub3(c1,centroid,dc1); MathExtra::sub3(c2,centroid,dc2); MathExtra::sub3(c3,centroid,dc3); double sigmasq = 0.25 * sigma*sigma; double len1sq = MathExtra::lensq3(dc1); double len2sq = MathExtra::lensq3(dc2); double len3sq = MathExtra::lensq3(dc3); // if sigma sphere overlaps all corner points, add particle at centroid if ((len1sq <= sigmasq) && (len2sq <= sigmasq) && (len3sq <= sigmasq)) { if (ndiscrete == dmax) { dmax += DELTA; discrete = (Discrete *) memory->srealloc(discrete,dmax*sizeof(Discrete),"pair:discrete"); } discrete[ndiscrete].dx = centroid[0]; discrete[ndiscrete].dy = centroid[1]; discrete[ndiscrete].dz = centroid[2]; sigmasq = MAX(len1sq,len2sq); sigmasq = MAX(sigmasq,len3sq); discrete[ndiscrete].sigma = 2.0 * sqrt(sigmasq); ndiscrete++; return; } // else break triangle into 2 sub-triangles and recurse double c12[3],c23[3],c13[3],mid[3]; MathExtra::sub3(c2,c3,c23); len1sq = MathExtra::lensq3(c23); MathExtra::sub3(c1,c3,c13); len2sq = MathExtra::lensq3(c13); MathExtra::sub3(c1,c2,c12); len3sq = MathExtra::lensq3(c12); double maxsq = MAX(len1sq,len2sq); maxsq = MAX(maxsq,len3sq); if (len1sq == maxsq) { MathExtra::add3(c2,c3,mid); MathExtra::scale3(0.5,mid); discretize(i,sigma,c1,c2,mid); discretize(i,sigma,c1,c3,mid); } else if (len2sq == maxsq) { MathExtra::add3(c1,c3,mid); MathExtra::scale3(0.5,mid); discretize(i,sigma,c2,c1,mid); discretize(i,sigma,c2,c3,mid); } else { MathExtra::add3(c1,c2,mid); MathExtra::scale3(0.5,mid); discretize(i,sigma,c3,c1,mid); discretize(i,sigma,c3,c2,mid); } } /* ---------------------------------------------------------------------- recursively discretize triangle I with displaced corners c1,c2,c3 into N sub-tris no more than sigma in size recurse by making 6 tris via centroid store new discrete particles in Discrete list ------------------------------------------------------------------------- */ /* void PairTriLJ::discretize(int i, double sigma, double *c1, double *c2, double *c3) { double centroid[3],dc1[3],dc2[3],dc3[3]; centroid[0] = (c1[0] + c2[0] + c3[0]) / 3.0; centroid[1] = (c1[1] + c2[1] + c3[1]) / 3.0; centroid[2] = (c1[2] + c2[2] + c3[2]) / 3.0; MathExtra::sub3(c1,centroid,dc1); MathExtra::sub3(c2,centroid,dc2); MathExtra::sub3(c3,centroid,dc3); double sigmasq = 0.25 * sigma*sigma; double len1sq = MathExtra::lensq3(dc1); double len2sq = MathExtra::lensq3(dc2); double len3sq = MathExtra::lensq3(dc3); // if sigma sphere overlaps all corner points, add particle at centroid if (len1sq <= sigmasq && len2sq <= sigmasq & len3sq <= sigmasq) { if (ndiscrete == dmax) { dmax += DELTA; discrete = (Discrete *) memory->srealloc(discrete,dmax*sizeof(Discrete),"pair:discrete"); } discrete[ndiscrete].dx = centroid[0]; discrete[ndiscrete].dy = centroid[1]; discrete[ndiscrete].dz = centroid[2]; sigmasq = MAX(len1sq,len2sq); sigmasq = MAX(sigmasq,len3sq); discrete[ndiscrete].sigma = 2.0 * sqrt(sigmasq); ndiscrete++; return; } // else break triangle into 6 sub-triangles and recurse double c1c2mid[3],c2c3mid[3],c1c3mid[3]; MathExtra::add3(c1,c2,c1c2mid); MathExtra::scale3(0.5,c1c2mid); MathExtra::add3(c2,c3,c2c3mid); MathExtra::scale3(0.5,c2c3mid); MathExtra::add3(c1,c3,c1c3mid); MathExtra::scale3(0.5,c1c3mid); discretize(i,sigma,c1,c1c2mid,centroid); discretize(i,sigma,c1,c1c3mid,centroid); discretize(i,sigma,c2,c2c3mid,centroid); discretize(i,sigma,c2,c1c2mid,centroid); discretize(i,sigma,c3,c1c3mid,centroid); discretize(i,sigma,c3,c2c3mid,centroid); } */ diff --git a/src/BODY/pair_body.cpp b/src/BODY/pair_body.cpp index 86fea7e85..2a9edb37c 100644 --- a/src/BODY/pair_body.cpp +++ b/src/BODY/pair_body.cpp @@ -1,484 +1,484 @@ /* ---------------------------------------------------------------------- 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 #include #include #include #include "pair_body.h" #include "math_extra.h" #include "atom.h" #include "atom_vec_body.h" #include "body_nparticle.h" #include "force.h" #include "neighbor.h" #include "neigh_list.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define DELTA 10000 /* ---------------------------------------------------------------------- */ PairBody::PairBody(LAMMPS *lmp) : Pair(lmp) { dmax = nmax = 0; discrete = NULL; dnum = dfirst = NULL; single_enable = 0; restartinfo = 0; } /* ---------------------------------------------------------------------- */ PairBody::~PairBody() { memory->destroy(discrete); memory->destroy(dnum); memory->destroy(dfirst); 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); } } /* ---------------------------------------------------------------------- */ void PairBody::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; int ni,nj,npi,npj,ifirst,jfirst; double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair; double rsq,r2inv,r6inv,forcelj; double xi[3],xj[3],fi[3],fj[3],ti[3],tj[3]; double *dxi,*dxj; 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; double **torque = atom->torque; int *body = atom->body; int *type = atom->type; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; int newton_pair = force->newton_pair; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // grow discrete list if necessary and initialize if (nall > nmax) { nmax = nall; memory->destroy(dnum); memory->destroy(dfirst); memory->create(dnum,nall,"pair:dnum"); memory->create(dfirst,nall,"pair:dfirst"); } for (i = 0; i < nall; i++) dnum[i] = 0; ndiscrete = 0; // 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]; if (rsq >= cutsq[itype][jtype]) continue; // body/body interactions = NxM sub-particles evdwl = 0.0; if (body[i] >= 0 && body[j] >= 0) { if (dnum[i] == 0) body2space(i); npi = dnum[i]; ifirst = dfirst[i]; if (dnum[j] == 0) body2space(j); npj = dnum[j]; jfirst = dfirst[j]; for (ni = 0; ni < npi; ni++) { dxi = discrete[ifirst+ni]; for (nj = 0; nj < npj; nj++) { dxj = discrete[jfirst+nj]; xi[0] = x[i][0] + dxi[0]; xi[1] = x[i][1] + dxi[1]; xi[2] = x[i][2] + dxi[2]; xj[0] = x[j][0] + dxj[0]; xj[1] = x[j][1] + dxj[1]; xj[2] = x[j][2] + dxj[2]; delx = xi[0] - xj[0]; dely = xi[1] - xj[1]; delz = xi[2] - xj[2]; rsq = delx*delx + dely*dely + delz*delz; r2inv = 1.0/rsq; r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); fpair = forcelj*r2inv; if (eflag) evdwl += r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]); fi[0] = delx*fpair; fi[1] = dely*fpair; fi[2] = delz*fpair; f[i][0] += fi[0]; f[i][1] += fi[1]; f[i][2] += fi[2]; ti[0] = dxi[1]*fi[2] - dxi[2]*fi[1]; ti[1] = dxi[2]*fi[0] - dxi[0]*fi[2]; ti[2] = dxi[0]*fi[1] - dxi[1]*fi[0]; torque[i][0] += ti[0]; torque[i][1] += ti[1]; torque[i][2] += ti[2]; if (newton_pair || j < nlocal) { fj[0] = -delx*fpair; fj[1] = -dely*fpair; fj[2] = -delz*fpair; f[j][0] += fj[0]; f[j][1] += fj[1]; f[j][2] += fj[2]; tj[0] = dxj[1]*fj[2] - dxj[2]*fj[1]; tj[1] = dxj[2]*fj[0] - dxj[0]*fj[2]; tj[2] = dxj[0]*fj[1] - dxj[1]*fj[0]; torque[j][0] += tj[0]; torque[j][1] += tj[1]; torque[j][2] += tj[2]; } } } // body/particle interaction = Nx1 sub-particles } else if (body[i] >= 0) { if (dnum[i] == 0) body2space(i); npi = dnum[i]; ifirst = dfirst[i]; for (ni = 0; ni < npi; ni++) { dxi = discrete[ifirst+ni]; xi[0] = x[i][0] + dxi[0]; xi[1] = x[i][1] + dxi[1]; xi[2] = x[i][2] + dxi[2]; xj[0] = x[j][0]; xj[1] = x[j][1]; xj[2] = x[j][2]; delx = xi[0] - xj[0]; dely = xi[1] - xj[1]; delz = xi[2] - xj[2]; rsq = delx*delx + dely*dely + delz*delz; r2inv = 1.0/rsq; r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); fpair = forcelj*r2inv; if (eflag) evdwl += r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]); fi[0] = delx*fpair; fi[1] = dely*fpair; fi[2] = delz*fpair; f[i][0] += fi[0]; f[i][1] += fi[1]; f[i][2] += fi[2]; ti[0] = dxi[1]*fi[2] - dxi[2]*fi[1]; ti[1] = dxi[2]*fi[0] - dxi[0]*fi[2]; ti[2] = dxi[0]*fi[1] - dxi[1]*fi[0]; torque[i][0] += ti[0]; torque[i][1] += ti[1]; torque[i][2] += ti[2]; if (newton_pair || j < nlocal) { fj[0] = -delx*fpair; fj[1] = -dely*fpair; fj[2] = -delz*fpair; f[j][0] += fj[0]; f[j][1] += fj[1]; f[j][2] += fj[2]; } } // particle/body interaction = Nx1 sub-particles } else if (body[j] >= 0) { if (dnum[j] == 0) body2space(j); npj = dnum[j]; jfirst = dfirst[j]; for (nj = 0; nj < npj; nj++) { dxj = discrete[jfirst+nj]; xi[0] = x[i][0]; xi[1] = x[i][1]; xi[2] = x[i][2]; xj[0] = x[j][0] + dxj[0]; xj[1] = x[j][1] + dxj[1]; xj[2] = x[j][2] + dxj[2]; delx = xi[0] - xj[0]; dely = xi[1] - xj[1]; delz = xi[2] - xj[2]; rsq = delx*delx + dely*dely + delz*delz; r2inv = 1.0/rsq; r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); fpair = forcelj*r2inv; if (eflag) evdwl += r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]); fi[0] = delx*fpair; fi[1] = dely*fpair; fi[2] = delz*fpair; f[i][0] += fi[0]; f[i][1] += fi[1]; f[i][2] += fi[2]; if (newton_pair || j < nlocal) { fj[0] = -delx*fpair; fj[1] = -dely*fpair; fj[2] = -delz*fpair; f[j][0] += fj[0]; f[j][1] += fj[1]; f[j][2] += fj[2]; tj[0] = dxj[1]*fj[2] - dxj[2]*fj[1]; tj[1] = dxj[2]*fj[0] - dxj[0]*fj[2]; tj[2] = dxj[0]*fj[1] - dxj[1]*fj[0]; torque[j][0] += tj[0]; torque[j][1] += tj[1]; torque[j][2] += tj[2]; } } // particle/particle interaction = 1x1 particles } else { r2inv = 1.0/rsq; r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); fpair = forcelj*r2inv; if (eflag) evdwl += r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]); 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 (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 PairBody::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"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairBody::settings(int narg, char **arg) { if (narg != 1) error->all(FLERR,"Illegal pair_style command"); cut_global = force->numeric(FLERR,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 PairBody::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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(FLERR,arg[2]); double sigma_one = force->numeric(FLERR,arg[3]); double cut_one = cut_global; if (narg == 5) cut_one = force->numeric(FLERR,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 PairBody::init_style() { avec = (AtomVecBody *) atom->style_match("body"); if (!avec) error->all(FLERR,"Pair body requires atom style body"); if (strcmp(avec->bptr->style,"nparticle") != 0) error->all(FLERR,"Pair body requires body style nparticle"); bptr = (BodyNparticle *) avec->bptr; neighbor->request(this,instance_me); } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairBody::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); epsilon[j][i] = epsilon[i][j]; sigma[j][i] = sigma[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]; return cut[i][j]; } /* ---------------------------------------------------------------------- convert N sub-particles in body I to space frame using current quaternion store sub-particle space-frame displacements from COM in discrete list ------------------------------------------------------------------------- */ void PairBody::body2space(int i) { int ibonus = atom->body[i]; AtomVecBody::Bonus *bonus = &avec->bonus[ibonus]; int nsub = bptr->nsub(bonus); double *coords = bptr->coords(bonus); dnum[i] = nsub; dfirst[i] = ndiscrete; if (ndiscrete + nsub > dmax) { dmax += DELTA; memory->grow(discrete,dmax,3,"pair:discrete"); } double p[3][3]; MathExtra::quat_to_mat(bonus->quat,p); for (int m = 0; m < nsub; m++) { MathExtra::matvec(p,&coords[3*m],discrete[ndiscrete]); ndiscrete++; } } diff --git a/src/CLASS2/angle_class2.cpp b/src/CLASS2/angle_class2.cpp index ceeba5567..0315e6601 100644 --- a/src/CLASS2/angle_class2.cpp +++ b/src/CLASS2/angle_class2.cpp @@ -1,465 +1,465 @@ /* ---------------------------------------------------------------------- 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: Eric Simon (Cray) ------------------------------------------------------------------------- */ #include #include #include #include "angle_class2.h" #include "atom.h" #include "neighbor.h" #include "domain.h" #include "comm.h" #include "force.h" #include "math_const.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace MathConst; #define SMALL 0.001 /* ---------------------------------------------------------------------- */ AngleClass2::AngleClass2(LAMMPS *lmp) : Angle(lmp) {} /* ---------------------------------------------------------------------- */ AngleClass2::~AngleClass2() { if (allocated) { memory->destroy(setflag); memory->destroy(setflag_a); memory->destroy(setflag_bb); memory->destroy(setflag_ba); memory->destroy(theta0); memory->destroy(k2); memory->destroy(k3); memory->destroy(k4); memory->destroy(bb_k); memory->destroy(bb_r1); memory->destroy(bb_r2); memory->destroy(ba_k1); memory->destroy(ba_k2); memory->destroy(ba_r1); memory->destroy(ba_r2); } } /* ---------------------------------------------------------------------- */ void AngleClass2::compute(int eflag, int vflag) { int i1,i2,i3,n,type; double delx1,dely1,delz1,delx2,dely2,delz2; double eangle,f1[3],f3[3]; double dtheta,dtheta2,dtheta3,dtheta4,de_angle; double dr1,dr2,tk1,tk2,aa1,aa2,aa11,aa12,aa21,aa22; double rsq1,rsq2,r1,r2,c,s,a,a11,a12,a22,b1,b2; double vx11,vx12,vy11,vy12,vz11,vz12,vx21,vx22,vy21,vy22,vz21,vz22; eangle = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; int **anglelist = neighbor->anglelist; int nanglelist = neighbor->nanglelist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < nanglelist; n++) { i1 = anglelist[n][0]; i2 = anglelist[n][1]; i3 = anglelist[n][2]; type = anglelist[n][3]; // 1st bond delx1 = x[i1][0] - x[i2][0]; dely1 = x[i1][1] - x[i2][1]; delz1 = x[i1][2] - x[i2][2]; rsq1 = delx1*delx1 + dely1*dely1 + delz1*delz1; r1 = sqrt(rsq1); // 2nd bond delx2 = x[i3][0] - x[i2][0]; dely2 = x[i3][1] - x[i2][1]; delz2 = x[i3][2] - x[i2][2]; rsq2 = delx2*delx2 + dely2*dely2 + delz2*delz2; r2 = sqrt(rsq2); // angle (cos and sin) c = delx1*delx2 + dely1*dely2 + delz1*delz2; c /= r1*r2; if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; s = sqrt(1.0 - c*c); if (s < SMALL) s = SMALL; s = 1.0/s; // force & energy for angle term dtheta = acos(c) - theta0[type]; dtheta2 = dtheta*dtheta; dtheta3 = dtheta2*dtheta; dtheta4 = dtheta3*dtheta; de_angle = 2.0*k2[type]*dtheta + 3.0*k3[type]*dtheta2 + 4.0*k4[type]*dtheta3; a = -de_angle*s; a11 = a*c / rsq1; a12 = -a / (r1*r2); a22 = a*c / rsq2; f1[0] = a11*delx1 + a12*delx2; f1[1] = a11*dely1 + a12*dely2; f1[2] = a11*delz1 + a12*delz2; f3[0] = a22*delx2 + a12*delx1; f3[1] = a22*dely2 + a12*dely1; f3[2] = a22*delz2 + a12*delz1; if (eflag) eangle = k2[type]*dtheta2 + k3[type]*dtheta3 + k4[type]*dtheta4; // force & energy for bond-bond term dr1 = r1 - bb_r1[type]; dr2 = r2 - bb_r2[type]; tk1 = bb_k[type] * dr1; tk2 = bb_k[type] * dr2; f1[0] -= delx1*tk2/r1; f1[1] -= dely1*tk2/r1; f1[2] -= delz1*tk2/r1; f3[0] -= delx2*tk1/r2; f3[1] -= dely2*tk1/r2; f3[2] -= delz2*tk1/r2; if (eflag) eangle += bb_k[type]*dr1*dr2; // force & energy for bond-angle term aa1 = s * dr1 * ba_k1[type]; aa2 = s * dr2 * ba_k2[type]; aa11 = aa1 * c / rsq1; aa12 = -aa1 / (r1 * r2); aa21 = aa2 * c / rsq1; aa22 = -aa2 / (r1 * r2); vx11 = (aa11 * delx1) + (aa12 * delx2); vx12 = (aa21 * delx1) + (aa22 * delx2); vy11 = (aa11 * dely1) + (aa12 * dely2); vy12 = (aa21 * dely1) + (aa22 * dely2); vz11 = (aa11 * delz1) + (aa12 * delz2); vz12 = (aa21 * delz1) + (aa22 * delz2); aa11 = aa1 * c / rsq2; aa21 = aa2 * c / rsq2; vx21 = (aa11 * delx2) + (aa12 * delx1); vx22 = (aa21 * delx2) + (aa22 * delx1); vy21 = (aa11 * dely2) + (aa12 * dely1); vy22 = (aa21 * dely2) + (aa22 * dely1); vz21 = (aa11 * delz2) + (aa12 * delz1); vz22 = (aa21 * delz2) + (aa22 * delz1); b1 = ba_k1[type] * dtheta / r1; b2 = ba_k2[type] * dtheta / r2; f1[0] -= vx11 + b1*delx1 + vx12; f1[1] -= vy11 + b1*dely1 + vy12; f1[2] -= vz11 + b1*delz1 + vz12; f3[0] -= vx21 + b2*delx2 + vx22; f3[1] -= vy21 + b2*dely2 + vy22; f3[2] -= vz21 + b2*delz2 + vz22; if (eflag) eangle += ba_k1[type]*dr1*dtheta + ba_k2[type]*dr2*dtheta; // apply force to each of 3 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += f1[0]; f[i1][1] += f1[1]; f[i1][2] += f1[2]; } if (newton_bond || i2 < nlocal) { f[i2][0] -= f1[0] + f3[0]; f[i2][1] -= f1[1] + f3[1]; f[i2][2] -= f1[2] + f3[2]; } if (newton_bond || i3 < nlocal) { f[i3][0] += f3[0]; f[i3][1] += f3[1]; f[i3][2] += f3[2]; } if (evflag) ev_tally(i1,i2,i3,nlocal,newton_bond,eangle,f1,f3, delx1,dely1,delz1,delx2,dely2,delz2); } } /* ---------------------------------------------------------------------- */ void AngleClass2::allocate() { allocated = 1; int n = atom->nangletypes; memory->create(theta0,n+1,"angle:theta0"); memory->create(k2,n+1,"angle:k2"); memory->create(k3,n+1,"angle:k3"); memory->create(k4,n+1,"angle:k4"); memory->create(bb_k,n+1,"angle:bb_k"); memory->create(bb_r1,n+1,"angle:bb_r1"); memory->create(bb_r2,n+1,"angle:bb_r2"); memory->create(ba_k1,n+1,"angle:ba_k1"); memory->create(ba_k2,n+1,"angle:ba_k2"); memory->create(ba_r1,n+1,"angle:ba_r1"); memory->create(ba_r2,n+1,"angle:ba_r2"); memory->create(setflag,n+1,"angle:setflag"); memory->create(setflag_a,n+1,"angle:setflag_a"); memory->create(setflag_bb,n+1,"angle:setflag_bb"); memory->create(setflag_ba,n+1,"angle:setflag_ba"); for (int i = 1; i <= n; i++) setflag[i] = setflag_a[i] = setflag_bb[i] = setflag_ba[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one or more types arg1 = "bb" -> BondBond coeffs arg1 = "ba" -> BondAngle coeffs else -> Angle coeffs ------------------------------------------------------------------------- */ void AngleClass2::coeff(int narg, char **arg) { if (narg < 2) error->all(FLERR,"Incorrect args for angle coefficients"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->nangletypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->nangletypes,ilo,ihi); int count = 0; if (strcmp(arg[1],"bb") == 0) { if (narg != 5) error->all(FLERR,"Incorrect args for angle coefficients"); double bb_k_one = force->numeric(FLERR,arg[2]); double bb_r1_one = force->numeric(FLERR,arg[3]); double bb_r2_one = force->numeric(FLERR,arg[4]); for (int i = ilo; i <= ihi; i++) { bb_k[i] = bb_k_one; bb_r1[i] = bb_r1_one; bb_r2[i] = bb_r2_one; setflag_bb[i] = 1; count++; } } else if (strcmp(arg[1],"ba") == 0) { if (narg != 6) error->all(FLERR,"Incorrect args for angle coefficients"); double ba_k1_one = force->numeric(FLERR,arg[2]); double ba_k2_one = force->numeric(FLERR,arg[3]); double ba_r1_one = force->numeric(FLERR,arg[4]); double ba_r2_one = force->numeric(FLERR,arg[5]); for (int i = ilo; i <= ihi; i++) { ba_k1[i] = ba_k1_one; ba_k2[i] = ba_k2_one; ba_r1[i] = ba_r1_one; ba_r2[i] = ba_r2_one; setflag_ba[i] = 1; count++; } } else { if (narg != 5) error->all(FLERR,"Incorrect args for angle coefficients"); double theta0_one = force->numeric(FLERR,arg[1]); double k2_one = force->numeric(FLERR,arg[2]); double k3_one = force->numeric(FLERR,arg[3]); double k4_one = force->numeric(FLERR,arg[4]); // convert theta0 from degrees to radians for (int i = ilo; i <= ihi; i++) { theta0[i] = theta0_one/180.0 * MY_PI; k2[i] = k2_one; k3[i] = k3_one; k4[i] = k4_one; setflag_a[i] = 1; count++; } } if (count == 0) error->all(FLERR,"Incorrect args for angle coefficients"); for (int i = ilo; i <= ihi; i++) if (setflag_a[i] == 1 && setflag_bb[i] == 1 && setflag_ba[i] == 1) setflag[i] = 1; } /* ---------------------------------------------------------------------- */ double AngleClass2::equilibrium_angle(int i) { return theta0[i]; } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void AngleClass2::write_restart(FILE *fp) { fwrite(&theta0[1],sizeof(double),atom->nangletypes,fp); fwrite(&k2[1],sizeof(double),atom->nangletypes,fp); fwrite(&k3[1],sizeof(double),atom->nangletypes,fp); fwrite(&k4[1],sizeof(double),atom->nangletypes,fp); fwrite(&bb_k[1],sizeof(double),atom->nangletypes,fp); fwrite(&bb_r1[1],sizeof(double),atom->nangletypes,fp); fwrite(&bb_r2[1],sizeof(double),atom->nangletypes,fp); fwrite(&ba_k1[1],sizeof(double),atom->nangletypes,fp); fwrite(&ba_k2[1],sizeof(double),atom->nangletypes,fp); fwrite(&ba_r1[1],sizeof(double),atom->nangletypes,fp); fwrite(&ba_r2[1],sizeof(double),atom->nangletypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void AngleClass2::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&theta0[1],sizeof(double),atom->nangletypes,fp); fread(&k2[1],sizeof(double),atom->nangletypes,fp); fread(&k3[1],sizeof(double),atom->nangletypes,fp); fread(&k4[1],sizeof(double),atom->nangletypes,fp); fread(&bb_k[1],sizeof(double),atom->nangletypes,fp); fread(&bb_r1[1],sizeof(double),atom->nangletypes,fp); fread(&bb_r2[1],sizeof(double),atom->nangletypes,fp); fread(&ba_k1[1],sizeof(double),atom->nangletypes,fp); fread(&ba_k2[1],sizeof(double),atom->nangletypes,fp); fread(&ba_r1[1],sizeof(double),atom->nangletypes,fp); fread(&ba_r2[1],sizeof(double),atom->nangletypes,fp); } MPI_Bcast(&theta0[1],atom->nangletypes,MPI_DOUBLE,0,world); MPI_Bcast(&k2[1],atom->nangletypes,MPI_DOUBLE,0,world); MPI_Bcast(&k3[1],atom->nangletypes,MPI_DOUBLE,0,world); MPI_Bcast(&k4[1],atom->nangletypes,MPI_DOUBLE,0,world); MPI_Bcast(&bb_k[1],atom->nangletypes,MPI_DOUBLE,0,world); MPI_Bcast(&bb_r1[1],atom->nangletypes,MPI_DOUBLE,0,world); MPI_Bcast(&bb_r2[1],atom->nangletypes,MPI_DOUBLE,0,world); MPI_Bcast(&ba_k1[1],atom->nangletypes,MPI_DOUBLE,0,world); MPI_Bcast(&ba_k2[1],atom->nangletypes,MPI_DOUBLE,0,world); MPI_Bcast(&ba_r1[1],atom->nangletypes,MPI_DOUBLE,0,world); MPI_Bcast(&ba_r2[1],atom->nangletypes,MPI_DOUBLE,0,world); for (int i = 1; i <= atom->nangletypes; i++) setflag[i] = 1; } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void AngleClass2::write_data(FILE *fp) { for (int i = 1; i <= atom->nangletypes; i++) fprintf(fp,"%d %g %g %g %g\n", i,theta0[i]/MY_PI*180.0,k2[i],k3[i],k4[i]); fprintf(fp,"\nBondBond Coeffs\n\n"); for (int i = 1; i <= atom->nangletypes; i++) fprintf(fp,"%d %g %g %g\n",i,bb_k[i],bb_r1[i],bb_r2[i]); fprintf(fp,"\nBondAngle Coeffs\n\n"); for (int i = 1; i <= atom->nangletypes; i++) fprintf(fp,"%d %g %g %g %g\n",i,ba_k1[i],ba_k2[i],ba_r1[i],ba_r2[i]); } /* ---------------------------------------------------------------------- */ double AngleClass2::single(int type, int i1, int i2, int i3) { double **x = atom->x; double delx1 = x[i1][0] - x[i2][0]; double dely1 = x[i1][1] - x[i2][1]; double delz1 = x[i1][2] - x[i2][2]; domain->minimum_image(delx1,dely1,delz1); double r1 = sqrt(delx1*delx1 + dely1*dely1 + delz1*delz1); double delx2 = x[i3][0] - x[i2][0]; double dely2 = x[i3][1] - x[i2][1]; double delz2 = x[i3][2] - x[i2][2]; domain->minimum_image(delx2,dely2,delz2); double r2 = sqrt(delx2*delx2 + dely2*dely2 + delz2*delz2); double c = delx1*delx2 + dely1*dely2 + delz1*delz2; c /= r1*r2; if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; double s = sqrt(1.0 - c*c); if (s < SMALL) s = SMALL; s = 1.0/s; double dtheta = acos(c) - theta0[type]; double dtheta2 = dtheta*dtheta; double dtheta3 = dtheta2*dtheta; double dtheta4 = dtheta3*dtheta; double energy = k2[type]*dtheta2 + k3[type]*dtheta3 + k4[type]*dtheta4; double dr1 = r1 - bb_r1[type]; double dr2 = r2 - bb_r2[type]; energy += bb_k[type]*dr1*dr2; energy += ba_k1[type]*dr1*dtheta + ba_k2[type]*dr2*dtheta; return energy; } diff --git a/src/CLASS2/bond_class2.cpp b/src/CLASS2/bond_class2.cpp index b87deed5a..f358720e7 100644 --- a/src/CLASS2/bond_class2.cpp +++ b/src/CLASS2/bond_class2.cpp @@ -1,221 +1,221 @@ /* ---------------------------------------------------------------------- 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: Eric Simon (Cray) ------------------------------------------------------------------------- */ #include #include #include "bond_class2.h" #include "atom.h" #include "neighbor.h" #include "domain.h" #include "comm.h" #include "force.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ BondClass2::BondClass2(LAMMPS *lmp) : Bond(lmp) {} /* ---------------------------------------------------------------------- */ BondClass2::~BondClass2() { if (allocated) { memory->destroy(setflag); memory->destroy(r0); memory->destroy(k2); memory->destroy(k3); memory->destroy(k4); } } /* ---------------------------------------------------------------------- */ void BondClass2::compute(int eflag, int vflag) { int i1,i2,n,type; double delx,dely,delz,ebond,fbond; double rsq,r,dr,dr2,dr3,dr4,de_bond; ebond = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; int **bondlist = neighbor->bondlist; int nbondlist = neighbor->nbondlist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < nbondlist; n++) { i1 = bondlist[n][0]; i2 = bondlist[n][1]; type = bondlist[n][2]; delx = x[i1][0] - x[i2][0]; dely = x[i1][1] - x[i2][1]; delz = x[i1][2] - x[i2][2]; rsq = delx*delx + dely*dely + delz*delz; r = sqrt(rsq); dr = r - r0[type]; dr2 = dr*dr; dr3 = dr2*dr; dr4 = dr3*dr; // force & energy de_bond = 2.0*k2[type]*dr + 3.0*k3[type]*dr2 + 4.0*k4[type]*dr3; if (r > 0.0) fbond = -de_bond/r; else fbond = 0.0; if (eflag) ebond = k2[type]*dr2 + k3[type]*dr3 + k4[type]*dr4; // apply force to each of 2 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += delx*fbond; f[i1][1] += dely*fbond; f[i1][2] += delz*fbond; } if (newton_bond || i2 < nlocal) { f[i2][0] -= delx*fbond; f[i2][1] -= dely*fbond; f[i2][2] -= delz*fbond; } if (evflag) ev_tally(i1,i2,nlocal,newton_bond,ebond,fbond,delx,dely,delz); } } /* ---------------------------------------------------------------------- */ void BondClass2::allocate() { allocated = 1; int n = atom->nbondtypes; memory->create(r0,n+1,"bond:r0"); memory->create(k2,n+1,"bond:k2"); memory->create(k3,n+1,"bond:k3"); memory->create(k4,n+1,"bond:k4"); memory->create(setflag,n+1,"bond:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs from one line in input script or data file ------------------------------------------------------------------------- */ void BondClass2::coeff(int narg, char **arg) { if (narg != 5) error->all(FLERR,"Incorrect args for bond coefficients"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->nbondtypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->nbondtypes,ilo,ihi); double r0_one = force->numeric(FLERR,arg[1]); double k2_one = force->numeric(FLERR,arg[2]); double k3_one = force->numeric(FLERR,arg[3]); double k4_one = force->numeric(FLERR,arg[4]); int count = 0; for (int i = ilo; i <= ihi; i++) { r0[i] = r0_one; k2[i] = k2_one; k3[i] = k3_one; k4[i] = k4_one; setflag[i] = 1; count++; } if (count == 0) error->all(FLERR,"Incorrect args for bond coefficients"); } /* ---------------------------------------------------------------------- return an equilbrium bond length ------------------------------------------------------------------------- */ double BondClass2::equilibrium_distance(int i) { return r0[i]; } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void BondClass2::write_restart(FILE *fp) { fwrite(&r0[1],sizeof(double),atom->nbondtypes,fp); fwrite(&k2[1],sizeof(double),atom->nbondtypes,fp); fwrite(&k3[1],sizeof(double),atom->nbondtypes,fp); fwrite(&k4[1],sizeof(double),atom->nbondtypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void BondClass2::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&r0[1],sizeof(double),atom->nbondtypes,fp); fread(&k2[1],sizeof(double),atom->nbondtypes,fp); fread(&k3[1],sizeof(double),atom->nbondtypes,fp); fread(&k4[1],sizeof(double),atom->nbondtypes,fp); } MPI_Bcast(&r0[1],atom->nbondtypes,MPI_DOUBLE,0,world); MPI_Bcast(&k2[1],atom->nbondtypes,MPI_DOUBLE,0,world); MPI_Bcast(&k3[1],atom->nbondtypes,MPI_DOUBLE,0,world); MPI_Bcast(&k4[1],atom->nbondtypes,MPI_DOUBLE,0,world); for (int i = 1; i <= atom->nbondtypes; i++) setflag[i] = 1; } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void BondClass2::write_data(FILE *fp) { for (int i = 1; i <= atom->nbondtypes; i++) fprintf(fp,"%d %g %g %g %g\n",i,r0[i],k2[i],k3[i],k4[i]); } /* ---------------------------------------------------------------------- */ double BondClass2::single(int type, double rsq, int i, int j, double &fforce) { double r = sqrt(rsq); double dr = r - r0[type]; double dr2 = dr*dr; double dr3 = dr2*dr; double dr4 = dr3*dr; double de_bond = 2.0*k2[type]*dr + 3.0*k3[type]*dr2 + 4.0*k4[type]*dr3; if (r > 0.0) fforce = -de_bond/r; else fforce = 0.0; return (k2[type]*dr2 + k3[type]*dr3 + k4[type]*dr4); } diff --git a/src/CLASS2/dihedral_class2.cpp b/src/CLASS2/dihedral_class2.cpp index d18d75b15..78be10fbc 100644 --- a/src/CLASS2/dihedral_class2.cpp +++ b/src/CLASS2/dihedral_class2.cpp @@ -1,961 +1,961 @@ /* ---------------------------------------------------------------------- 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: Eric Simon (Cray) ------------------------------------------------------------------------- */ #include #include #include #include "dihedral_class2.h" #include "atom.h" #include "neighbor.h" #include "update.h" #include "domain.h" #include "comm.h" #include "force.h" #include "math_const.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace MathConst; #define TOLERANCE 0.05 #define SMALL 0.0000001 /* ---------------------------------------------------------------------- */ DihedralClass2::DihedralClass2(LAMMPS *lmp) : Dihedral(lmp) { writedata = 1; } /* ---------------------------------------------------------------------- */ DihedralClass2::~DihedralClass2() { if (allocated) { memory->destroy(setflag); memory->destroy(setflag_d); memory->destroy(setflag_mbt); memory->destroy(setflag_ebt); memory->destroy(setflag_at); memory->destroy(setflag_aat); memory->destroy(setflag_bb13t); memory->destroy(k1); memory->destroy(k2); memory->destroy(k3); memory->destroy(phi1); memory->destroy(phi2); memory->destroy(phi3); memory->destroy(mbt_f1); memory->destroy(mbt_f2); memory->destroy(mbt_f3); memory->destroy(mbt_r0); memory->destroy(ebt_f1_1); memory->destroy(ebt_f2_1); memory->destroy(ebt_f3_1); memory->destroy(ebt_r0_1); memory->destroy(ebt_f1_2); memory->destroy(ebt_f2_2); memory->destroy(ebt_f3_2); memory->destroy(ebt_r0_2); memory->destroy(at_f1_1); memory->destroy(at_f2_1); memory->destroy(at_f3_1); memory->destroy(at_theta0_1); memory->destroy(at_f1_2); memory->destroy(at_f2_2); memory->destroy(at_f3_2); memory->destroy(at_theta0_2); memory->destroy(aat_k); memory->destroy(aat_theta0_1); memory->destroy(aat_theta0_2); memory->destroy(bb13t_k); memory->destroy(bb13t_r10); memory->destroy(bb13t_r30); } } /* ---------------------------------------------------------------------- */ void DihedralClass2::compute(int eflag, int vflag) { int i1,i2,i3,i4,i,j,k,n,type; double vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z,vb2xm,vb2ym,vb2zm; double edihedral; double r1mag2,r1,r2mag2,r2,r3mag2,r3; double sb1,rb1,sb2,rb2,sb3,rb3,c0,r12c1; double r12c2,costh12,costh13,costh23,sc1,sc2,s1,s2,c; double cosphi,phi,sinphi,a11,a22,a33,a12,a13,a23,sx1,sx2; double sx12,sy1,sy2,sy12,sz1,sz2,sz12,dphi1,dphi2,dphi3; double de_dihedral,t1,t2,t3,t4,cos2phi,cos3phi,bt1,bt2; double bt3,sumbte,db,sumbtf,at1,at2,at3,da,da1,da2,r1_0; double r3_0,dr1,dr2,tk1,tk2,s12,sin2; double dcosphidr[4][3],dphidr[4][3],dbonddr[3][4][3],dthetadr[2][4][3]; double fabcd[4][3]; edihedral = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; int **dihedrallist = neighbor->dihedrallist; int ndihedrallist = neighbor->ndihedrallist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < ndihedrallist; n++) { i1 = dihedrallist[n][0]; i2 = dihedrallist[n][1]; i3 = dihedrallist[n][2]; i4 = dihedrallist[n][3]; type = dihedrallist[n][4]; // 1st bond vb1x = x[i1][0] - x[i2][0]; vb1y = x[i1][1] - x[i2][1]; vb1z = x[i1][2] - x[i2][2]; // 2nd bond vb2x = x[i3][0] - x[i2][0]; vb2y = x[i3][1] - x[i2][1]; vb2z = x[i3][2] - x[i2][2]; vb2xm = -vb2x; vb2ym = -vb2y; vb2zm = -vb2z; // 3rd bond vb3x = x[i4][0] - x[i3][0]; vb3y = x[i4][1] - x[i3][1]; vb3z = x[i4][2] - x[i3][2]; // distances r1mag2 = vb1x*vb1x + vb1y*vb1y + vb1z*vb1z; r1 = sqrt(r1mag2); r2mag2 = vb2x*vb2x + vb2y*vb2y + vb2z*vb2z; r2 = sqrt(r2mag2); r3mag2 = vb3x*vb3x + vb3y*vb3y + vb3z*vb3z; r3 = sqrt(r3mag2); sb1 = 1.0/r1mag2; rb1 = 1.0/r1; sb2 = 1.0/r2mag2; rb2 = 1.0/r2; sb3 = 1.0/r3mag2; rb3 = 1.0/r3; c0 = (vb1x*vb3x + vb1y*vb3y + vb1z*vb3z) * rb1*rb3; // angles r12c1 = rb1*rb2; r12c2 = rb2*rb3; costh12 = (vb1x*vb2x + vb1y*vb2y + vb1z*vb2z) * r12c1; costh13 = c0; costh23 = (vb2xm*vb3x + vb2ym*vb3y + vb2zm*vb3z) * r12c2; // cos and sin of 2 angles and final c sin2 = MAX(1.0 - costh12*costh12,0.0); sc1 = sqrt(sin2); if (sc1 < SMALL) sc1 = SMALL; sc1 = 1.0/sc1; sin2 = MAX(1.0 - costh23*costh23,0.0); sc2 = sqrt(sin2); if (sc2 < SMALL) sc2 = SMALL; sc2 = 1.0/sc2; s1 = sc1 * sc1; s2 = sc2 * sc2; s12 = sc1 * sc2; c = (c0 + costh12*costh23) * s12; // error check if (c > 1.0 + TOLERANCE || c < (-1.0 - TOLERANCE)) { int me; MPI_Comm_rank(world,&me); if (screen) { char str[128]; sprintf(str,"Dihedral problem: %d " BIGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT, me,update->ntimestep, atom->tag[i1],atom->tag[i2],atom->tag[i3],atom->tag[i4]); error->warning(FLERR,str,0); fprintf(screen," 1st atom: %d %g %g %g\n", me,x[i1][0],x[i1][1],x[i1][2]); fprintf(screen," 2nd atom: %d %g %g %g\n", me,x[i2][0],x[i2][1],x[i2][2]); fprintf(screen," 3rd atom: %d %g %g %g\n", me,x[i3][0],x[i3][1],x[i3][2]); fprintf(screen," 4th atom: %d %g %g %g\n", me,x[i4][0],x[i4][1],x[i4][2]); } } if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; cosphi = c; phi = acos(c); sinphi = sqrt(1.0 - c*c); sinphi = MAX(sinphi,SMALL); // n123 = vb1 x vb2 double n123x = vb1y*vb2z - vb1z*vb2y; double n123y = vb1z*vb2x - vb1x*vb2z; double n123z = vb1x*vb2y - vb1y*vb2x; double n123_dot_vb3 = n123x*vb3x + n123y*vb3y + n123z*vb3z; if (n123_dot_vb3 > 0.0) { phi = -phi; sinphi = -sinphi; } a11 = -c*sb1*s1; a22 = sb2 * (2.0*costh13*s12 - c*(s1+s2)); a33 = -c*sb3*s2; a12 = r12c1 * (costh12*c*s1 + costh23*s12); a13 = rb1*rb3*s12; a23 = r12c2 * (-costh23*c*s2 - costh12*s12); sx1 = a11*vb1x + a12*vb2x + a13*vb3x; sx2 = a12*vb1x + a22*vb2x + a23*vb3x; sx12 = a13*vb1x + a23*vb2x + a33*vb3x; sy1 = a11*vb1y + a12*vb2y + a13*vb3y; sy2 = a12*vb1y + a22*vb2y + a23*vb3y; sy12 = a13*vb1y + a23*vb2y + a33*vb3y; sz1 = a11*vb1z + a12*vb2z + a13*vb3z; sz2 = a12*vb1z + a22*vb2z + a23*vb3z; sz12 = a13*vb1z + a23*vb2z + a33*vb3z; // set up d(cos(phi))/d(r) and dphi/dr arrays dcosphidr[0][0] = -sx1; dcosphidr[0][1] = -sy1; dcosphidr[0][2] = -sz1; dcosphidr[1][0] = sx2 + sx1; dcosphidr[1][1] = sy2 + sy1; dcosphidr[1][2] = sz2 + sz1; dcosphidr[2][0] = sx12 - sx2; dcosphidr[2][1] = sy12 - sy2; dcosphidr[2][2] = sz12 - sz2; dcosphidr[3][0] = -sx12; dcosphidr[3][1] = -sy12; dcosphidr[3][2] = -sz12; for (i = 0; i < 4; i++) for (j = 0; j < 3; j++) dphidr[i][j] = -dcosphidr[i][j] / sinphi; // energy dphi1 = phi - phi1[type]; dphi2 = 2.0*phi - phi2[type]; dphi3 = 3.0*phi - phi3[type]; if (eflag) edihedral = k1[type]*(1.0 - cos(dphi1)) + k2[type]*(1.0 - cos(dphi2)) + k3[type]*(1.0 - cos(dphi3)); de_dihedral = k1[type]*sin(dphi1) + 2.0*k2[type]*sin(dphi2) + 3.0*k3[type]*sin(dphi3); // torsion forces on all 4 atoms for (i = 0; i < 4; i++) for (j = 0; j < 3; j++) fabcd[i][j] = de_dihedral*dphidr[i][j]; // set up d(bond)/d(r) array // dbonddr(i,j,k) = bond i, atom j, coordinate k for (i = 0; i < 3; i++) for (j = 0; j < 4; j++) for (k = 0; k < 3; k++) dbonddr[i][j][k] = 0.0; // bond1 dbonddr[0][0][0] = vb1x / r1; dbonddr[0][0][1] = vb1y / r1; dbonddr[0][0][2] = vb1z / r1; dbonddr[0][1][0] = -vb1x / r1; dbonddr[0][1][1] = -vb1y / r1; dbonddr[0][1][2] = -vb1z / r1; // bond2 dbonddr[1][1][0] = vb2x / r2; dbonddr[1][1][1] = vb2y / r2; dbonddr[1][1][2] = vb2z / r2; dbonddr[1][2][0] = -vb2x / r2; dbonddr[1][2][1] = -vb2y / r2; dbonddr[1][2][2] = -vb2z / r2; // bond3 dbonddr[2][2][0] = vb3x / r3; dbonddr[2][2][1] = vb3y / r3; dbonddr[2][2][2] = vb3z / r3; dbonddr[2][3][0] = -vb3x / r3; dbonddr[2][3][1] = -vb3y / r3; dbonddr[2][3][2] = -vb3z / r3; // set up d(theta)/d(r) array // dthetadr(i,j,k) = angle i, atom j, coordinate k for (i = 0; i < 2; i++) for (j = 0; j < 4; j++) for (k = 0; k < 3; k++) dthetadr[i][j][k] = 0.0; t1 = costh12 / r1mag2; t2 = costh23 / r2mag2; t3 = costh12 / r2mag2; t4 = costh23 / r3mag2; // angle12 dthetadr[0][0][0] = sc1 * ((t1 * vb1x) - (vb2x * r12c1)); dthetadr[0][0][1] = sc1 * ((t1 * vb1y) - (vb2y * r12c1)); dthetadr[0][0][2] = sc1 * ((t1 * vb1z) - (vb2z * r12c1)); dthetadr[0][1][0] = sc1 * ((-t1 * vb1x) + (vb2x * r12c1) + (-t3 * vb2x) + (vb1x * r12c1)); dthetadr[0][1][1] = sc1 * ((-t1 * vb1y) + (vb2y * r12c1) + (-t3 * vb2y) + (vb1y * r12c1)); dthetadr[0][1][2] = sc1 * ((-t1 * vb1z) + (vb2z * r12c1) + (-t3 * vb2z) + (vb1z * r12c1)); dthetadr[0][2][0] = sc1 * ((t3 * vb2x) - (vb1x * r12c1)); dthetadr[0][2][1] = sc1 * ((t3 * vb2y) - (vb1y * r12c1)); dthetadr[0][2][2] = sc1 * ((t3 * vb2z) - (vb1z * r12c1)); // angle23 dthetadr[1][1][0] = sc2 * ((t2 * vb2x) + (vb3x * r12c2)); dthetadr[1][1][1] = sc2 * ((t2 * vb2y) + (vb3y * r12c2)); dthetadr[1][1][2] = sc2 * ((t2 * vb2z) + (vb3z * r12c2)); dthetadr[1][2][0] = sc2 * ((-t2 * vb2x) - (vb3x * r12c2) + (t4 * vb3x) + (vb2x * r12c2)); dthetadr[1][2][1] = sc2 * ((-t2 * vb2y) - (vb3y * r12c2) + (t4 * vb3y) + (vb2y * r12c2)); dthetadr[1][2][2] = sc2 * ((-t2 * vb2z) - (vb3z * r12c2) + (t4 * vb3z) + (vb2z * r12c2)); dthetadr[1][3][0] = -sc2 * ((t4 * vb3x) + (vb2x * r12c2)); dthetadr[1][3][1] = -sc2 * ((t4 * vb3y) + (vb2y * r12c2)); dthetadr[1][3][2] = -sc2 * ((t4 * vb3z) + (vb2z * r12c2)); // mid-bond/torsion coupling // energy on bond2 (middle bond) cos2phi = cos(2.0*phi); cos3phi = cos(3.0*phi); bt1 = mbt_f1[type] * cosphi; bt2 = mbt_f2[type] * cos2phi; bt3 = mbt_f3[type] * cos3phi; sumbte = bt1 + bt2 + bt3; db = r2 - mbt_r0[type]; if (eflag) edihedral += db * sumbte; // force on bond2 bt1 = -mbt_f1[type] * sinphi; bt2 = -2.0 * mbt_f2[type] * sin(2.0*phi); bt3 = -3.0 * mbt_f3[type] * sin(3.0*phi); sumbtf = bt1 + bt2 + bt3; for (i = 0; i < 4; i++) for (j = 0; j < 3; j++) fabcd[i][j] += db*sumbtf*dphidr[i][j] + sumbte*dbonddr[1][i][j]; // end-bond/torsion coupling // energy on bond1 (first bond) bt1 = ebt_f1_1[type] * cosphi; bt2 = ebt_f2_1[type] * cos2phi; bt3 = ebt_f3_1[type] * cos3phi; sumbte = bt1 + bt2 + bt3; db = r1 - ebt_r0_1[type]; if (eflag) edihedral += db * (bt1+bt2+bt3); // force on bond1 bt1 = ebt_f1_1[type] * sinphi; bt2 = 2.0 * ebt_f2_1[type] * sin(2.0*phi); bt3 = 3.0 * ebt_f3_1[type] * sin(3.0*phi); sumbtf = bt1 + bt2 + bt3; for (i = 0; i < 4; i++) for (j = 0; j < 3; j++) fabcd[i][j] -= db*sumbtf*dphidr[i][j] + sumbte*dbonddr[0][i][j]; // end-bond/torsion coupling // energy on bond3 (last bond) bt1 = ebt_f1_2[type] * cosphi; bt2 = ebt_f2_2[type] * cos2phi; bt3 = ebt_f3_2[type] * cos3phi; sumbte = bt1 + bt2 + bt3; db = r3 - ebt_r0_2[type]; if (eflag) edihedral += db * (bt1+bt2+bt3); // force on bond3 bt1 = -ebt_f1_2[type] * sinphi; bt2 = -2.0 * ebt_f2_2[type] * sin(2.0*phi); bt3 = -3.0 * ebt_f3_2[type] * sin(3.0*phi); sumbtf = bt1 + bt2 + bt3; for (i = 0; i < 4; i++) for (j = 0; j < 3; j++) fabcd[i][j] += db*sumbtf*dphidr[i][j] + sumbte*dbonddr[2][i][j]; // angle/torsion coupling // energy on angle1 at1 = at_f1_1[type] * cosphi; at2 = at_f2_1[type] * cos2phi; at3 = at_f3_1[type] * cos3phi; sumbte = at1 + at2 + at3; da = acos(costh12) - at_theta0_1[type]; if (eflag) edihedral += da * (at1+at2+at3); // force on angle1 bt1 = at_f1_1[type] * sinphi; bt2 = 2.0 * at_f2_1[type] * sin(2.0*phi); bt3 = 3.0 * at_f3_1[type] * sin(3.0*phi); sumbtf = bt1 + bt2 + bt3; for (i = 0; i < 4; i++) for (j = 0; j < 3; j++) fabcd[i][j] -= da*sumbtf*dphidr[i][j] + sumbte*dthetadr[0][i][j]; // energy on angle2 at1 = at_f1_2[type] * cosphi; at2 = at_f2_2[type] * cos2phi; at3 = at_f3_2[type] * cos3phi; sumbte = at1 + at2 + at3; da = acos(costh23) - at_theta0_2[type]; if (eflag) edihedral += da * (at1+at2+at3); // force on angle2 bt1 = -at_f1_2[type] * sinphi; bt2 = -2.0 * at_f2_2[type] * sin(2.0*phi); bt3 = -3.0 * at_f3_2[type] * sin(3.0*phi); sumbtf = bt1 + bt2 + bt3; for (i = 0; i < 4; i++) for (j = 0; j < 3; j++) fabcd[i][j] += da*sumbtf*dphidr[i][j] + sumbte*dthetadr[1][i][j]; // angle/angle/torsion coupling da1 = acos(costh12) - aat_theta0_1[type]; da2 = acos(costh23) - aat_theta0_2[type]; if (eflag) edihedral += aat_k[type]*da1*da2*cosphi; for (i = 0; i < 4; i++) for (j = 0; j < 3; j++) fabcd[i][j] -= aat_k[type] * (cosphi * (da2*dthetadr[0][i][j] - da1*dthetadr[1][i][j]) + sinphi * da1*da2*dphidr[i][j]); // bond1/bond3 coupling if (fabs(bb13t_k[type]) > SMALL) { r1_0 = bb13t_r10[type]; r3_0 = bb13t_r30[type]; dr1 = r1 - r1_0; dr2 = r3 - r3_0; tk1 = -bb13t_k[type] * dr1 / r3; tk2 = -bb13t_k[type] * dr2 / r1; if (eflag) edihedral += bb13t_k[type]*dr1*dr2; fabcd[0][0] += tk2 * vb1x; fabcd[0][1] += tk2 * vb1y; fabcd[0][2] += tk2 * vb1z; fabcd[1][0] -= tk2 * vb1x; fabcd[1][1] -= tk2 * vb1y; fabcd[1][2] -= tk2 * vb1z; fabcd[2][0] -= tk1 * vb3x; fabcd[2][1] -= tk1 * vb3y; fabcd[2][2] -= tk1 * vb3z; fabcd[3][0] += tk1 * vb3x; fabcd[3][1] += tk1 * vb3y; fabcd[3][2] += tk1 * vb3z; } // apply force to each of 4 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += fabcd[0][0]; f[i1][1] += fabcd[0][1]; f[i1][2] += fabcd[0][2]; } if (newton_bond || i2 < nlocal) { f[i2][0] += fabcd[1][0]; f[i2][1] += fabcd[1][1]; f[i2][2] += fabcd[1][2]; } if (newton_bond || i3 < nlocal) { f[i3][0] += fabcd[2][0]; f[i3][1] += fabcd[2][1]; f[i3][2] += fabcd[2][2]; } if (newton_bond || i4 < nlocal) { f[i4][0] += fabcd[3][0]; f[i4][1] += fabcd[3][1]; f[i4][2] += fabcd[3][2]; } if (evflag) ev_tally(i1,i2,i3,i4,nlocal,newton_bond,edihedral, fabcd[0],fabcd[2],fabcd[3], vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z); } } /* ---------------------------------------------------------------------- */ void DihedralClass2::allocate() { allocated = 1; int n = atom->ndihedraltypes; memory->create(k1,n+1,"dihedral:k1"); memory->create(k2,n+1,"dihedral:k2"); memory->create(k3,n+1,"dihedral:k3"); memory->create(phi1,n+1,"dihedral:phi1"); memory->create(phi2,n+1,"dihedral:phi2"); memory->create(phi3,n+1,"dihedral:phi3"); memory->create(mbt_f1,n+1,"dihedral:mbt_f1"); memory->create(mbt_f2,n+1,"dihedral:mbt_f2"); memory->create(mbt_f3,n+1,"dihedral:mbt_f3"); memory->create(mbt_r0,n+1,"dihedral:mbt_r0"); memory->create(ebt_f1_1,n+1,"dihedral:ebt_f1_1"); memory->create(ebt_f2_1,n+1,"dihedral:ebt_f2_1"); memory->create(ebt_f3_1,n+1,"dihedral:ebt_f3_1"); memory->create(ebt_r0_1,n+1,"dihedral:ebt_r0_1"); memory->create(ebt_f1_2,n+1,"dihedral:ebt_f1_2"); memory->create(ebt_f2_2,n+1,"dihedral:ebt_f2_2"); memory->create(ebt_f3_2,n+1,"dihedral:ebt_f3_2"); memory->create(ebt_r0_2,n+1,"dihedral:ebt_r0_2"); memory->create(at_f1_1,n+1,"dihedral:at_f1_1"); memory->create(at_f2_1,n+1,"dihedral:at_f2_1"); memory->create(at_f3_1,n+1,"dihedral:at_f3_1"); memory->create(at_theta0_1,n+1,"dihedral:at_theta0_1"); memory->create(at_f1_2,n+1,"dihedral:at_f1_2"); memory->create(at_f2_2,n+1,"dihedral:at_f2_2"); memory->create(at_f3_2,n+1,"dihedral:at_f3_2"); memory->create(at_theta0_2,n+1,"dihedral:at_theta0_2"); memory->create(aat_k,n+1,"dihedral:aat_k"); memory->create(aat_theta0_1,n+1,"dihedral:aat_theta0_1"); memory->create(aat_theta0_2,n+1,"dihedral:aat_theta0_2"); memory->create(bb13t_k,n+1,"dihedral:bb13t_k"); memory->create(bb13t_r10,n+1,"dihedral:bb13t_r10"); memory->create(bb13t_r30,n+1,"dihedral:bb13t_r30"); memory->create(setflag,n+1,"dihedral:setflag"); memory->create(setflag_d,n+1,"dihedral:setflag_d"); memory->create(setflag_mbt,n+1,"dihedral:setflag_mbt"); memory->create(setflag_ebt,n+1,"dihedral:setflag_ebt"); memory->create(setflag_at,n+1,"dihedral:setflag_at"); memory->create(setflag_aat,n+1,"dihedral:setflag_aat"); memory->create(setflag_bb13t,n+1,"dihedral:setflag_bb13t"); for (int i = 1; i <= n; i++) setflag[i] = setflag_d[i] = setflag_mbt[i] = setflag_ebt[i] = setflag_at[i] = setflag_aat[i] = setflag_bb13t[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one or more types arg1 = "mbt" -> MiddleBondTorsion coeffs arg1 = "ebt" -> EndBondTorsion coeffs arg1 = "at" -> AngleTorsion coeffs arg1 = "aat" -> AngleAngleTorsion coeffs arg1 = "bb13" -> BondBond13Torsion coeffs arg1 -> Dihedral coeffs ------------------------------------------------------------------------- */ void DihedralClass2::coeff(int narg, char **arg) { if (narg < 2) error->all(FLERR,"Invalid coeffs for this dihedral style"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->ndihedraltypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->ndihedraltypes,ilo,ihi); int count = 0; if (strcmp(arg[1],"mbt") == 0) { if (narg != 6) error->all(FLERR,"Incorrect args for dihedral coefficients"); double f1_one = force->numeric(FLERR,arg[2]); double f2_one = force->numeric(FLERR,arg[3]); double f3_one = force->numeric(FLERR,arg[4]); double r0_one = force->numeric(FLERR,arg[5]); for (int i = ilo; i <= ihi; i++) { mbt_f1[i] = f1_one; mbt_f2[i] = f2_one; mbt_f3[i] = f3_one; mbt_r0[i] = r0_one; setflag_mbt[i] = 1; count++; } } else if (strcmp(arg[1],"ebt") == 0) { if (narg != 10) error->all(FLERR,"Incorrect args for dihedral coefficients"); double f1_1_one = force->numeric(FLERR,arg[2]); double f2_1_one = force->numeric(FLERR,arg[3]); double f3_1_one = force->numeric(FLERR,arg[4]); double f1_2_one = force->numeric(FLERR,arg[5]); double f2_2_one = force->numeric(FLERR,arg[6]); double f3_2_one = force->numeric(FLERR,arg[7]); double r0_1_one = force->numeric(FLERR,arg[8]); double r0_2_one = force->numeric(FLERR,arg[9]); for (int i = ilo; i <= ihi; i++) { ebt_f1_1[i] = f1_1_one; ebt_f2_1[i] = f2_1_one; ebt_f3_1[i] = f3_1_one; ebt_f1_2[i] = f1_2_one; ebt_f2_2[i] = f2_2_one; ebt_f3_2[i] = f3_2_one; ebt_r0_1[i] = r0_1_one; ebt_r0_2[i] = r0_2_one; setflag_ebt[i] = 1; count++; } } else if (strcmp(arg[1],"at") == 0) { if (narg != 10) error->all(FLERR,"Incorrect args for dihedral coefficients"); double f1_1_one = force->numeric(FLERR,arg[2]); double f2_1_one = force->numeric(FLERR,arg[3]); double f3_1_one = force->numeric(FLERR,arg[4]); double f1_2_one = force->numeric(FLERR,arg[5]); double f2_2_one = force->numeric(FLERR,arg[6]); double f3_2_one = force->numeric(FLERR,arg[7]); double theta0_1_one = force->numeric(FLERR,arg[8]); double theta0_2_one = force->numeric(FLERR,arg[9]); // convert theta0's from degrees to radians for (int i = ilo; i <= ihi; i++) { at_f1_1[i] = f1_1_one; at_f2_1[i] = f2_1_one; at_f3_1[i] = f3_1_one; at_f1_2[i] = f1_2_one; at_f2_2[i] = f2_2_one; at_f3_2[i] = f3_2_one; at_theta0_1[i] = theta0_1_one/180.0 * MY_PI; at_theta0_2[i] = theta0_2_one/180.0 * MY_PI; setflag_at[i] = 1; count++; } } else if (strcmp(arg[1],"aat") == 0) { if (narg != 5) error->all(FLERR,"Incorrect args for dihedral coefficients"); double k_one = force->numeric(FLERR,arg[2]); double theta0_1_one = force->numeric(FLERR,arg[3]); double theta0_2_one = force->numeric(FLERR,arg[4]); // convert theta0's from degrees to radians for (int i = ilo; i <= ihi; i++) { aat_k[i] = k_one; aat_theta0_1[i] = theta0_1_one/180.0 * MY_PI; aat_theta0_2[i] = theta0_2_one/180.0 * MY_PI; setflag_aat[i] = 1; count++; } } else if (strcmp(arg[1],"bb13") == 0) { if (narg != 5) error->all(FLERR,"Incorrect args for dihedral coefficients"); double k_one = force->numeric(FLERR,arg[2]); double r10_one = force->numeric(FLERR,arg[3]); double r30_one = force->numeric(FLERR,arg[4]); for (int i = ilo; i <= ihi; i++) { bb13t_k[i] = k_one; bb13t_r10[i] = r10_one; bb13t_r30[i] = r30_one; setflag_bb13t[i] = 1; count++; } } else { if (narg != 7) error->all(FLERR,"Incorrect args for dihedral coefficients"); double k1_one = force->numeric(FLERR,arg[1]); double phi1_one = force->numeric(FLERR,arg[2]); double k2_one = force->numeric(FLERR,arg[3]); double phi2_one = force->numeric(FLERR,arg[4]); double k3_one = force->numeric(FLERR,arg[5]); double phi3_one = force->numeric(FLERR,arg[6]); // convert phi's from degrees to radians for (int i = ilo; i <= ihi; i++) { k1[i] = k1_one; phi1[i] = phi1_one/180.0 * MY_PI; k2[i] = k2_one; phi2[i] = phi2_one/180.0 * MY_PI; k3[i] = k3_one; phi3[i] = phi3_one/180.0 * MY_PI; setflag_d[i] = 1; count++; } } if (count == 0) error->all(FLERR,"Incorrect args for dihedral coefficients"); for (int i = ilo; i <= ihi; i++) if (setflag_d[i] == 1 && setflag_mbt[i] == 1 && setflag_ebt[i] == 1 && setflag_at[i] == 1 && setflag_aat[i] == 1 && setflag_bb13t[i] == 1) setflag[i] = 1; } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void DihedralClass2::write_restart(FILE *fp) { fwrite(&k1[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&k2[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&k3[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&phi1[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&phi2[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&phi3[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&mbt_f1[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&mbt_f2[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&mbt_f3[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&mbt_r0[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&ebt_f1_1[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&ebt_f2_1[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&ebt_f3_1[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&ebt_r0_1[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&ebt_f1_2[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&ebt_f2_2[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&ebt_f3_2[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&ebt_r0_2[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&at_f1_1[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&at_f2_1[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&at_f3_1[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&at_theta0_1[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&at_f1_2[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&at_f2_2[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&at_f3_2[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&at_theta0_2[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&aat_k[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&aat_theta0_1[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&aat_theta0_2[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&bb13t_k[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&bb13t_r10[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&bb13t_r30[1],sizeof(double),atom->ndihedraltypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void DihedralClass2::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&k1[1],sizeof(double),atom->ndihedraltypes,fp); fread(&k2[1],sizeof(double),atom->ndihedraltypes,fp); fread(&k3[1],sizeof(double),atom->ndihedraltypes,fp); fread(&phi1[1],sizeof(double),atom->ndihedraltypes,fp); fread(&phi2[1],sizeof(double),atom->ndihedraltypes,fp); fread(&phi3[1],sizeof(double),atom->ndihedraltypes,fp); fread(&mbt_f1[1],sizeof(double),atom->ndihedraltypes,fp); fread(&mbt_f2[1],sizeof(double),atom->ndihedraltypes,fp); fread(&mbt_f3[1],sizeof(double),atom->ndihedraltypes,fp); fread(&mbt_r0[1],sizeof(double),atom->ndihedraltypes,fp); fread(&ebt_f1_1[1],sizeof(double),atom->ndihedraltypes,fp); fread(&ebt_f2_1[1],sizeof(double),atom->ndihedraltypes,fp); fread(&ebt_f3_1[1],sizeof(double),atom->ndihedraltypes,fp); fread(&ebt_r0_1[1],sizeof(double),atom->ndihedraltypes,fp); fread(&ebt_f1_2[1],sizeof(double),atom->ndihedraltypes,fp); fread(&ebt_f2_2[1],sizeof(double),atom->ndihedraltypes,fp); fread(&ebt_f3_2[1],sizeof(double),atom->ndihedraltypes,fp); fread(&ebt_r0_2[1],sizeof(double),atom->ndihedraltypes,fp); fread(&at_f1_1[1],sizeof(double),atom->ndihedraltypes,fp); fread(&at_f2_1[1],sizeof(double),atom->ndihedraltypes,fp); fread(&at_f3_1[1],sizeof(double),atom->ndihedraltypes,fp); fread(&at_theta0_1[1],sizeof(double),atom->ndihedraltypes,fp); fread(&at_f1_2[1],sizeof(double),atom->ndihedraltypes,fp); fread(&at_f2_2[1],sizeof(double),atom->ndihedraltypes,fp); fread(&at_f3_2[1],sizeof(double),atom->ndihedraltypes,fp); fread(&at_theta0_2[1],sizeof(double),atom->ndihedraltypes,fp); fread(&aat_k[1],sizeof(double),atom->ndihedraltypes,fp); fread(&aat_theta0_1[1],sizeof(double),atom->ndihedraltypes,fp); fread(&aat_theta0_2[1],sizeof(double),atom->ndihedraltypes,fp); fread(&bb13t_k[1],sizeof(double),atom->ndihedraltypes,fp); fread(&bb13t_r10[1],sizeof(double),atom->ndihedraltypes,fp); fread(&bb13t_r30[1],sizeof(double),atom->ndihedraltypes,fp); } MPI_Bcast(&k1[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&k2[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&k3[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&phi1[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&phi2[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&phi3[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&mbt_f1[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&mbt_f2[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&mbt_f3[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&mbt_r0[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&ebt_f1_1[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&ebt_f2_1[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&ebt_f3_1[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&ebt_r0_1[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&ebt_f1_2[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&ebt_f2_2[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&ebt_f3_2[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&ebt_r0_2[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&at_f1_1[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&at_f2_1[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&at_f3_1[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&at_theta0_1[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&at_f1_2[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&at_f2_2[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&at_f3_2[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&at_theta0_2[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&aat_k[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&aat_theta0_1[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&aat_theta0_2[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&bb13t_k[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&bb13t_r10[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&bb13t_r30[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); for (int i = 1; i <= atom->ndihedraltypes; i++) setflag[i] = 1; } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void DihedralClass2::write_data(FILE *fp) { for (int i = 1; i <= atom->ndihedraltypes; i++) fprintf(fp,"%d %g %g %g %g %g %g\n",i, k1[i],phi1[i]*180.0/MY_PI, k2[i],phi2[i]*180.0/MY_PI, k3[i],phi3[i]*180.0/MY_PI); fprintf(fp,"\nAngleAngleTorsion Coeffs\n\n"); for (int i = 1; i <= atom->ndihedraltypes; i++) fprintf(fp,"%d %g %g %g\n",i,aat_k[i], aat_theta0_1[i]*180.0/MY_PI,aat_theta0_2[i]*180.0/MY_PI); fprintf(fp,"\nEndBondTorsion Coeffs\n\n"); for (int i = 1; i <= atom->ndihedraltypes; i++) fprintf(fp,"%d %g %g %g %g %g %g %g %g\n",i, ebt_f1_1[i],ebt_f2_1[i],ebt_f3_1[i], ebt_f1_2[i],ebt_f2_2[i],ebt_f3_2[i], ebt_r0_1[i],ebt_r0_2[i]); fprintf(fp,"\nMiddleBondTorsion Coeffs\n\n"); for (int i = 1; i <= atom->ndihedraltypes; i++) fprintf(fp,"%d %g %g %g %g\n",i,mbt_f1[i],mbt_f2[i],mbt_f3[i],mbt_r0[i]); fprintf(fp,"\nBondBond13 Coeffs\n\n"); for (int i = 1; i <= atom->ndihedraltypes; i++) fprintf(fp,"%d %g %g %g\n",i,bb13t_k[i],bb13t_r10[i],bb13t_r30[i]); fprintf(fp,"\nAngleTorsion Coeffs\n\n"); for (int i = 1; i <= atom->ndihedraltypes; i++) fprintf(fp,"%d %g %g %g %g %g %g %g %g\n",i, at_f1_1[i],at_f2_1[i],at_f3_1[i], at_f1_2[i],at_f2_2[i],at_f3_2[i], at_theta0_1[i]*180.0/MY_PI,at_theta0_2[i]*180.0/MY_PI); } diff --git a/src/CLASS2/improper_class2.cpp b/src/CLASS2/improper_class2.cpp index 6c599276c..618e20f6c 100644 --- a/src/CLASS2/improper_class2.cpp +++ b/src/CLASS2/improper_class2.cpp @@ -1,861 +1,861 @@ /* ---------------------------------------------------------------------- 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: Eric Simon (Cray) ------------------------------------------------------------------------- */ #include #include #include #include "improper_class2.h" #include "atom.h" #include "neighbor.h" #include "update.h" #include "domain.h" #include "comm.h" #include "force.h" #include "math_const.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace MathConst; #define SMALL 0.001 /* ---------------------------------------------------------------------- */ ImproperClass2::ImproperClass2(LAMMPS *lmp) : Improper(lmp) { writedata = 1; } /* ---------------------------------------------------------------------- */ ImproperClass2::~ImproperClass2() { if (allocated) { memory->destroy(setflag); memory->destroy(setflag_i); memory->destroy(setflag_aa); memory->destroy(k0); memory->destroy(chi0); memory->destroy(aa_k1); memory->destroy(aa_k2); memory->destroy(aa_k3); memory->destroy(aa_theta0_1); memory->destroy(aa_theta0_2); memory->destroy(aa_theta0_3); } } /* ---------------------------------------------------------------------- */ void ImproperClass2::compute(int eflag, int vflag) { int i1,i2,i3,i4,i,j,k,n,type; double eimproper; double delr[3][3],rmag[3],rinvmag[3],rmag2[3]; double theta[3],costheta[3],sintheta[3]; double cossqtheta[3],sinsqtheta[3],invstheta[3]; double rABxrCB[3],rDBxrAB[3],rCBxrDB[3]; double ddelr[3][4],dr[3][4][3],dinvr[3][4][3]; double dthetadr[3][4][3],dinvsth[3][4][3]; double dinv3r[4][3],dinvs3r[3][4][3]; double drCBxrDB[3],rCBxdrDB[3],drDBxrAB[3],rDBxdrAB[3]; double drABxrCB[3],rABxdrCB[3]; double dot1,dot2,dd[3]; double fdot[3][4][3],ftmp,invs3r[3],inv3r; double t,tt1,tt3,sc1; double dotCBDBAB,dotDBABCB,dotABCBDB; double chi,deltachi,d2chi,cossin2; double drAB[3][4][3],drCB[3][4][3],drDB[3][4][3]; double dchi[3][4][3],dtotalchi[4][3]; double schiABCD,chiABCD,schiCBDA,chiCBDA,schiDBAC,chiDBAC; double fabcd[4][3]; eimproper = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; for (i = 0; i < 3; i++) for (j = 0; j < 4; j++) for (k = 0; k < 3; k++) { dthetadr[i][j][k] = 0.0; drAB[i][j][k] = 0.0; drCB[i][j][k] = 0.0; drDB[i][j][k] = 0.0; } double **x = atom->x; double **f = atom->f; int **improperlist = neighbor->improperlist; int nimproperlist = neighbor->nimproperlist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < nimproperlist; n++) { i1 = improperlist[n][0]; i2 = improperlist[n][1]; i3 = improperlist[n][2]; i4 = improperlist[n][3]; type = improperlist[n][4]; if (k0[type] == 0.0) continue; // difference vectors delr[0][0] = x[i1][0] - x[i2][0]; delr[0][1] = x[i1][1] - x[i2][1]; delr[0][2] = x[i1][2] - x[i2][2]; delr[1][0] = x[i3][0] - x[i2][0]; delr[1][1] = x[i3][1] - x[i2][1]; delr[1][2] = x[i3][2] - x[i2][2]; delr[2][0] = x[i4][0] - x[i2][0]; delr[2][1] = x[i4][1] - x[i2][1]; delr[2][2] = x[i4][2] - x[i2][2]; // bond lengths and associated values for (i = 0; i < 3; i++) { rmag2[i] = delr[i][0]*delr[i][0] + delr[i][1]*delr[i][1] + delr[i][2]*delr[i][2]; rmag[i] = sqrt(rmag2[i]); rinvmag[i] = 1.0/rmag[i]; } // angle ABC, CBD, ABD costheta[0] = (delr[0][0]*delr[1][0] + delr[0][1]*delr[1][1] + delr[0][2]*delr[1][2]) / (rmag[0]*rmag[1]); costheta[1] = (delr[1][0]*delr[2][0] + delr[1][1]*delr[2][1] + delr[1][2]*delr[2][2]) / (rmag[1]*rmag[2]); costheta[2] = (delr[0][0]*delr[2][0] + delr[0][1]*delr[2][1] + delr[0][2]*delr[2][2]) / (rmag[0]*rmag[2]); // angle error check for (i = 0; i < 3; i++) { if (costheta[i] == -1.0) { int me; MPI_Comm_rank(world,&me); if (screen) { char str[128]; sprintf(str,"Improper problem: %d " BIGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT, me,update->ntimestep, atom->tag[i1],atom->tag[i2],atom->tag[i3],atom->tag[i4]); error->warning(FLERR,str,0); fprintf(screen," 1st atom: %d %g %g %g\n", me,x[i1][0],x[i1][1],x[i1][2]); fprintf(screen," 2nd atom: %d %g %g %g\n", me,x[i2][0],x[i2][1],x[i2][2]); fprintf(screen," 3rd atom: %d %g %g %g\n", me,x[i3][0],x[i3][1],x[i3][2]); fprintf(screen," 4th atom: %d %g %g %g\n", me,x[i4][0],x[i4][1],x[i4][2]); } } } for (i = 0; i < 3; i++) { if (costheta[i] > 1.0) costheta[i] = 1.0; if (costheta[i] < -1.0) costheta[i] = -1.0; theta[i] = acos(costheta[i]); cossqtheta[i] = costheta[i]*costheta[i]; sintheta[i] = sin(theta[i]); invstheta[i] = 1.0/sintheta[i]; sinsqtheta[i] = sintheta[i]*sintheta[i]; } // cross & dot products cross(delr[0],delr[1],rABxrCB); cross(delr[2],delr[0],rDBxrAB); cross(delr[1],delr[2],rCBxrDB); dotCBDBAB = dot(rCBxrDB,delr[0]); dotDBABCB = dot(rDBxrAB,delr[1]); dotABCBDB = dot(rABxrCB,delr[2]); t = rmag[0] * rmag[1] * rmag[2]; inv3r = 1.0/t; invs3r[0] = invstheta[1] * inv3r; invs3r[1] = invstheta[2] * inv3r; invs3r[2] = invstheta[0] * inv3r; // chi ABCD, CBDA, DBAC // final chi is average of three schiABCD = dotCBDBAB * invs3r[0]; chiABCD = asin(schiABCD); schiCBDA = dotDBABCB * invs3r[1]; chiCBDA = asin(schiCBDA); schiDBAC = dotABCBDB * invs3r[2]; chiDBAC = asin(schiDBAC); chi = (chiABCD + chiCBDA + chiDBAC) / 3.0; deltachi = chi - chi0[type]; d2chi = deltachi * deltachi; // energy if (eflag) eimproper = k0[type]*d2chi; // forces // define d(delr) // i = bond AB/CB/DB, j = atom A/B/C/D for (i = 0; i < 3; i++) for (j = 0; j < 4; j++) ddelr[i][j] = 0.0; ddelr[0][0] = 1.0; ddelr[0][1] = -1.0; ddelr[1][1] = -1.0; ddelr[1][2] = 1.0; ddelr[2][1] = -1.0; ddelr[2][3] = 1.0; // compute d(|r|)/dr and d(1/|r|)/dr for each direction, bond and atom // define d(r) for each r // i = bond AB/CB/DB, j = atom A/B/C/D, k = X/Y/Z for (i = 0; i < 3; i++) for (j = 0; j < 4; j++) for (k = 0; k < 3; k++) { dr[i][j][k] = delr[i][k] * ddelr[i][j] / rmag[i]; dinvr[i][j][k] = -dr[i][j][k] / rmag2[i]; } // compute d(1 / (|r_AB| * |r_CB| * |r_DB|) / dr // i = atom A/B/C/D, j = X/Y/Z for (i = 0; i < 4; i++) for (j = 0; j < 3; j++) dinv3r[i][j] = rinvmag[1] * (rinvmag[2] * dinvr[0][i][j] + rinvmag[0] * dinvr[2][i][j]) + rinvmag[2] * rinvmag[0] * dinvr[1][i][j]; // compute d(theta)/d(r) for 3 angles // angleABC tt1 = costheta[0] / rmag2[0]; tt3 = costheta[0] / rmag2[1]; sc1 = 1.0 / sqrt(1.0 - cossqtheta[0]); dthetadr[0][0][0] = sc1 * ((tt1 * delr[0][0]) - (delr[1][0] * rinvmag[0] * rinvmag[1])); dthetadr[0][0][1] = sc1 * ((tt1 * delr[0][1]) - (delr[1][1] * rinvmag[0] * rinvmag[1])); dthetadr[0][0][2] = sc1 * ((tt1 * delr[0][2]) - (delr[1][2] * rinvmag[0] * rinvmag[1])); dthetadr[0][1][0] = -sc1 * ((tt1 * delr[0][0]) - (delr[1][0] * rinvmag[0] * rinvmag[1]) + (tt3 * delr[1][0]) - (delr[0][0] * rinvmag[0] * rinvmag[1])); dthetadr[0][1][1] = -sc1 * ((tt1 * delr[0][1]) - (delr[1][1] * rinvmag[0] * rinvmag[1]) + (tt3 * delr[1][1]) - (delr[0][1] * rinvmag[0] * rinvmag[1])); dthetadr[0][1][2] = -sc1 * ((tt1 * delr[0][2]) - (delr[1][2] * rinvmag[0] * rinvmag[1]) + (tt3 * delr[1][2]) - (delr[0][2] * rinvmag[0] * rinvmag[1])); dthetadr[0][2][0] = sc1 * ((tt3 * delr[1][0]) - (delr[0][0] * rinvmag[0] * rinvmag[1])); dthetadr[0][2][1] = sc1 * ((tt3 * delr[1][1]) - (delr[0][1] * rinvmag[0] * rinvmag[1])); dthetadr[0][2][2] = sc1 * ((tt3 * delr[1][2]) - (delr[0][2] * rinvmag[0] * rinvmag[1])); // angleCBD tt1 = costheta[1] / rmag2[1]; tt3 = costheta[1] / rmag2[2]; sc1 = 1.0 / sqrt(1.0 - cossqtheta[1]); dthetadr[1][2][0] = sc1 * ((tt1 * delr[1][0]) - (delr[2][0] * rinvmag[1] * rinvmag[2])); dthetadr[1][2][1] = sc1 * ((tt1 * delr[1][1]) - (delr[2][1] * rinvmag[1] * rinvmag[2])); dthetadr[1][2][2] = sc1 * ((tt1 * delr[1][2]) - (delr[2][2] * rinvmag[1] * rinvmag[2])); dthetadr[1][1][0] = -sc1 * ((tt1 * delr[1][0]) - (delr[2][0] * rinvmag[1] * rinvmag[2]) + (tt3 * delr[2][0]) - (delr[1][0] * rinvmag[2] * rinvmag[1])); dthetadr[1][1][1] = -sc1 * ((tt1 * delr[1][1]) - (delr[2][1] * rinvmag[1] * rinvmag[2]) + (tt3 * delr[2][1]) - (delr[1][1] * rinvmag[2] * rinvmag[1])); dthetadr[1][1][2] = -sc1 * ((tt1 * delr[1][2]) - (delr[2][2] * rinvmag[1] * rinvmag[2]) + (tt3 * delr[2][2]) - (delr[1][2] * rinvmag[2] * rinvmag[1])); dthetadr[1][3][0] = sc1 * ((tt3 * delr[2][0]) - (delr[1][0] * rinvmag[2] * rinvmag[1])); dthetadr[1][3][1] = sc1 * ((tt3 * delr[2][1]) - (delr[1][1] * rinvmag[2] * rinvmag[1])); dthetadr[1][3][2] = sc1 * ((tt3 * delr[2][2]) - (delr[1][2] * rinvmag[2] * rinvmag[1])); // angleABD tt1 = costheta[2] / rmag2[0]; tt3 = costheta[2] / rmag2[2]; sc1 = 1.0 / sqrt(1.0 - cossqtheta[2]); dthetadr[2][0][0] = sc1 * ((tt1 * delr[0][0]) - (delr[2][0] * rinvmag[0] * rinvmag[2])); dthetadr[2][0][1] = sc1 * ((tt1 * delr[0][1]) - (delr[2][1] * rinvmag[0] * rinvmag[2])); dthetadr[2][0][2] = sc1 * ((tt1 * delr[0][2]) - (delr[2][2] * rinvmag[0] * rinvmag[2])); dthetadr[2][1][0] = -sc1 * ((tt1 * delr[0][0]) - (delr[2][0] * rinvmag[0] * rinvmag[2]) + (tt3 * delr[2][0]) - (delr[0][0] * rinvmag[2] * rinvmag[0])); dthetadr[2][1][1] = -sc1 * ((tt1 * delr[0][1]) - (delr[2][1] * rinvmag[0] * rinvmag[2]) + (tt3 * delr[2][1]) - (delr[0][1] * rinvmag[2] * rinvmag[0])); dthetadr[2][1][2] = -sc1 * ((tt1 * delr[0][2]) - (delr[2][2] * rinvmag[0] * rinvmag[2]) + (tt3 * delr[2][2]) - (delr[0][2] * rinvmag[2] * rinvmag[0])); dthetadr[2][3][0] = sc1 * ((tt3 * delr[2][0]) - (delr[0][0] * rinvmag[2] * rinvmag[0])); dthetadr[2][3][1] = sc1 * ((tt3 * delr[2][1]) - (delr[0][1] * rinvmag[2] * rinvmag[0])); dthetadr[2][3][2] = sc1 * ((tt3 * delr[2][2]) - (delr[0][2] * rinvmag[2] * rinvmag[0])); // compute d( 1 / sin(theta))/dr // i = angle, j = atom, k = direction for (i = 0; i < 3; i++) { cossin2 = -costheta[i] / sinsqtheta[i]; for (j = 0; j < 4; j++) for (k = 0; k < 3; k++) dinvsth[i][j][k] = cossin2 * dthetadr[i][j][k]; } // compute d(1 / sin(theta) * |r_AB| * |r_CB| * |r_DB|)/dr // i = angle, j = atom for (i = 0; i < 4; i++) for (j = 0; j < 3; j++) { dinvs3r[0][i][j] = (invstheta[1] * dinv3r[i][j]) + (inv3r * dinvsth[1][i][j]); dinvs3r[1][i][j] = (invstheta[2] * dinv3r[i][j]) + (inv3r * dinvsth[2][i][j]); dinvs3r[2][i][j] = (invstheta[0] * dinv3r[i][j]) + (inv3r * dinvsth[0][i][j]); } // drCB(i,j,k), etc // i = vector X'/Y'/Z', j = atom A/B/C/D, k = direction X/Y/Z for (i = 0; i < 3; i++) { drCB[i][1][i] = -1.0; drAB[i][1][i] = -1.0; drDB[i][1][i] = -1.0; drDB[i][3][i] = 1.0; drCB[i][2][i] = 1.0; drAB[i][0][i] = 1.0; } // d((r_CB x r_DB) dot r_AB) // r_CB x d(r_DB) // d(r_CB) x r_DB // (r_CB x d(r_DB)) + (d(r_CB) x r_DB) // (r_CB x d(r_DB)) + (d(r_CB) x r_DB) dot r_AB // d(r_AB) dot (r_CB x r_DB) for (i = 0; i < 3; i++) for (j = 0; j < 4; j++) { cross(delr[1],drDB[i][j],rCBxdrDB); cross(drCB[i][j],delr[2],drCBxrDB); for (k = 0; k < 3; k++) dd[k] = rCBxdrDB[k] + drCBxrDB[k]; dot1 = dot(dd,delr[0]); dot2 = dot(rCBxrDB,drAB[i][j]); fdot[0][j][i] = dot1 + dot2; } // d((r_DB x r_AB) dot r_CB) // r_DB x d(r_AB) // d(r_DB) x r_AB // (r_DB x d(r_AB)) + (d(r_DB) x r_AB) // (r_DB x d(r_AB)) + (d(r_DB) x r_AB) dot r_CB // d(r_CB) dot (r_DB x r_AB) for (i = 0; i < 3; i++) for (j = 0; j < 4; j++) { cross(delr[2],drAB[i][j],rDBxdrAB); cross(drDB[i][j],delr[0],drDBxrAB); for (k = 0; k < 3; k++) dd[k] = rDBxdrAB[k] + drDBxrAB[k]; dot1 = dot(dd,delr[1]); dot2 = dot(rDBxrAB,drCB[i][j]); fdot[1][j][i] = dot1 + dot2; } // d((r_AB x r_CB) dot r_DB) // r_AB x d(r_CB) // d(r_AB) x r_CB // (r_AB x d(r_CB)) + (d(r_AB) x r_CB) // (r_AB x d(r_CB)) + (d(r_AB) x r_CB) dot r_DB // d(r_DB) dot (r_AB x r_CB) for (i = 0; i < 3; i++) for (j = 0; j < 4; j++) { cross(delr[0],drCB[i][j],rABxdrCB); cross(drAB[i][j],delr[1],drABxrCB); for (k = 0; k < 3; k++) dd[k] = rABxdrCB[k] + drABxrCB[k]; dot1 = dot(dd,delr[2]); dot2 = dot(rABxrCB,drDB[i][j]); fdot[2][j][i] = dot1 + dot2; } // force on each atom for (i = 0; i < 4; i++) for (j = 0; j < 3; j++) { ftmp = (fdot[0][i][j] * invs3r[0]) + (dinvs3r[0][i][j] * dotCBDBAB); dchi[0][i][j] = ftmp / cos(chiABCD); ftmp = (fdot[1][i][j] * invs3r[1]) + (dinvs3r[1][i][j] * dotDBABCB); dchi[1][i][j] = ftmp / cos(chiCBDA); ftmp = (fdot[2][i][j] * invs3r[2]) + (dinvs3r[2][i][j] * dotABCBDB); dchi[2][i][j] = ftmp / cos(chiDBAC); dtotalchi[i][j] = (dchi[0][i][j]+dchi[1][i][j]+dchi[2][i][j]) / 3.0; } for (i = 0; i < 4; i++) for (j = 0; j < 3; j++) fabcd[i][j] = -2.0*k0[type] * deltachi*dtotalchi[i][j]; // apply force to each of 4 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += fabcd[0][0]; f[i1][1] += fabcd[0][1]; f[i1][2] += fabcd[0][2]; } if (newton_bond || i2 < nlocal) { f[i2][0] += fabcd[1][0]; f[i2][1] += fabcd[1][1]; f[i2][2] += fabcd[1][2]; } if (newton_bond || i3 < nlocal) { f[i3][0] += fabcd[2][0]; f[i3][1] += fabcd[2][1]; f[i3][2] += fabcd[2][2]; } if (newton_bond || i4 < nlocal) { f[i4][0] += fabcd[3][0]; f[i4][1] += fabcd[3][1]; f[i4][2] += fabcd[3][2]; } if (evflag) ev_tally(i1,i2,i3,i4,nlocal,newton_bond,eimproper, fabcd[0],fabcd[2],fabcd[3], delr[0][0],delr[0][1],delr[0][2], delr[1][0],delr[1][1],delr[1][2], delr[2][0]-delr[1][0],delr[2][1]-delr[1][1], delr[2][2]-delr[1][2]); } // compute angle-angle interactions angleangle(eflag,vflag); } /* ---------------------------------------------------------------------- */ void ImproperClass2::allocate() { allocated = 1; int n = atom->nimpropertypes; memory->create(k0,n+1,"improper:k0"); memory->create(chi0,n+1,"improper:chi0"); memory->create(aa_k1,n+1,"improper:aa_k1"); memory->create(aa_k2,n+1,"improper:aa_k2"); memory->create(aa_k3,n+1,"improper:aa_k3"); memory->create(aa_theta0_1,n+1,"improper:aa_theta0_1"); memory->create(aa_theta0_2,n+1,"improper:aa_theta0_2"); memory->create(aa_theta0_3,n+1,"improper:aa_theta0_3"); memory->create(setflag,n+1,"improper:setflag"); memory->create(setflag_i,n+1,"improper:setflag_i"); memory->create(setflag_aa,n+1,"improper:setflag_aa"); for (int i = 1; i <= n; i++) setflag[i] = setflag_i[i] = setflag_aa[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one or more types arg1 = "aa" -> AngleAngle coeffs else arg1 -> improper coeffs ------------------------------------------------------------------------- */ void ImproperClass2::coeff(int narg, char **arg) { if (narg < 2) error->all(FLERR,"Incorrect args for improper coefficients"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->nimpropertypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->nimpropertypes,ilo,ihi); int count = 0; if (strcmp(arg[1],"aa") == 0) { if (narg != 8) error->all(FLERR,"Incorrect args for improper coefficients"); double k1_one = force->numeric(FLERR,arg[2]); double k2_one = force->numeric(FLERR,arg[3]); double k3_one = force->numeric(FLERR,arg[4]); double theta0_1_one = force->numeric(FLERR,arg[5]); double theta0_2_one = force->numeric(FLERR,arg[6]); double theta0_3_one = force->numeric(FLERR,arg[7]); // convert theta0's from degrees to radians for (int i = ilo; i <= ihi; i++) { aa_k1[i] = k1_one; aa_k2[i] = k2_one; aa_k3[i] = k3_one; aa_theta0_1[i] = theta0_1_one/180.0 * MY_PI; aa_theta0_2[i] = theta0_2_one/180.0 * MY_PI; aa_theta0_3[i] = theta0_3_one/180.0 * MY_PI; setflag_aa[i] = 1; count++; } } else { if (narg != 3) error->all(FLERR,"Incorrect args for improper coefficients"); double k0_one = force->numeric(FLERR,arg[1]); double chi0_one = force->numeric(FLERR,arg[2]); // convert chi0 from degrees to radians for (int i = ilo; i <= ihi; i++) { k0[i] = k0_one; chi0[i] = chi0_one/180.0 * MY_PI; setflag_i[i] = 1; count++; } } if (count == 0) error->all(FLERR,"Incorrect args for improper coefficients"); for (int i = ilo; i <= ihi; i++) if (setflag_i[i] == 1 && setflag_aa[i] == 1) setflag[i] = 1; } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void ImproperClass2::write_restart(FILE *fp) { fwrite(&k0[1],sizeof(double),atom->nimpropertypes,fp); fwrite(&chi0[1],sizeof(double),atom->nimpropertypes,fp); fwrite(&aa_k1[1],sizeof(double),atom->nimpropertypes,fp); fwrite(&aa_k2[1],sizeof(double),atom->nimpropertypes,fp); fwrite(&aa_k3[1],sizeof(double),atom->nimpropertypes,fp); fwrite(&aa_theta0_1[1],sizeof(double),atom->nimpropertypes,fp); fwrite(&aa_theta0_2[1],sizeof(double),atom->nimpropertypes,fp); fwrite(&aa_theta0_3[1],sizeof(double),atom->nimpropertypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void ImproperClass2::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&k0[1],sizeof(double),atom->nimpropertypes,fp); fread(&chi0[1],sizeof(double),atom->nimpropertypes,fp); fread(&aa_k1[1],sizeof(double),atom->nimpropertypes,fp); fread(&aa_k2[1],sizeof(double),atom->nimpropertypes,fp); fread(&aa_k3[1],sizeof(double),atom->nimpropertypes,fp); fread(&aa_theta0_1[1],sizeof(double),atom->nimpropertypes,fp); fread(&aa_theta0_2[1],sizeof(double),atom->nimpropertypes,fp); fread(&aa_theta0_3[1],sizeof(double),atom->nimpropertypes,fp); } MPI_Bcast(&k0[1],atom->nimpropertypes,MPI_DOUBLE,0,world); MPI_Bcast(&chi0[1],atom->nimpropertypes,MPI_DOUBLE,0,world); MPI_Bcast(&aa_k1[1],atom->nimpropertypes,MPI_DOUBLE,0,world); MPI_Bcast(&aa_k2[1],atom->nimpropertypes,MPI_DOUBLE,0,world); MPI_Bcast(&aa_k3[1],atom->nimpropertypes,MPI_DOUBLE,0,world); MPI_Bcast(&aa_theta0_1[1],atom->nimpropertypes,MPI_DOUBLE,0,world); MPI_Bcast(&aa_theta0_2[1],atom->nimpropertypes,MPI_DOUBLE,0,world); MPI_Bcast(&aa_theta0_3[1],atom->nimpropertypes,MPI_DOUBLE,0,world); for (int i = 1; i <= atom->nimpropertypes; i++) setflag[i] = 1; } /* ---------------------------------------------------------------------- angle-angle interactions within improper ------------------------------------------------------------------------- */ void ImproperClass2::angleangle(int eflag, int vflag) { int i1,i2,i3,i4,i,j,k,n,type; double eimproper; double delxAB,delyAB,delzAB,rABmag2,rAB; double delxBC,delyBC,delzBC,rBCmag2,rBC; double delxBD,delyBD,delzBD,rBDmag2,rBD; double costhABC,thetaABC,costhABD; double thetaABD,costhCBD,thetaCBD,dthABC,dthCBD,dthABD; double sc1,t1,t3,r12; double dthetadr[3][4][3],fabcd[4][3]; double **x = atom->x; double **f = atom->f; int **improperlist = neighbor->improperlist; int nimproperlist = neighbor->nimproperlist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < nimproperlist; n++) { i1 = improperlist[n][0]; i2 = improperlist[n][1]; i3 = improperlist[n][2]; i4 = improperlist[n][3]; type = improperlist[n][4]; if ((aa_k1[type] == 0.0) && (aa_k2[type] == 0.0) && (aa_k3[type] == 0.0)) continue; // difference vectors delxAB = x[i1][0] - x[i2][0]; delyAB = x[i1][1] - x[i2][1]; delzAB = x[i1][2] - x[i2][2]; delxBC = x[i3][0] - x[i2][0]; delyBC = x[i3][1] - x[i2][1]; delzBC = x[i3][2] - x[i2][2]; delxBD = x[i4][0] - x[i2][0]; delyBD = x[i4][1] - x[i2][1]; delzBD = x[i4][2] - x[i2][2]; // bond lengths rABmag2 = delxAB*delxAB + delyAB*delyAB + delzAB*delzAB; rAB = sqrt(rABmag2); rBCmag2 = delxBC*delxBC + delyBC*delyBC + delzBC*delzBC; rBC = sqrt(rBCmag2); rBDmag2 = delxBD*delxBD + delyBD*delyBD + delzBD*delzBD; rBD = sqrt(rBDmag2); // angle ABC, ABD, CBD costhABC = (delxAB*delxBC + delyAB*delyBC + delzAB*delzBC) / (rAB * rBC); if (costhABC > 1.0) costhABC = 1.0; if (costhABC < -1.0) costhABC = -1.0; thetaABC = acos(costhABC); costhABD = (delxAB*delxBD + delyAB*delyBD + delzAB*delzBD) / (rAB * rBD); if (costhABD > 1.0) costhABD = 1.0; if (costhABD < -1.0) costhABD = -1.0; thetaABD = acos(costhABD); costhCBD = (delxBC*delxBD + delyBC*delyBD + delzBC*delzBD) /(rBC * rBD); if (costhCBD > 1.0) costhCBD = 1.0; if (costhCBD < -1.0) costhCBD = -1.0; thetaCBD = acos(costhCBD); dthABC = thetaABC - aa_theta0_1[type]; dthABD = thetaABD - aa_theta0_2[type]; dthCBD = thetaCBD - aa_theta0_3[type]; // energy if (eflag) eimproper = aa_k2[type] * dthABC * dthABD + aa_k1[type] * dthABC * dthCBD + aa_k3[type] * dthABD * dthCBD; // d(theta)/d(r) array // angle i, atom j, coordinate k for (i = 0; i < 3; i++) for (j = 0; j < 4; j++) for (k = 0; k < 3; k++) dthetadr[i][j][k] = 0.0; // angle ABC sc1 = sqrt(1.0/(1.0 - costhABC*costhABC)); t1 = costhABC / rABmag2; t3 = costhABC / rBCmag2; r12 = 1.0 / (rAB * rBC); dthetadr[0][0][0] = sc1 * ((t1 * delxAB) - (delxBC * r12)); dthetadr[0][0][1] = sc1 * ((t1 * delyAB) - (delyBC * r12)); dthetadr[0][0][2] = sc1 * ((t1 * delzAB) - (delzBC * r12)); dthetadr[0][1][0] = sc1 * ((-t1 * delxAB) + (delxBC * r12) + (-t3 * delxBC) + (delxAB * r12)); dthetadr[0][1][1] = sc1 * ((-t1 * delyAB) + (delyBC * r12) + (-t3 * delyBC) + (delyAB * r12)); dthetadr[0][1][2] = sc1 * ((-t1 * delzAB) + (delzBC * r12) + (-t3 * delzBC) + (delzAB * r12)); dthetadr[0][2][0] = sc1 * ((t3 * delxBC) - (delxAB * r12)); dthetadr[0][2][1] = sc1 * ((t3 * delyBC) - (delyAB * r12)); dthetadr[0][2][2] = sc1 * ((t3 * delzBC) - (delzAB * r12)); // angle CBD sc1 = sqrt(1.0/(1.0 - costhCBD*costhCBD)); t1 = costhCBD / rBCmag2; t3 = costhCBD / rBDmag2; r12 = 1.0 / (rBC * rBD); dthetadr[1][2][0] = sc1 * ((t1 * delxBC) - (delxBD * r12)); dthetadr[1][2][1] = sc1 * ((t1 * delyBC) - (delyBD * r12)); dthetadr[1][2][2] = sc1 * ((t1 * delzBC) - (delzBD * r12)); dthetadr[1][1][0] = sc1 * ((-t1 * delxBC) + (delxBD * r12) + (-t3 * delxBD) + (delxBC * r12)); dthetadr[1][1][1] = sc1 * ((-t1 * delyBC) + (delyBD * r12) + (-t3 * delyBD) + (delyBC * r12)); dthetadr[1][1][2] = sc1 * ((-t1 * delzBC) + (delzBD * r12) + (-t3 * delzBD) + (delzBC * r12)); dthetadr[1][3][0] = sc1 * ((t3 * delxBD) - (delxBC * r12)); dthetadr[1][3][1] = sc1 * ((t3 * delyBD) - (delyBC * r12)); dthetadr[1][3][2] = sc1 * ((t3 * delzBD) - (delzBC * r12)); // angle ABD sc1 = sqrt(1.0/(1.0 - costhABD*costhABD)); t1 = costhABD / rABmag2; t3 = costhABD / rBDmag2; r12 = 1.0 / (rAB * rBD); dthetadr[2][0][0] = sc1 * ((t1 * delxAB) - (delxBD * r12)); dthetadr[2][0][1] = sc1 * ((t1 * delyAB) - (delyBD * r12)); dthetadr[2][0][2] = sc1 * ((t1 * delzAB) - (delzBD * r12)); dthetadr[2][1][0] = sc1 * ((-t1 * delxAB) + (delxBD * r12) + (-t3 * delxBD) + (delxAB * r12)); dthetadr[2][1][1] = sc1 * ((-t1 * delyAB) + (delyBD * r12) + (-t3 * delyBD) + (delyAB * r12)); dthetadr[2][1][2] = sc1 * ((-t1 * delzAB) + (delzBD * r12) + (-t3 * delzBD) + (delzAB * r12)); dthetadr[2][3][0] = sc1 * ((t3 * delxBD) - (delxAB * r12)); dthetadr[2][3][1] = sc1 * ((t3 * delyBD) - (delyAB * r12)); dthetadr[2][3][2] = sc1 * ((t3 * delzBD) - (delzAB * r12)); // angleangle forces for (i = 0; i < 4; i++) for (j = 0; j < 3; j++) fabcd[i][j] = - ((aa_k1[type] * (dthABC*dthetadr[1][i][j] + dthCBD*dthetadr[0][i][j])) + (aa_k2[type] * (dthABC*dthetadr[2][i][j] + dthABD*dthetadr[0][i][j])) + (aa_k3[type] * (dthABD*dthetadr[1][i][j] + dthCBD*dthetadr[2][i][j]))); // apply force to each of 4 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += fabcd[0][0]; f[i1][1] += fabcd[0][1]; f[i1][2] += fabcd[0][2]; } if (newton_bond || i2 < nlocal) { f[i2][0] += fabcd[1][0]; f[i2][1] += fabcd[1][1]; f[i2][2] += fabcd[1][2]; } if (newton_bond || i3 < nlocal) { f[i3][0] += fabcd[2][0]; f[i3][1] += fabcd[2][1]; f[i3][2] += fabcd[2][2]; } if (newton_bond || i4 < nlocal) { f[i4][0] += fabcd[3][0]; f[i4][1] += fabcd[3][1]; f[i4][2] += fabcd[3][2]; } if (evflag) ev_tally(i1,i2,i3,i4,nlocal,newton_bond,eimproper, fabcd[0],fabcd[2],fabcd[3], delxAB,delyAB,delzAB,delxBC,delyBC,delzBC, delxBD-delxBC,delyBD-delyBC,delzBD-delzBC); } } /* ---------------------------------------------------------------------- cross product: c = a x b ------------------------------------------------------------------------- */ void ImproperClass2::cross(double *a, double *b, double *c) { c[0] = a[1]*b[2] - a[2]*b[1]; c[1] = a[2]*b[0] - a[0]*b[2]; c[2] = a[0]*b[1] - a[1]*b[0]; } /* ---------------------------------------------------------------------- dot product of a dot b ------------------------------------------------------------------------- */ double ImproperClass2::dot(double *a, double *b) { return (a[0]*b[0] + a[1]*b[1] + a[2]*b[2]); } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void ImproperClass2::write_data(FILE *fp) { for (int i = 1; i <= atom->nimpropertypes; i++) fprintf(fp,"%d %g %g\n",i,k0[i],chi0[i]); fprintf(fp,"\nAngleAngle Coeffs\n\n"); for (int i = 1; i <= atom->nimpropertypes; i++) fprintf(fp,"%d %g %g %g %g %g %g\n",i,aa_k1[i],aa_k2[i],aa_k3[i], aa_theta0_1[i]*180.0/MY_PI,aa_theta0_2[i]*180.0/MY_PI, aa_theta0_3[i]*180.0/MY_PI); } diff --git a/src/CLASS2/pair_lj_class2.cpp b/src/CLASS2/pair_lj_class2.cpp index 0974769b9..ee61aaae1 100644 --- a/src/CLASS2/pair_lj_class2.cpp +++ b/src/CLASS2/pair_lj_class2.cpp @@ -1,396 +1,396 @@ /* ---------------------------------------------------------------------- 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 #include #include #include "pair_lj_class2.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; /* ---------------------------------------------------------------------- */ PairLJClass2::PairLJClass2(LAMMPS *lmp) : Pair(lmp) { writedata = 1; } /* ---------------------------------------------------------------------- */ PairLJClass2::~PairLJClass2() { if (!copymode) { 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 PairLJClass2::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,rinv,r2inv,r3inv,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; rinv = sqrt(r2inv); r3inv = r2inv*rinv; r6inv = r3inv*r3inv; forcelj = r6inv * (lj1[itype][jtype]*r3inv - 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]*r3inv-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(); } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairLJClass2::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 PairLJClass2::settings(int narg, char **arg) { if (narg != 1) error->all(FLERR,"Illegal pair_style command"); cut_global = force->numeric(FLERR,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 PairLJClass2::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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(FLERR,arg[2]); double sigma_one = force->numeric(FLERR,arg[3]); double cut_one = cut_global; if (narg == 5) cut_one = force->numeric(FLERR,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 for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairLJClass2::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[i][j] = mix_distance(cut[i][i],cut[j][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[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; 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[i][j]*cut[i][j]*cut[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[i][j]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJClass2::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 PairLJClass2::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 PairLJClass2::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); fwrite(&tail_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJClass2::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); fread(&tail_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); MPI_Bcast(&tail_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void PairLJClass2::write_data(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) fprintf(fp,"%d %g %g\n",i,epsilon[i][i],sigma[i][i]); } /* ---------------------------------------------------------------------- proc 0 writes all pairs to data file ------------------------------------------------------------------------- */ void PairLJClass2::write_data_all(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) fprintf(fp,"%d %d %g %g %g\n",i,j,epsilon[i][j],sigma[i][j],cut[i][j]); } /* ---------------------------------------------------------------------- */ double PairLJClass2::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r2inv,rinv,r3inv,r6inv,forcelj,philj; r2inv = 1.0/rsq; rinv = sqrt(r2inv); r3inv = r2inv*rinv; r6inv = r3inv*r3inv; forcelj = r6inv * (lj1[itype][jtype]*r3inv - lj2[itype][jtype]); fforce = factor_lj*forcelj*r2inv; philj = r6inv*(lj3[itype][jtype]*r3inv-lj4[itype][jtype]) - offset[itype][jtype]; return factor_lj*philj; } diff --git a/src/CLASS2/pair_lj_class2_coul_cut.cpp b/src/CLASS2/pair_lj_class2_coul_cut.cpp index c7c473868..45f0ccfe2 100644 --- a/src/CLASS2/pair_lj_class2_coul_cut.cpp +++ b/src/CLASS2/pair_lj_class2_coul_cut.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 #include #include #include "pair_lj_class2_coul_cut.h" #include "atom.h" #include "comm.h" #include "force.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; /* ---------------------------------------------------------------------- */ PairLJClass2CoulCut::PairLJClass2CoulCut(LAMMPS *lmp) : Pair(lmp) { writedata = 1; } /* ---------------------------------------------------------------------- */ PairLJClass2CoulCut::~PairLJClass2CoulCut() { if (!copymode) { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut_lj); memory->destroy(cut_ljsq); memory->destroy(cut_coul); memory->destroy(cut_coulsq); memory->destroy(epsilon); memory->destroy(sigma); memory->destroy(lj1); memory->destroy(lj2); memory->destroy(lj3); memory->destroy(lj4); memory->destroy(offset); } } } /* ---------------------------------------------------------------------- */ void PairLJClass2CoulCut::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,rinv,r2inv,r3inv,r6inv,forcecoul,forcelj; 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[itype][jtype]) forcecoul = qqrd2e * qtmp*q[j]*sqrt(r2inv); 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 = (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[itype][jtype]) ecoul = factor_coul * qqrd2e * qtmp*q[j]*sqrt(r2inv); 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 PairLJClass2CoulCut::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(cut_coul,n+1,n+1,"pair:cut_coul"); memory->create(cut_coulsq,n+1,n+1,"pair:cut_coulsq"); 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 PairLJClass2CoulCut::settings(int narg, char **arg) { if (narg < 1 || narg > 2) error->all(FLERR,"Illegal pair_style command"); cut_lj_global = force->numeric(FLERR,arg[0]); if (narg == 1) cut_coul_global = cut_lj_global; else cut_coul_global = force->numeric(FLERR,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; cut_coul[i][j] = cut_coul_global; } } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairLJClass2CoulCut::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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(FLERR,arg[2]); double sigma_one = force->numeric(FLERR,arg[3]); double cut_lj_one = cut_lj_global; double cut_coul_one = cut_coul_global; if (narg >= 5) cut_coul_one = cut_lj_one = force->numeric(FLERR,arg[4]); if (narg == 6) cut_coul_one = force->numeric(FLERR,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; cut_lj[i][j] = cut_lj_one; cut_coul[i][j] = cut_coul_one; setflag[i][j] = 1; count++; } } if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairLJClass2CoulCut::init_style() { if (!atom->q_flag) error->all(FLERR,"Pair style lj/class2/coul/cut requires atom attribute q"); neighbor->request(this,instance_me); } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairLJClass2CoulCut::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]); cut_coul[i][j] = mix_distance(cut_coul[i][i],cut_coul[j][j]); } double cut = MAX(cut_lj[i][j],cut_coul[i][j]); cut_ljsq[i][j] = cut_lj[i][j] * cut_lj[i][j]; cut_coulsq[i][j] = cut_coul[i][j] * cut_coul[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]; cut_coulsq[j][i] = cut_coulsq[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 PairLJClass2CoulCut::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); fwrite(&cut_coul[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJClass2CoulCut::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); fread(&cut_coul[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); MPI_Bcast(&cut_coul[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJClass2CoulCut::write_restart_settings(FILE *fp) { fwrite(&cut_lj_global,sizeof(double),1,fp); fwrite(&cut_coul_global,sizeof(double),1,fp); fwrite(&offset_flag,sizeof(int),1,fp); fwrite(&mix_flag,sizeof(int),1,fp); fwrite(&tail_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJClass2CoulCut::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&cut_lj_global,sizeof(double),1,fp); fread(&cut_coul_global,sizeof(double),1,fp); fread(&offset_flag,sizeof(int),1,fp); fread(&mix_flag,sizeof(int),1,fp); fread(&tail_flag,sizeof(int),1,fp); } MPI_Bcast(&cut_lj_global,1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_coul_global,1,MPI_DOUBLE,0,world); MPI_Bcast(&offset_flag,1,MPI_INT,0,world); MPI_Bcast(&mix_flag,1,MPI_INT,0,world); MPI_Bcast(&tail_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void PairLJClass2CoulCut::write_data(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) fprintf(fp,"%d %g %g\n",i,epsilon[i][i],sigma[i][i]); } /* ---------------------------------------------------------------------- proc 0 writes all pairs to data file ------------------------------------------------------------------------- */ void PairLJClass2CoulCut::write_data_all(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) fprintf(fp,"%d %d %g %g %g\n",i,j,epsilon[i][j],sigma[i][j],cut_lj[i][j]); } /* ---------------------------------------------------------------------- */ double PairLJClass2CoulCut::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r2inv,rinv,r3inv,r6inv,forcecoul,forcelj,phicoul,philj; r2inv = 1.0/rsq; if (rsq < cut_coulsq[itype][jtype]) forcecoul = force->qqrd2e * atom->q[i]*atom->q[j]*sqrt(r2inv); 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 = (factor_coul*forcecoul + factor_lj*forcelj) * r2inv; double eng = 0.0; if (rsq < cut_coulsq[itype][jtype]) { phicoul = force->qqrd2e * atom->q[i]*atom->q[j]*sqrt(r2inv); eng += factor_coul*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; } diff --git a/src/CLASS2/pair_lj_class2_coul_long.cpp b/src/CLASS2/pair_lj_class2_coul_long.cpp index 62ffdab6e..b58094713 100644 --- a/src/CLASS2/pair_lj_class2_coul_long.cpp +++ b/src/CLASS2/pair_lj_class2_coul_long.cpp @@ -1,552 +1,552 @@ /* ---------------------------------------------------------------------- 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 #include #include #include #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) { ewaldflag = pppmflag = 1; writedata = 1; ftable = NULL; } /* ---------------------------------------------------------------------- */ PairLJClass2CoulLong::~PairLJClass2CoulLong() { if (!copymode) { 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,itable,itype,jtype; double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair; double fraction,table; 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) { 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]) { 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) { 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]*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(FLERR,arg[0]); if (narg == 1) cut_coul = cut_lj_global; else cut_coul = force->numeric(FLERR,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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(FLERR,arg[2]); double sigma_one = force->numeric(FLERR,arg[3]); double cut_lj_one = cut_lj_global; if (narg == 5) cut_lj_one = force->numeric(FLERR,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,instance_me); 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 requires a KSpace style"); g_ewald = force->kspace->g_ewald; // setup force tables if (ncoultablebits) init_tables(cut_coul,NULL); } /* ---------------------------------------------------------------------- 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); fwrite(&tail_flag,sizeof(int),1,fp); fwrite(&ncoultablebits,sizeof(int),1,fp); fwrite(&tabinner,sizeof(double),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); fread(&tail_flag,sizeof(int),1,fp); fread(&ncoultablebits,sizeof(int),1,fp); fread(&tabinner,sizeof(double),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); MPI_Bcast(&tail_flag,1,MPI_INT,0,world); MPI_Bcast(&ncoultablebits,1,MPI_INT,0,world); MPI_Bcast(&tabinner,1,MPI_DOUBLE,0,world); } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void PairLJClass2CoulLong::write_data(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) fprintf(fp,"%d %g %g\n",i,epsilon[i][i],sigma[i][i]); } /* ---------------------------------------------------------------------- proc 0 writes all pairs to data file ------------------------------------------------------------------------- */ void PairLJClass2CoulLong::write_data_all(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) fprintf(fp,"%d %d %g %g %g\n",i,j,epsilon[i][j],sigma[i][j],cut_lj[i][j]); } /* ---------------------------------------------------------------------- */ 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 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[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) { 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]*r3inv-lj4[itype][jtype]) - offset[itype][jtype]; eng += factor_lj*philj; } return eng; } /* ---------------------------------------------------------------------- */ 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/COLLOID/pair_brownian.cpp b/src/COLLOID/pair_brownian.cpp index c1cc523d3..84fda485a 100644 --- a/src/COLLOID/pair_brownian.cpp +++ b/src/COLLOID/pair_brownian.cpp @@ -1,733 +1,733 @@ /* ---------------------------------------------------------------------- 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: Amit Kumar and Michael Bybee (UIUC) ------------------------------------------------------------------------- */ #include #include #include #include #include "pair_brownian.h" #include "atom.h" #include "atom_vec.h" #include "comm.h" #include "force.h" #include "neighbor.h" #include "neigh_list.h" #include "neigh_request.h" #include "domain.h" #include "update.h" #include "modify.h" #include "fix.h" #include "fix_deform.h" #include "fix_wall.h" #include "input.h" #include "variable.h" #include "random_mars.h" #include "math_const.h" #include "math_special.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace MathConst; using namespace MathSpecial; // same as fix_wall.cpp enum{EDGE,CONSTANT,VARIABLE}; /* ---------------------------------------------------------------------- */ PairBrownian::PairBrownian(LAMMPS *lmp) : Pair(lmp) { single_enable = 0; random = NULL; } /* ---------------------------------------------------------------------- */ PairBrownian::~PairBrownian() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut); memory->destroy(cut_inner); } delete random; } /* ---------------------------------------------------------------------- */ void PairBrownian::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,fx,fy,fz,tx,ty,tz; double rsq,r,h_sep,radi; int *ilist,*jlist,*numneigh,**firstneigh; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; double **x = atom->x; double **f = atom->f; double **torque = atom->torque; double *radius = atom->radius; int *type = atom->type; int nlocal = atom->nlocal; int newton_pair = force->newton_pair; double vxmu2f = force->vxmu2f; double randr; double prethermostat; double xl[3],a_sq,a_sh,a_pu,Fbmag; double p1[3],p2[3],p3[3]; int overlaps = 0; // This section of code adjusts R0/RT0/RS0 if necessary due to changes // in the volume fraction as a result of fix deform or moving walls double dims[3], wallcoord; if (flagVF) // Flag for volume fraction corrections if (flagdeform || flagwall == 2){ // Possible changes in volume fraction if (flagdeform && !flagwall) for (j = 0; j < 3; j++) dims[j] = domain->prd[j]; else if (flagwall == 2 || (flagdeform && flagwall == 1)){ double wallhi[3], walllo[3]; for (int j = 0; j < 3; j++){ wallhi[j] = domain->prd[j]; walllo[j] = 0; } for (int m = 0; m < wallfix->nwall; m++){ int dim = wallfix->wallwhich[m] / 2; int side = wallfix->wallwhich[m] % 2; if (wallfix->xstyle[m] == VARIABLE){ wallcoord = input->variable->compute_equal(wallfix->xindex[m]); } else wallcoord = wallfix->coord0[m]; if (side == 0) walllo[dim] = wallcoord; else wallhi[dim] = wallcoord; } for (int j = 0; j < 3; j++) dims[j] = wallhi[j] - walllo[j]; } double vol_T = dims[0]*dims[1]*dims[2]; double vol_f = vol_P/vol_T; if (flaglog == 0) { R0 = 6*MY_PI*mu*rad*(1.0 + 2.16*vol_f); RT0 = 8*MY_PI*mu*cube(rad); //RS0 = 20.0/3.0*MY_PI*mu*pow(rad,3)*(1.0 + 3.33*vol_f + 2.80*vol_f*vol_f); } else { R0 = 6*MY_PI*mu*rad*(1.0 + 2.725*vol_f - 6.583*vol_f*vol_f); RT0 = 8*MY_PI*mu*cube(rad)*(1.0 + 0.749*vol_f - 2.469*vol_f*vol_f); //RS0 = 20.0/3.0*MY_PI*mu*pow(rad,3)*(1.0 + 3.64*vol_f - 6.95*vol_f*vol_f); } } // scale factor for Brownian moments prethermostat = sqrt(24.0*force->boltz*t_target/update->dt); prethermostat *= sqrt(force->vxmu2f/force->ftm2v/force->mvv2e); inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; for (ii = 0; ii < inum; ii++) { i = ilist[ii]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; radi = radius[i]; jlist = firstneigh[i]; jnum = numneigh[i]; // FLD contribution to force and torque due to isotropic terms if (flagfld) { f[i][0] += prethermostat*sqrt(R0)*(random->uniform()-0.5); f[i][1] += prethermostat*sqrt(R0)*(random->uniform()-0.5); f[i][2] += prethermostat*sqrt(R0)*(random->uniform()-0.5); if (flaglog) { torque[i][0] += prethermostat*sqrt(RT0)*(random->uniform()-0.5); torque[i][1] += prethermostat*sqrt(RT0)*(random->uniform()-0.5); torque[i][2] += prethermostat*sqrt(RT0)*(random->uniform()-0.5); } } if (!flagHI) continue; 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]; if (rsq < cutsq[itype][jtype]) { r = sqrt(rsq); // scalar resistances a_sq and a_sh h_sep = r - 2.0*radi; // check for overlaps if (h_sep < 0.0) overlaps++; // if less than minimum gap, use minimum gap instead if (r < cut_inner[itype][jtype]) h_sep = cut_inner[itype][jtype] - 2.0*radi; // scale h_sep by radi h_sep = h_sep/radi; // scalar resistances if (flaglog) { a_sq = 6.0*MY_PI*mu*radi*(1.0/4.0/h_sep + 9.0/40.0*log(1.0/h_sep)); a_sh = 6.0*MY_PI*mu*radi*(1.0/6.0*log(1.0/h_sep)); a_pu = 8.0*MY_PI*mu*cube(radi)*(3.0/160.0*log(1.0/h_sep)); } else a_sq = 6.0*MY_PI*mu*radi*(1.0/4.0/h_sep); // generate the Pairwise Brownian Force: a_sq Fbmag = prethermostat*sqrt(a_sq); // generate a random number randr = random->uniform()-0.5; // contribution due to Brownian motion fx = Fbmag*randr*delx/r; fy = Fbmag*randr*dely/r; fz = Fbmag*randr*delz/r; // add terms due to a_sh if (flaglog) { // generate two orthogonal vectors to the line of centers p1[0] = delx/r; p1[1] = dely/r; p1[2] = delz/r; set_3_orthogonal_vectors(p1,p2,p3); // magnitude Fbmag = prethermostat*sqrt(a_sh); // force in each of the two directions randr = random->uniform()-0.5; fx += Fbmag*randr*p2[0]; fy += Fbmag*randr*p2[1]; fz += Fbmag*randr*p2[2]; randr = random->uniform()-0.5; fx += Fbmag*randr*p3[0]; fy += Fbmag*randr*p3[1]; fz += Fbmag*randr*p3[2]; } // scale forces to appropriate units fx = vxmu2f*fx; fy = vxmu2f*fy; fz = vxmu2f*fz; // sum to total force f[i][0] -= fx; f[i][1] -= fy; f[i][2] -= fz; if (newton_pair || j < nlocal) { //randr = random->uniform()-0.5; //fx = Fbmag*randr*delx/r; //fy = Fbmag*randr*dely/r; //fz = Fbmag*randr*delz/r; f[j][0] += fx; f[j][1] += fy; f[j][2] += fz; } // torque due to the Brownian Force if (flaglog) { // location of the point of closest approach on I from its center xl[0] = -delx/r*radi; xl[1] = -dely/r*radi; xl[2] = -delz/r*radi; // torque = xl_cross_F tx = xl[1]*fz - xl[2]*fy; ty = xl[2]*fx - xl[0]*fz; tz = xl[0]*fy - xl[1]*fx; // torque is same on both particles torque[i][0] -= tx; torque[i][1] -= ty; torque[i][2] -= tz; if (newton_pair || j < nlocal) { torque[j][0] -= tx; torque[j][1] -= ty; torque[j][2] -= tz; } // torque due to a_pu Fbmag = prethermostat*sqrt(a_pu); // force in each direction randr = random->uniform()-0.5; tx = Fbmag*randr*p2[0]; ty = Fbmag*randr*p2[1]; tz = Fbmag*randr*p2[2]; randr = random->uniform()-0.5; tx += Fbmag*randr*p3[0]; ty += Fbmag*randr*p3[1]; tz += Fbmag*randr*p3[2]; // torque has opposite sign on two particles torque[i][0] -= tx; torque[i][1] -= ty; torque[i][2] -= tz; if (newton_pair || j < nlocal) { torque[j][0] += tx; torque[j][1] += ty; torque[j][2] += tz; } } if (evflag) ev_tally_xyz(i,j,nlocal,newton_pair, 0.0,0.0,-fx,-fy,-fz,delx,dely,delz); } } } int print_overlaps = 0; if (print_overlaps && overlaps) printf("Number of overlaps=%d\n",overlaps); if (vflag_fdotr) virial_fdotr_compute(); } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairBrownian::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(cut_inner,n+1,n+1,"pair:cut_inner"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairBrownian::settings(int narg, char **arg) { if (narg != 7 && narg != 9) error->all(FLERR,"Illegal pair_style command"); mu = force->numeric(FLERR,arg[0]); flaglog = force->inumeric(FLERR,arg[1]); flagfld = force->inumeric(FLERR,arg[2]); cut_inner_global = force->numeric(FLERR,arg[3]); cut_global = force->numeric(FLERR,arg[4]); t_target = force->numeric(FLERR,arg[5]); seed = force->inumeric(FLERR,arg[6]); flagHI = flagVF = 1; if (narg == 9) { flagHI = force->inumeric(FLERR,arg[7]); flagVF = force->inumeric(FLERR,arg[8]); } if (flaglog == 1 && flagHI == 0) { error->warning(FLERR,"Cannot include log terms without 1/r terms; " "setting flagHI to 1"); flagHI = 1; } // initialize Marsaglia RNG with processor-unique seed delete random; random = new RanMars(lmp,seed + comm->me); // reset cutoffs that have been explicitly set if (allocated) { for (int i = 1; i <= atom->ntypes; i++) for (int j = i+1; j <= atom->ntypes; j++) if (setflag[i][j]) { cut_inner[i][j] = cut_inner_global; cut[i][j] = cut_global; } } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairBrownian::coeff(int narg, char **arg) { if (narg != 2 && 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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double cut_inner_one = cut_inner_global; double cut_one = cut_global; if (narg == 4) { cut_inner_one = force->numeric(FLERR,arg[2]); cut_one = force->numeric(FLERR,arg[3]); } int count = 0; for (int i = ilo; i <= ihi; i++) for (int j = MAX(jlo,i); j <= jhi; j++) { cut_inner[i][j] = cut_inner_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 PairBrownian::init_style() { if (!atom->sphere_flag) error->all(FLERR,"Pair brownian requires atom style sphere"); // if newton off, forces between atoms ij will be double computed // using different random numbers if (force->newton_pair == 0 && comm->me == 0) error->warning(FLERR, "Pair brownian needs newton pair on for " "momentum conservation"); neighbor->request(this,instance_me); // insure all particles are finite-size // for pair hybrid, should limit test to types using the pair style double *radius = atom->radius; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (radius[i] == 0.0) error->one(FLERR,"Pair brownian requires extended particles"); // require monodisperse system with same radii for all types double radtype; for (int i = 1; i <= atom->ntypes; i++) { if (!atom->radius_consistency(i,radtype)) error->all(FLERR,"Pair brownian requires monodisperse particles"); if (i > 1 && radtype != rad) error->all(FLERR,"Pair brownian requires monodisperse particles"); rad = radtype; } // set the isotropic constants that depend on the volume fraction // vol_T = total volume // check for fix deform, if exists it must use "remap v" // If box will change volume, set appropriate flag so that volume // and v.f. corrections are re-calculated at every step. // // If available volume is different from box volume // due to walls, set volume appropriately; if walls will // move, set appropriate flag so that volume and v.f. corrections // are re-calculated at every step. flagdeform = flagwall = 0; for (int i = 0; i < modify->nfix; i++){ if (strcmp(modify->fix[i]->style,"deform") == 0) flagdeform = 1; else if (strstr(modify->fix[i]->style,"wall") != NULL) { if (flagwall) error->all(FLERR, "Cannot use multiple fix wall commands with pair brownian"); flagwall = 1; // Walls exist wallfix = (FixWall *) modify->fix[i]; if (wallfix->xflag) flagwall = 2; // Moving walls exist } } // set the isotropic constants depending on the volume fraction // vol_T = total volumeshearing = flagdeform = flagwall = 0; double vol_T, wallcoord; if (!flagwall) vol_T = domain->xprd*domain->yprd*domain->zprd; else { double wallhi[3], walllo[3]; for (int j = 0; j < 3; j++){ wallhi[j] = domain->prd[j]; walllo[j] = 0; } for (int m = 0; m < wallfix->nwall; m++){ int dim = wallfix->wallwhich[m] / 2; int side = wallfix->wallwhich[m] % 2; if (wallfix->xstyle[m] == VARIABLE){ wallfix->xindex[m] = input->variable->find(wallfix->xstr[m]); // Since fix->wall->init happens after pair->init_style wallcoord = input->variable->compute_equal(wallfix->xindex[m]); } else wallcoord = wallfix->coord0[m]; if (side == 0) walllo[dim] = wallcoord; else wallhi[dim] = wallcoord; } vol_T = (wallhi[0] - walllo[0]) * (wallhi[1] - walllo[1]) * (wallhi[2] - walllo[2]); } // vol_P = volume of particles, assuming mono-dispersity // vol_f = volume fraction vol_P = atom->natoms*(4.0/3.0)*MY_PI*cube(rad); double vol_f = vol_P/vol_T; // set isotropic constants if (!flagVF) vol_f = 0; if (flaglog == 0) { R0 = 6*MY_PI*mu*rad*(1.0 + 2.16*vol_f); RT0 = 8*MY_PI*mu*cube(rad); // not actually needed } else { R0 = 6*MY_PI*mu*rad*(1.0 + 2.725*vol_f - 6.583*vol_f*vol_f); RT0 = 8*MY_PI*mu*cube(rad)*(1.0 + 0.749*vol_f - 2.469*vol_f*vol_f); } } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairBrownian::init_one(int i, int j) { if (setflag[i][j] == 0) { cut_inner[i][j] = mix_distance(cut_inner[i][i],cut_inner[j][j]); cut[i][j] = mix_distance(cut[i][i],cut[j][j]); } cut_inner[j][i] = cut_inner[i][j]; return cut[i][j]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairBrownian::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_inner[i][j],sizeof(double),1,fp); fwrite(&cut[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairBrownian::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_inner[i][j],sizeof(double),1,fp); fread(&cut[i][j],sizeof(double),1,fp); } MPI_Bcast(&cut_inner[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairBrownian::write_restart_settings(FILE *fp) { fwrite(&mu,sizeof(double),1,fp); fwrite(&flaglog,sizeof(int),1,fp); fwrite(&flagfld,sizeof(int),1,fp); fwrite(&cut_inner_global,sizeof(double),1,fp); fwrite(&cut_global,sizeof(double),1,fp); fwrite(&t_target,sizeof(double),1,fp); fwrite(&seed,sizeof(int),1,fp); fwrite(&offset_flag,sizeof(int),1,fp); fwrite(&mix_flag,sizeof(int),1,fp); fwrite(&flagHI,sizeof(int),1,fp); fwrite(&flagVF,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairBrownian::read_restart_settings(FILE *fp) { int me = comm->me; if (me == 0) { fread(&mu,sizeof(double),1,fp); fread(&flaglog,sizeof(int),1,fp); fread(&flagfld,sizeof(int),1,fp); fread(&cut_inner_global,sizeof(double),1,fp); fread(&cut_global,sizeof(double),1,fp); fread(&t_target, sizeof(double),1,fp); fread(&seed, sizeof(int),1,fp); fread(&offset_flag,sizeof(int),1,fp); fread(&mix_flag,sizeof(int),1,fp); fread(&flagHI,sizeof(int),1,fp); fread(&flagVF,sizeof(int),1,fp); } MPI_Bcast(&mu,1,MPI_DOUBLE,0,world); MPI_Bcast(&flaglog,1,MPI_INT,0,world); MPI_Bcast(&flagfld,1,MPI_INT,0,world); MPI_Bcast(&cut_inner_global,1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world); MPI_Bcast(&t_target,1,MPI_DOUBLE,0,world); MPI_Bcast(&seed,1,MPI_INT,0,world); MPI_Bcast(&offset_flag,1,MPI_INT,0,world); MPI_Bcast(&mix_flag,1,MPI_INT,0,world); MPI_Bcast(&flagHI,1,MPI_INT,0,world); MPI_Bcast(&flagVF,1,MPI_INT,0,world); // additional setup based on restart parameters delete random; random = new RanMars(lmp,seed + comm->me); } /* ----------------------------------------------------------------------*/ void PairBrownian::set_3_orthogonal_vectors(double p1[3], double p2[3], double p3[3]) { double norm; int ix,iy,iz; // find the index of maximum magnitude and store it in iz if (fabs(p1[0]) > fabs(p1[1])) { iz=0; ix=1; iy=2; } else { iz=1; ix=2; iy=0; } if (iz==0) { if (fabs(p1[0]) < fabs(p1[2])) { iz = 2; ix = 0; iy = 1; } } else { if (fabs(p1[1]) < fabs(p1[2])) { iz = 2; ix = 0; iy = 1; } } // set p2 arbitrarily such that it's orthogonal to p1 p2[ix]=1.0; p2[iy]=1.0; p2[iz] = -(p1[ix]*p2[ix] + p1[iy]*p2[iy])/p1[iz]; // normalize p2 norm = sqrt(p2[0]*p2[0] + p2[1]*p2[1] + p2[2]*p2[2]); p2[0] = p2[0]/norm; p2[1] = p2[1]/norm; p2[2] = p2[2]/norm; // Set p3 by taking the cross product p3=p2xp1 p3[0] = p1[1]*p2[2] - p1[2]*p2[1]; p3[1] = p1[2]*p2[0] - p1[0]*p2[2]; p3[2] = p1[0]*p2[1] - p1[1]*p2[0]; } diff --git a/src/COLLOID/pair_colloid.cpp b/src/COLLOID/pair_colloid.cpp index b5d83233a..440d6f9d4 100644 --- a/src/COLLOID/pair_colloid.cpp +++ b/src/COLLOID/pair_colloid.cpp @@ -1,545 +1,545 @@ /* ---------------------------------------------------------------------- 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: Pieter in 't Veld (SNL) ------------------------------------------------------------------------- */ #include #include #include #include #include "pair_colloid.h" #include "atom.h" #include "comm.h" #include "force.h" #include "neighbor.h" #include "neigh_list.h" #include "math_special.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace MathSpecial; /* ---------------------------------------------------------------------- */ PairColloid::PairColloid(LAMMPS *lmp) : Pair(lmp) { writedata = 1; } /* ---------------------------------------------------------------------- */ PairColloid::~PairColloid() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(form); memory->destroy(a12); memory->destroy(sigma); memory->destroy(d1); memory->destroy(d2); memory->destroy(a1); memory->destroy(a2); memory->destroy(diameter); memory->destroy(cut); memory->destroy(offset); memory->destroy(sigma3); memory->destroy(sigma6); memory->destroy(lj1); memory->destroy(lj2); memory->destroy(lj3); memory->destroy(lj4); } } /* ---------------------------------------------------------------------- */ void PairColloid::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,r,forcelj,factor_lj; double r2inv,r6inv,c1,c2,fR,dUR,dUA; double K[9],h[4],g[4]; 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]) continue; switch (form[itype][jtype]) { case SMALL_SMALL: r2inv = 1.0/rsq; r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); fpair = factor_lj*forcelj*r2inv; if (eflag) evdwl = r6inv*(r6inv*lj3[itype][jtype]-lj4[itype][jtype]) - offset[itype][jtype]; break; case SMALL_LARGE: c2 = a2[itype][jtype]; K[1] = c2*c2; K[2] = rsq; K[0] = K[1] - rsq; K[4] = rsq*rsq; K[3] = K[1] - K[2]; K[3] *= K[3]*K[3]; K[6] = K[3]*K[3]; fR = sigma3[itype][jtype]*a12[itype][jtype]*c2*K[1]/K[3]; fpair = 4.0/15.0*fR*factor_lj * (2.0*(K[1]+K[2]) * (K[1]*(5.0*K[1]+22.0*K[2])+5.0*K[4]) * sigma6[itype][jtype]/K[6]-5.0) / K[0]; if (eflag) evdwl = 2.0/9.0*fR * (1.0-(K[1]*(K[1]*(K[1]/3.0+3.0*K[2])+4.2*K[4])+K[2]*K[4]) * sigma6[itype][jtype]/K[6]) - offset[itype][jtype]; if (rsq <= K[1]) error->one(FLERR,"Overlapping small/large in pair colloid"); break; case LARGE_LARGE: r = sqrt(rsq); c1 = a1[itype][jtype]; c2 = a2[itype][jtype]; K[0] = c1*c2; K[1] = c1+c2; K[2] = c1-c2; K[3] = K[1]+r; K[4] = K[1]-r; K[5] = K[2]+r; K[6] = K[2]-r; K[7] = 1.0/(K[3]*K[4]); K[8] = 1.0/(K[5]*K[6]); g[0] = powint(K[3],-7); g[1] = powint(K[4],-7); g[2] = powint(K[5],-7); g[3] = powint(K[6],-7); h[0] = ((K[3]+5.0*K[1])*K[3]+30.0*K[0])*g[0]; h[1] = ((K[4]+5.0*K[1])*K[4]+30.0*K[0])*g[1]; h[2] = ((K[5]+5.0*K[2])*K[5]-30.0*K[0])*g[2]; h[3] = ((K[6]+5.0*K[2])*K[6]-30.0*K[0])*g[3]; g[0] *= 42.0*K[0]/K[3]+6.0*K[1]+K[3]; g[1] *= 42.0*K[0]/K[4]+6.0*K[1]+K[4]; g[2] *= -42.0*K[0]/K[5]+6.0*K[2]+K[5]; g[3] *= -42.0*K[0]/K[6]+6.0*K[2]+K[6]; fR = a12[itype][jtype]*sigma6[itype][jtype]/r/37800.0; evdwl = fR * (h[0]-h[1]-h[2]+h[3]); dUR = evdwl/r + 5.0*fR*(g[0]+g[1]-g[2]-g[3]); dUA = -a12[itype][jtype]/3.0*r*((2.0*K[0]*K[7]+1.0)*K[7] + (2.0*K[0]*K[8]-1.0)*K[8]); fpair = factor_lj * (dUR+dUA)/r; if (eflag) evdwl += a12[itype][jtype]/6.0 * (2.0*K[0]*(K[7]+K[8])-log(K[8]/K[7])) - offset[itype][jtype]; if (r <= K[1]) error->one(FLERR,"Overlapping large/large in pair colloid"); break; } if (eflag) evdwl *= factor_lj; 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 (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 PairColloid::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(form,n+1,n+1,"pair:form"); memory->create(a12,n+1,n+1,"pair:a12"); memory->create(sigma,n+1,n+1,"pair:sigma"); memory->create(d1,n+1,n+1,"pair:d1"); memory->create(d2,n+1,n+1,"pair:d2"); memory->create(a1,n+1,n+1,"pair:a1"); memory->create(a2,n+1,n+1,"pair:a2"); memory->create(diameter,n+1,n+1,"pair:diameter"); memory->create(cut,n+1,n+1,"pair:cut"); memory->create(offset,n+1,n+1,"pair:offset"); memory->create(sigma3,n+1,n+1,"pair:sigma3"); memory->create(sigma6,n+1,n+1,"pair:sigma6"); 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"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairColloid::settings(int narg, char **arg) { if (narg != 1) error->all(FLERR,"Illegal pair_style command"); cut_global = force->numeric(FLERR,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 PairColloid::coeff(int narg, char **arg) { if (narg < 6 || narg > 7) 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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double a12_one = force->numeric(FLERR,arg[2]); double sigma_one = force->numeric(FLERR,arg[3]); double d1_one = force->numeric(FLERR,arg[4]); double d2_one = force->numeric(FLERR,arg[5]); double cut_one = cut_global; if (narg == 7) cut_one = force->numeric(FLERR,arg[6]); if (d1_one < 0.0 || d2_one < 0.0) error->all(FLERR,"Invalid d1 or d2 value for pair colloid coeff"); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { a12[i][j] = a12_one; sigma[i][j] = sigma_one; if (i == j && d1_one != d2_one) error->all(FLERR,"Invalid d1 or d2 value for pair colloid coeff"); d1[i][j] = d1_one; d2[i][j] = d2_one; diameter[i][j] = 0.5*(d1_one+d2_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 PairColloid::init_one(int i, int j) { if (setflag[i][j] == 0) { a12[i][j] = mix_energy(a12[i][i],a12[j][j],sigma[i][i],sigma[j][j]); sigma[i][j] = mix_distance(sigma[i][i],sigma[j][j]); d1[i][j] = mix_distance(d1[i][i],d1[j][j]); d2[i][j] = mix_distance(d2[i][i],d2[j][j]); diameter[i][j] = 0.5 * (d1[i][j] + d2[i][j]); cut[i][j] = mix_distance(cut[i][i],cut[j][j]); } sigma3[i][j] = sigma[i][j]*sigma[i][j]*sigma[i][j]; sigma6[i][j] = sigma3[i][j]*sigma3[i][j]; if (d1[i][j] == 0.0 && d2[i][j] == 0.0) form[i][j] = SMALL_SMALL; else if (d1[i][j] == 0.0 || d2[i][j] == 0.0) form[i][j] = SMALL_LARGE; else form[i][j] = LARGE_LARGE; // for SMALL_SMALL, a1/a2 do not need to be set // for SMALL_LARGE, a1 does not need to be set, a2 = radius for i,j and j,i // for LARGE_LARGE, a1/a2 are radii, swap them for j,i if (form[i][j] == SMALL_LARGE) { if (d1[i][j] > 0.0) a2[i][j] = 0.5*d1[i][j]; else a2[i][j] = 0.5*d2[i][j]; a2[j][i] = a2[i][j]; } else if (form[i][j] == LARGE_LARGE) { a2[j][i] = a1[i][j] = 0.5*d1[i][j]; a1[j][i] = a2[i][j] = 0.5*d2[i][j]; } form[j][i] = form[i][j]; a12[j][i] = a12[i][j]; sigma[j][i] = sigma[i][j]; sigma3[j][i] = sigma3[i][j]; sigma6[j][i] = sigma6[i][j]; diameter[j][i] = diameter[i][j]; double epsilon = a12[i][j]/144.0; lj1[j][i] = lj1[i][j] = 48.0 * epsilon * sigma6[i][j] * sigma6[i][j]; lj2[j][i] = lj2[i][j] = 24.0 * epsilon * sigma6[i][j]; lj3[j][i] = lj3[i][j] = 4.0 * epsilon * sigma6[i][j] * sigma6[i][j]; lj4[j][i] = lj4[i][j] = 4.0 * epsilon * sigma6[i][j]; offset[j][i] = offset[i][j] = 0.0; if (offset_flag) { double tmp; offset[j][i] = offset[i][j] = single(0,0,i,j,cut[i][j]*cut[i][j],0.0,1.0,tmp); } return cut[i][j]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairColloid::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(&a12[i][j],sizeof(double),1,fp); fwrite(&sigma[i][j],sizeof(double),1,fp); fwrite(&d1[i][j],sizeof(double),1,fp); fwrite(&d2[i][j],sizeof(double),1,fp); fwrite(&cut[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairColloid::read_restart(FILE *fp) { read_restart_settings(fp); allocate(); int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { if (comm->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 (comm->me == 0) { fread(&a12[i][j],sizeof(double),1,fp); fread(&sigma[i][j],sizeof(double),1,fp); fread(&d1[i][j],sizeof(double),1,fp); fread(&d2[i][j],sizeof(double),1,fp); fread(&cut[i][j],sizeof(double),1,fp); } MPI_Bcast(&a12[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&d1[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&d2[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairColloid::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 PairColloid::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); } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void PairColloid::write_data(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) fprintf(fp,"%d %g %g %g %g\n",i,a12[i][i],sigma[i][i],d1[i][i],d2[i][i]); } /* ---------------------------------------------------------------------- proc 0 writes all pairs to data file ------------------------------------------------------------------------- */ void PairColloid::write_data_all(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) fprintf(fp,"%d %g %g %g %g %g\n",i, a12[i][j],sigma[i][j],d1[i][j],d2[i][j],cut[i][j]); } /* ---------------------------------------------------------------------- */ double PairColloid::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double K[9],h[4],g[4]; double r,r2inv,r6inv,forcelj,c1,c2,phi,fR,dUR,dUA; switch (form[itype][jtype]) { case SMALL_SMALL: r2inv = 1.0/rsq; r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); fforce = factor_lj*forcelj*r2inv; phi = r6inv*(r6inv*lj3[itype][jtype]-lj4[itype][jtype]) - offset[itype][jtype]; break; case SMALL_LARGE: c2 = a2[itype][jtype]; K[1] = c2*c2; K[2] = rsq; K[0] = K[1] - rsq; K[4] = rsq*rsq; K[3] = K[1] - K[2]; K[3] *= K[3]*K[3]; K[6] = K[3]*K[3]; fR = sigma3[itype][jtype]*a12[itype][jtype]*c2*K[1]/K[3]; fforce = 4.0/15.0*fR*factor_lj * (2.0*(K[1]+K[2])*(K[1]*(5.0*K[1]+22.0*K[2])+5.0*K[4]) * sigma6[itype][jtype]/K[6] - 5.0)/K[0]; phi = 2.0/9.0*fR * (1.0-(K[1]*(K[1]*(K[1]/3.0+3.0*K[2])+4.2*K[4])+K[2]*K[4]) * sigma6[itype][jtype]/K[6]) - offset[itype][jtype]; break; case LARGE_LARGE: r = sqrt(rsq); c1 = a1[itype][jtype]; c2 = a2[itype][jtype]; K[0] = c1*c2; K[1] = c1+c2; K[2] = c1-c2; K[3] = K[1]+r; K[4] = K[1]-r; K[5] = K[2]+r; K[6] = K[2]-r; K[7] = 1.0/(K[3]*K[4]); K[8] = 1.0/(K[5]*K[6]); g[0] = powint(K[3],-7); g[1] = powint(K[4],-7); g[2] = powint(K[5],-7); g[3] = powint(K[6],-7); h[0] = ((K[3]+5.0*K[1])*K[3]+30.0*K[0])*g[0]; h[1] = ((K[4]+5.0*K[1])*K[4]+30.0*K[0])*g[1]; h[2] = ((K[5]+5.0*K[2])*K[5]-30.0*K[0])*g[2]; h[3] = ((K[6]+5.0*K[2])*K[6]-30.0*K[0])*g[3]; g[0] *= 42.0*K[0]/K[3]+6.0*K[1]+K[3]; g[1] *= 42.0*K[0]/K[4]+6.0*K[1]+K[4]; g[2] *= -42.0*K[0]/K[5]+6.0*K[2]+K[5]; g[3] *= -42.0*K[0]/K[6]+6.0*K[2]+K[6]; fR = a12[itype][jtype]*sigma6[itype][jtype]/r/37800.0; phi = fR * (h[0]-h[1]-h[2]+h[3]); dUR = phi/r + 5.0*fR*(g[0]+g[1]-g[2]-g[3]); dUA = -a12[itype][jtype]/3.0*r*((2.0*K[0]*K[7]+1.0)*K[7] + (2.0*K[0]*K[8]-1.0)*K[8]); fforce = factor_lj*(dUR+dUA)/r; phi += a12[itype][jtype]/6.0*(2.0*K[0]*(K[7]+K[8])-log(K[8]/K[7])) - offset[itype][jtype]; break; } return factor_lj*phi; } diff --git a/src/COLLOID/pair_lubricate.cpp b/src/COLLOID/pair_lubricate.cpp index ea398c340..71e08f3f1 100644 --- a/src/COLLOID/pair_lubricate.cpp +++ b/src/COLLOID/pair_lubricate.cpp @@ -1,820 +1,820 @@ /* ---------------------------------------------------------------------- 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: Randy Schunk (SNL) Amit Kumar and Michael Bybee (UIUC) ------------------------------------------------------------------------- */ #include #include #include #include #include "pair_lubricate.h" #include "atom.h" #include "atom_vec.h" #include "comm.h" #include "force.h" #include "neighbor.h" #include "neigh_list.h" #include "neigh_request.h" #include "domain.h" #include "modify.h" #include "fix.h" #include "fix_deform.h" #include "fix_wall.h" #include "input.h" #include "variable.h" #include "random_mars.h" #include "math_const.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace MathConst; // same as fix_deform.cpp enum{NO_REMAP,X_REMAP,V_REMAP}; // same as fix_wall.cpp enum{EDGE,CONSTANT,VARIABLE}; /* ---------------------------------------------------------------------- */ PairLubricate::PairLubricate(LAMMPS *lmp) : Pair(lmp) { single_enable = 0; // set comm size needed by this Pair comm_forward = 6; } /* ---------------------------------------------------------------------- */ PairLubricate::~PairLubricate() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut); memory->destroy(cut_inner); } } /* ---------------------------------------------------------------------- */ void PairLubricate::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,fx,fy,fz,tx,ty,tz; double rsq,r,h_sep,radi; double vr1,vr2,vr3,vnnr,vn1,vn2,vn3; double vt1,vt2,vt3,wt1,wt2,wt3,wdotn; double vRS0; double vi[3],vj[3],wi[3],wj[3],xl[3]; double a_sq,a_sh,a_pu; int *ilist,*jlist,*numneigh,**firstneigh; double lamda[3],vstream[3]; double vxmu2f = force->vxmu2f; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; double **x = atom->x; double **v = atom->v; double **f = atom->f; double **omega = atom->omega; double **torque = atom->torque; double *radius = atom->radius; 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; // subtract streaming component of velocity, omega, angmom // assume fluid streaming velocity = box deformation rate // vstream = (ux,uy,uz) // ux = h_rate[0]*x + h_rate[5]*y + h_rate[4]*z // uy = h_rate[1]*y + h_rate[3]*z // uz = h_rate[2]*z // omega_new = omega - curl(vstream)/2 // angmom_new = angmom - I*curl(vstream)/2 // Ef = (grad(vstream) + (grad(vstream))^T) / 2 if (shearing) { double *h_rate = domain->h_rate; double *h_ratelo = domain->h_ratelo; for (ii = 0; ii < inum; ii++) { i = ilist[ii]; itype = type[i]; radi = radius[i]; domain->x2lamda(x[i],lamda); vstream[0] = h_rate[0]*lamda[0] + h_rate[5]*lamda[1] + h_rate[4]*lamda[2] + h_ratelo[0]; vstream[1] = h_rate[1]*lamda[1] + h_rate[3]*lamda[2] + h_ratelo[1]; vstream[2] = h_rate[2]*lamda[2] + h_ratelo[2]; v[i][0] -= vstream[0]; v[i][1] -= vstream[1]; v[i][2] -= vstream[2]; omega[i][0] += 0.5*h_rate[3]; omega[i][1] -= 0.5*h_rate[4]; omega[i][2] += 0.5*h_rate[5]; } // set Ef from h_rate in strain units Ef[0][0] = h_rate[0]/domain->xprd; Ef[1][1] = h_rate[1]/domain->yprd; Ef[2][2] = h_rate[2]/domain->zprd; Ef[0][1] = Ef[1][0] = 0.5 * h_rate[5]/domain->yprd; Ef[0][2] = Ef[2][0] = 0.5 * h_rate[4]/domain->zprd; Ef[1][2] = Ef[2][1] = 0.5 * h_rate[3]/domain->zprd; // copy updated velocity/omega/angmom to the ghost particles // no need to do this if not shearing since comm->ghost_velocity is set comm->forward_comm_pair(this); } // This section of code adjusts R0/RT0/RS0 if necessary due to changes // in the volume fraction as a result of fix deform or moving walls double dims[3], wallcoord; if (flagVF) // Flag for volume fraction corrections if (flagdeform || flagwall == 2){ // Possible changes in volume fraction if (flagdeform && !flagwall) for (j = 0; j < 3; j++) dims[j] = domain->prd[j]; else if (flagwall == 2 || (flagdeform && flagwall == 1)){ double wallhi[3], walllo[3]; for (int j = 0; j < 3; j++){ wallhi[j] = domain->prd[j]; walllo[j] = 0; } for (int m = 0; m < wallfix->nwall; m++){ int dim = wallfix->wallwhich[m] / 2; int side = wallfix->wallwhich[m] % 2; if (wallfix->xstyle[m] == VARIABLE){ wallcoord = input->variable->compute_equal(wallfix->xindex[m]); } else wallcoord = wallfix->coord0[m]; if (side == 0) walllo[dim] = wallcoord; else wallhi[dim] = wallcoord; } for (int j = 0; j < 3; j++) dims[j] = wallhi[j] - walllo[j]; } double vol_T = dims[0]*dims[1]*dims[2]; double vol_f = vol_P/vol_T; if (flaglog == 0) { R0 = 6*MY_PI*mu*rad*(1.0 + 2.16*vol_f); RT0 = 8*MY_PI*mu*pow(rad,3.0); RS0 = 20.0/3.0*MY_PI*mu*pow(rad,3.0)* (1.0 + 3.33*vol_f + 2.80*vol_f*vol_f); } else { R0 = 6*MY_PI*mu*rad*(1.0 + 2.725*vol_f - 6.583*vol_f*vol_f); RT0 = 8*MY_PI*mu*pow(rad,3.0)*(1.0 + 0.749*vol_f - 2.469*vol_f*vol_f); RS0 = 20.0/3.0*MY_PI*mu*pow(rad,3.0)* (1.0 + 3.64*vol_f - 6.95*vol_f*vol_f); } } // end of R0 adjustment code for (ii = 0; ii < inum; ii++) { i = ilist[ii]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; radi = radius[i]; jlist = firstneigh[i]; jnum = numneigh[i]; // angular velocity wi[0] = omega[i][0]; wi[1] = omega[i][1]; wi[2] = omega[i][2]; // FLD contribution to force and torque due to isotropic terms // FLD contribution to stress from isotropic RS0 if (flagfld) { f[i][0] -= vxmu2f*R0*v[i][0]; f[i][1] -= vxmu2f*R0*v[i][1]; f[i][2] -= vxmu2f*R0*v[i][2]; torque[i][0] -= vxmu2f*RT0*wi[0]; torque[i][1] -= vxmu2f*RT0*wi[1]; torque[i][2] -= vxmu2f*RT0*wi[2]; if (shearing && vflag_either) { vRS0 = -vxmu2f * RS0; v_tally_tensor(i,i,nlocal,newton_pair, vRS0*Ef[0][0],vRS0*Ef[1][1],vRS0*Ef[2][2], vRS0*Ef[0][1],vRS0*Ef[0][2],vRS0*Ef[1][2]); } } if (!flagHI) continue; 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]; if (rsq < cutsq[itype][jtype]) { r = sqrt(rsq); // angular momentum = I*omega = 2/5 * M*R^2 * omega wj[0] = omega[j][0]; wj[1] = omega[j][1]; wj[2] = omega[j][2]; // xl = point of closest approach on particle i from its center xl[0] = -delx/r*radi; xl[1] = -dely/r*radi; xl[2] = -delz/r*radi; // velocity at the point of closest approach on both particles // v = v + omega_cross_xl - Ef.xl // particle i vi[0] = v[i][0] + (wi[1]*xl[2] - wi[2]*xl[1]) - (Ef[0][0]*xl[0] + Ef[0][1]*xl[1] + Ef[0][2]*xl[2]); vi[1] = v[i][1] + (wi[2]*xl[0] - wi[0]*xl[2]) - (Ef[1][0]*xl[0] + Ef[1][1]*xl[1] + Ef[1][2]*xl[2]); vi[2] = v[i][2] + (wi[0]*xl[1] - wi[1]*xl[0]) - (Ef[2][0]*xl[0] + Ef[2][1]*xl[1] + Ef[2][2]*xl[2]); // particle j vj[0] = v[j][0] - (wj[1]*xl[2] - wj[2]*xl[1]) + (Ef[0][0]*xl[0] + Ef[0][1]*xl[1] + Ef[0][2]*xl[2]); vj[1] = v[j][1] - (wj[2]*xl[0] - wj[0]*xl[2]) + (Ef[1][0]*xl[0] + Ef[1][1]*xl[1] + Ef[1][2]*xl[2]); vj[2] = v[j][2] - (wj[0]*xl[1] - wj[1]*xl[0]) + (Ef[2][0]*xl[0] + Ef[2][1]*xl[1] + Ef[2][2]*xl[2]); // scalar resistances XA and YA h_sep = r - 2.0*radi; // if less than the minimum gap use the minimum gap instead if (r < cut_inner[itype][jtype]) h_sep = cut_inner[itype][jtype] - 2.0*radi; // scale h_sep by radi h_sep = h_sep/radi; // scalar resistances if (flaglog) { a_sq = 6.0*MY_PI*mu*radi*(1.0/4.0/h_sep + 9.0/40.0*log(1.0/h_sep)); a_sh = 6.0*MY_PI*mu*radi*(1.0/6.0*log(1.0/h_sep)); a_pu = 8.0*MY_PI*mu*pow(radi,3.0)*(3.0/160.0*log(1.0/h_sep)); } else a_sq = 6.0*MY_PI*mu*radi*(1.0/4.0/h_sep); // relative velocity at the point of closest approach // includes fluid velocity vr1 = vi[0] - vj[0]; vr2 = vi[1] - vj[1]; vr3 = vi[2] - vj[2]; // normal component (vr.n)n vnnr = (vr1*delx + vr2*dely + vr3*delz)/r; vn1 = vnnr*delx/r; vn2 = vnnr*dely/r; vn3 = vnnr*delz/r; // tangential component vr - (vr.n)n vt1 = vr1 - vn1; vt2 = vr2 - vn2; vt3 = vr3 - vn3; // force due to squeeze type motion fx = a_sq*vn1; fy = a_sq*vn2; fz = a_sq*vn3; // force due to all shear kind of motions if (flaglog) { fx = fx + a_sh*vt1; fy = fy + a_sh*vt2; fz = fz + a_sh*vt3; } // scale forces for appropriate units fx *= vxmu2f; fy *= vxmu2f; fz *= vxmu2f; // add to total force f[i][0] -= fx; f[i][1] -= fy; f[i][2] -= fz; if (newton_pair || j < nlocal) { f[j][0] += fx; f[j][1] += fy; f[j][2] += fz; } // torque due to this force if (flaglog) { tx = xl[1]*fz - xl[2]*fy; ty = xl[2]*fx - xl[0]*fz; tz = xl[0]*fy - xl[1]*fx; torque[i][0] -= vxmu2f*tx; torque[i][1] -= vxmu2f*ty; torque[i][2] -= vxmu2f*tz; if (newton_pair || j < nlocal) { torque[j][0] -= vxmu2f*tx; torque[j][1] -= vxmu2f*ty; torque[j][2] -= vxmu2f*tz; } // torque due to a_pu wdotn = ((wi[0]-wj[0])*delx + (wi[1]-wj[1])*dely + (wi[2]-wj[2])*delz)/r; wt1 = (wi[0]-wj[0]) - wdotn*delx/r; wt2 = (wi[1]-wj[1]) - wdotn*dely/r; wt3 = (wi[2]-wj[2]) - wdotn*delz/r; tx = a_pu*wt1; ty = a_pu*wt2; tz = a_pu*wt3; torque[i][0] -= vxmu2f*tx; torque[i][1] -= vxmu2f*ty; torque[i][2] -= vxmu2f*tz; if (newton_pair || j < nlocal) { torque[j][0] += vxmu2f*tx; torque[j][1] += vxmu2f*ty; torque[j][2] += vxmu2f*tz; } } if (evflag) ev_tally_xyz(i,j,nlocal,newton_pair, 0.0,0.0,-fx,-fy,-fz,delx,dely,delz); } } } // restore streaming component of velocity, omega, angmom if (shearing) { double *h_rate = domain->h_rate; double *h_ratelo = domain->h_ratelo; for (ii = 0; ii < inum; ii++) { i = ilist[ii]; itype = type[i]; radi = radius[i]; domain->x2lamda(x[i],lamda); vstream[0] = h_rate[0]*lamda[0] + h_rate[5]*lamda[1] + h_rate[4]*lamda[2] + h_ratelo[0]; vstream[1] = h_rate[1]*lamda[1] + h_rate[3]*lamda[2] + h_ratelo[1]; vstream[2] = h_rate[2]*lamda[2] + h_ratelo[2]; v[i][0] += vstream[0]; v[i][1] += vstream[1]; v[i][2] += vstream[2]; omega[i][0] -= 0.5*h_rate[3]; omega[i][1] += 0.5*h_rate[4]; omega[i][2] -= 0.5*h_rate[5]; } } if (vflag_fdotr) virial_fdotr_compute(); } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairLubricate::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(cut_inner,n+1,n+1,"pair:cut_inner"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairLubricate::settings(int narg, char **arg) { if (narg != 5 && narg != 7) error->all(FLERR,"Illegal pair_style command"); mu = force->numeric(FLERR,arg[0]); flaglog = force->inumeric(FLERR,arg[1]); flagfld = force->inumeric(FLERR,arg[2]); cut_inner_global = force->numeric(FLERR,arg[3]); cut_global = force->numeric(FLERR,arg[4]); flagHI = flagVF = 1; if (narg == 7) { flagHI = force->inumeric(FLERR,arg[5]); flagVF = force->inumeric(FLERR,arg[6]); } if (flaglog == 1 && flagHI == 0) { error->warning(FLERR,"Cannot include log terms without 1/r terms; " "setting flagHI to 1"); flagHI = 1; } // reset cutoffs that have been explicitly set if (allocated) { for (int i = 1; i <= atom->ntypes; i++) for (int j = i+1; j <= atom->ntypes; j++) if (setflag[i][j]) { cut_inner[i][j] = cut_inner_global; cut[i][j] = cut_global; } } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairLubricate::coeff(int narg, char **arg) { if (narg != 2 && 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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double cut_inner_one = cut_inner_global; double cut_one = cut_global; if (narg == 4) { cut_inner_one = force->numeric(FLERR,arg[2]); cut_one = force->numeric(FLERR,arg[3]); } int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { cut_inner[i][j] = cut_inner_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 PairLubricate::init_style() { if (!atom->sphere_flag) error->all(FLERR,"Pair lubricate requires atom style sphere"); if (comm->ghost_velocity == 0) error->all(FLERR,"Pair lubricate requires ghost atoms store velocity"); neighbor->request(this,instance_me); // require that atom radii are identical within each type // require monodisperse system with same radii for all types double radtype; for (int i = 1; i <= atom->ntypes; i++) { if (!atom->radius_consistency(i,radtype)) error->all(FLERR,"Pair lubricate requires monodisperse particles"); if (i > 1 && radtype != rad) error->all(FLERR,"Pair lubricate requires monodisperse particles"); rad = radtype; } // check for fix deform, if exists it must use "remap v" // If box will change volume, set appropriate flag so that volume // and v.f. corrections are re-calculated at every step. // // If available volume is different from box volume // due to walls, set volume appropriately; if walls will // move, set appropriate flag so that volume and v.f. corrections // are re-calculated at every step. shearing = flagdeform = flagwall = 0; for (int i = 0; i < modify->nfix; i++){ if (strcmp(modify->fix[i]->style,"deform") == 0) { shearing = flagdeform = 1; if (((FixDeform *) modify->fix[i])->remapflag != V_REMAP) error->all(FLERR,"Using pair lubricate with inconsistent " "fix deform remap option"); } if (strstr(modify->fix[i]->style,"wall") != NULL) { if (flagwall) error->all(FLERR, "Cannot use multiple fix wall commands with pair lubricate"); flagwall = 1; // Walls exist wallfix = (FixWall *) modify->fix[i]; if (wallfix->xflag) flagwall = 2; // Moving walls exist } } // set the isotropic constants that depend on the volume fraction // vol_T = total volume double vol_T; double wallcoord; if (!flagwall) vol_T = domain->xprd*domain->yprd*domain->zprd; else { double wallhi[3], walllo[3]; for (int j = 0; j < 3; j++){ wallhi[j] = domain->prd[j]; walllo[j] = 0; } for (int m = 0; m < wallfix->nwall; m++){ int dim = wallfix->wallwhich[m] / 2; int side = wallfix->wallwhich[m] % 2; if (wallfix->xstyle[m] == VARIABLE){ wallfix->xindex[m] = input->variable->find(wallfix->xstr[m]); //Since fix->wall->init happens after pair->init_style wallcoord = input->variable->compute_equal(wallfix->xindex[m]); } else wallcoord = wallfix->coord0[m]; if (side == 0) walllo[dim] = wallcoord; else wallhi[dim] = wallcoord; } vol_T = (wallhi[0] - walllo[0]) * (wallhi[1] - walllo[1]) * (wallhi[2] - walllo[2]); } // vol_P = volume of particles, assuming monodispersity // vol_f = volume fraction vol_P = atom->natoms*(4.0/3.0)*MY_PI*pow(rad,3.0); double vol_f = vol_P/vol_T; if (!flagVF) vol_f = 0; // set isotropic constants for FLD if (flaglog == 0) { R0 = 6*MY_PI*mu*rad*(1.0 + 2.16*vol_f); RT0 = 8*MY_PI*mu*pow(rad,3.0); RS0 = 20.0/3.0*MY_PI*mu*pow(rad,3.0)*(1.0 + 3.33*vol_f + 2.80*vol_f*vol_f); } else { R0 = 6*MY_PI*mu*rad*(1.0 + 2.725*vol_f - 6.583*vol_f*vol_f); RT0 = 8*MY_PI*mu*pow(rad,3.0)*(1.0 + 0.749*vol_f - 2.469*vol_f*vol_f); RS0 = 20.0/3.0*MY_PI*mu*pow(rad,3.0)*(1.0 + 3.64*vol_f - 6.95*vol_f*vol_f); } // set Ef = 0 since used whether shearing or not Ef[0][0] = Ef[0][1] = Ef[0][2] = 0.0; Ef[1][0] = Ef[1][1] = Ef[1][2] = 0.0; Ef[2][0] = Ef[2][1] = Ef[2][2] = 0.0; } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairLubricate::init_one(int i, int j) { if (setflag[i][j] == 0) { cut_inner[i][j] = mix_distance(cut_inner[i][i],cut_inner[j][j]); cut[i][j] = mix_distance(cut[i][i],cut[j][j]); } cut_inner[j][i] = cut_inner[i][j]; return cut[i][j]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLubricate::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_inner[i][j],sizeof(double),1,fp); fwrite(&cut[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLubricate::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_inner[i][j],sizeof(double),1,fp); fread(&cut[i][j],sizeof(double),1,fp); } MPI_Bcast(&cut_inner[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLubricate::write_restart_settings(FILE *fp) { fwrite(&mu,sizeof(double),1,fp); fwrite(&flaglog,sizeof(int),1,fp); fwrite(&flagfld,sizeof(int),1,fp); fwrite(&cut_inner_global,sizeof(double),1,fp); fwrite(&cut_global,sizeof(double),1,fp); fwrite(&offset_flag,sizeof(int),1,fp); fwrite(&mix_flag,sizeof(int),1,fp); fwrite(&flagHI,sizeof(int),1,fp); fwrite(&flagVF,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLubricate::read_restart_settings(FILE *fp) { int me = comm->me; if (me == 0) { fread(&mu,sizeof(double),1,fp); fread(&flaglog,sizeof(int),1,fp); fread(&flagfld,sizeof(int),1,fp); fread(&cut_inner_global,sizeof(double),1,fp); fread(&cut_global,sizeof(double),1,fp); fread(&offset_flag,sizeof(int),1,fp); fread(&mix_flag,sizeof(int),1,fp); fread(&flagHI,sizeof(int),1,fp); fread(&flagVF,sizeof(int),1,fp); } MPI_Bcast(&mu,1,MPI_DOUBLE,0,world); MPI_Bcast(&flaglog,1,MPI_INT,0,world); MPI_Bcast(&flagfld,1,MPI_INT,0,world); MPI_Bcast(&cut_inner_global,1,MPI_DOUBLE,0,world); 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); MPI_Bcast(&flagHI,1,MPI_INT,0,world); MPI_Bcast(&flagVF,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- */ int PairLubricate::pack_forward_comm(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; double **v = atom->v; double **omega = atom->omega; m = 0; for (i = 0; i < n; i++) { j = list[i]; buf[m++] = v[j][0]; buf[m++] = v[j][1]; buf[m++] = v[j][2]; buf[m++] = omega[j][0]; buf[m++] = omega[j][1]; buf[m++] = omega[j][2]; } return m; } /* ---------------------------------------------------------------------- */ void PairLubricate::unpack_forward_comm(int n, int first, double *buf) { int i,m,last; double **v = atom->v; double **omega = atom->omega; m = 0; last = first + n; for (i = first; i < last; i++) { v[i][0] = buf[m++]; v[i][1] = buf[m++]; v[i][2] = buf[m++]; omega[i][0] = buf[m++]; omega[i][1] = buf[m++]; omega[i][2] = buf[m++]; } } /* ---------------------------------------------------------------------- check if name is recognized, return integer index for that name if name not recognized, return -1 if type pair setting, return -2 if no type pairs are set ------------------------------------------------------------------------- */ int PairLubricate::pre_adapt(char *name, int ilo, int ihi, int jlo, int jhi) { if (strcmp(name,"mu") == 0) return 0; return -1; } /* ---------------------------------------------------------------------- adapt parameter indexed by which change all pair variables affected by the reset parameter if type pair setting, set I-J and J-I coeffs ------------------------------------------------------------------------- */ void PairLubricate::adapt(int which, int ilo, int ihi, int jlo, int jhi, double value) { mu = value; } diff --git a/src/COLLOID/pair_lubricateU.cpp b/src/COLLOID/pair_lubricateU.cpp index 214bc3c2f..eafa57973 100644 --- a/src/COLLOID/pair_lubricateU.cpp +++ b/src/COLLOID/pair_lubricateU.cpp @@ -1,2061 +1,2061 @@ /* ---------------------------------------------------------------------- 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: Amit Kumar and Michael Bybee (UIUC) ------------------------------------------------------------------------- */ #include #include #include #include #include #include "pair_lubricateU.h" #include "atom.h" #include "atom_vec.h" #include "comm.h" #include "force.h" #include "neighbor.h" #include "neigh_list.h" #include "neigh_request.h" #include "domain.h" #include "update.h" #include "math_const.h" #include "modify.h" #include "fix.h" #include "fix_deform.h" #include "fix_wall.h" #include "input.h" #include "variable.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace MathConst; #define TOL 1E-4 // tolerance for conjugate gradient // same as fix_wall.cpp enum{EDGE,CONSTANT,VARIABLE}; /* ---------------------------------------------------------------------- */ PairLubricateU::PairLubricateU(LAMMPS *lmp) : Pair(lmp) { single_enable = 0; // pair lubricateU cannot compute virial as F dot r // due to how drag forces are applied to atoms // correct method is how per-atom virial does it no_virial_fdotr_compute = 1; nmax = 0; fl = Tl = xl = NULL; cgmax = 0; bcg = xcg = rcg = rcg1 = pcg = RU = NULL; // set comm size needed by this Pair comm_forward = 6; } /* ---------------------------------------------------------------------- */ PairLubricateU::~PairLubricateU() { memory->destroy(fl); memory->destroy(Tl); memory->destroy(xl); memory->destroy(bcg); memory->destroy(xcg); memory->destroy(rcg); memory->destroy(rcg1); memory->destroy(pcg); memory->destroy(RU); if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut); memory->destroy(cut_inner); } } /* ---------------------------------------------------------------------- It first has to solve for the velocity of the particles such that the net force on the particles is zero. NOTE: it has to be the last type of pair interaction specified in the input file. Also, it assumes that no other types of interactions, like k-space, is present. As already mentioned, the net force on the particles after this pair interaction would be identically zero. ---------------------------------------------------------------------- */ void PairLubricateU::compute(int eflag, int vflag) { int i,j; double **x = atom->x; double **f = atom->f; double **torque = atom->torque; int nlocal = atom->nlocal; int nghost = atom->nghost; int nall = nlocal + nghost; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; // skip compute() if called from integrate::setup() // this is b/c do not want compute() to update velocities twice on a restart // when restarting, call compute on step N (last step of prev run), // again on step N (setup of restart run), // then on step N+1 (first step of restart) // so this is one extra time which leads to bad dynamics if (update->setupflag) return; // grow per-atom arrays if necessary // need to be atom->nmax in length if (atom->nmax > nmax) { memory->destroy(fl); memory->destroy(Tl); memory->destroy(xl); nmax = atom->nmax; memory->create(fl,nmax,3,"pair:fl"); memory->create(Tl,nmax,3,"pair:Tl"); memory->create(xl,nmax,3,"pair:xl"); } // Added to implement midpoint integration scheme // Save force, torque found so far. Also save the positions for (i=0;ix; double **v = atom->v; double **f = atom->f; double **omega = atom->omega; double **torque = atom->torque; int newton_pair = force->newton_pair; int *ilist; inum = list->inum; ilist = list->ilist; if (6*inum > cgmax) { memory->destroy(bcg); memory->destroy(xcg); memory->destroy(rcg); memory->destroy(rcg1); memory->destroy(pcg); memory->destroy(RU); cgmax = 6*inum; memory->create(bcg,cgmax,"pair:bcg"); memory->create(xcg,cgmax,"pair:bcg"); memory->create(rcg,cgmax,"pair:bcg"); memory->create(rcg1,cgmax,"pair:bcg"); memory->create(pcg,cgmax,"pair:bcg"); memory->create(RU,cgmax,"pair:bcg"); } double alpha,beta; double normi,error,normig; double send[2],recv[2],rcg_dot_rcg; // First compute R_FE*E compute_RE(); // Reverse communication of forces and torques to // accumulate the net force on each of the particles if (newton_pair) comm->reverse_comm(); // CONJUGATE GRADIENT // Find the right hand side= -ve of all forces/torques // b = 6*Npart in overall size for(ii = 0; ii < inum; ii++) { i = ilist[ii]; for (j = 0; j < 3; j++) { bcg[6*ii+j] = -f[i][j]; bcg[6*ii+j+3] = -torque[i][j]; } } // Start solving the equation : F^H = -F^P -F^B - F^H_{Ef} // Store initial guess for velocity and angular-velocities/angular momentum // NOTE velocities and angular velocities are assumed relative to the fluid for (ii=0;iiforward_comm_pair(this); // Find initial residual compute_RU(); // reverse communication of forces and torques if (newton_pair) comm->reverse_comm(); copy_uo_vec(inum,f,torque,RU); for (i=0;i<6*inum;i++) rcg[i] = bcg[i] - RU[i]; // Set initial conjugate direction for (i=0;i<6*inum;i++) pcg[i] = rcg[i]; // Find initial norm of the residual or norm of the RHS (either is fine) normi = dot_vec_vec(6*inum,bcg,bcg); MPI_Allreduce(&normi,&normig,1,MPI_DOUBLE,MPI_SUM,world); // Loop until convergence do { // find R*p copy_vec_uo(inum,pcg,v,omega); // set velocities for ghost particles comm->forward_comm_pair(this); compute_RU(); // reverse communication of forces and torques if (newton_pair) comm->reverse_comm(); copy_uo_vec(inum,f,torque,RU); // Find alpha send[0] = dot_vec_vec(6*inum,rcg,rcg); send[1] = dot_vec_vec(6*inum,RU,pcg); MPI_Allreduce(send,recv,2,MPI_DOUBLE,MPI_SUM,world); alpha = recv[0]/recv[1]; rcg_dot_rcg = recv[0]; // Find new x for (i=0;i<6*inum;i++) xcg[i] = xcg[i] + alpha*pcg[i]; // find new residual for (i=0;i<6*inum;i++) rcg1[i] = rcg[i] - alpha*RU[i]; // find beta send[0] = dot_vec_vec(6*inum,rcg1,rcg1); MPI_Allreduce(send,recv,1,MPI_DOUBLE,MPI_SUM,world); beta = recv[0]/rcg_dot_rcg; // Find new conjugate direction for (i=0;i<6*inum;i++) pcg[i] = rcg1[i] + beta*pcg[i]; for (i=0;i<6*inum;i++) rcg[i] = rcg1[i]; // Find relative error error = sqrt(recv[0]/normig); } while (error > TOL); // update the final converged velocities in respective arrays copy_vec_uo(inum,xcg,v,omega); // set velocities for ghost particles comm->forward_comm_pair(this); // Find actual particle's velocities from relative velocities // Only non-zero component of fluid's vel : vx=gdot*y and wz=-gdot/2 for (ii=0;iix; double **v = atom->v; double dtv = update->dt; for (i=0;iv; double **f = atom->f; double **omega = atom->omega; double **torque = atom->torque; int newton_pair = force->newton_pair; int *ilist; inum = list->inum; ilist = list->ilist; double alpha,beta; double normi,error,normig; double send[2],recv[2],rcg_dot_rcg; // First compute R_FE*E compute_RE(x); // Reverse communication of forces and torques to // accumulate the net force on each of the particles if (newton_pair) comm->reverse_comm(); // CONJUGATE GRADIENT // Find the right hand side= -ve of all forces/torques // b = 6*Npart in overall size for(ii = 0; ii < inum; ii++) { i = ilist[ii]; for (j = 0; j < 3; j++) { bcg[6*ii+j] = -f[i][j]; bcg[6*ii+j+3] = -torque[i][j]; } } // Start solving the equation : F^H = -F^P -F^B - F^H_{Ef} // Store initial guess for velocity and angular-velocities/angular momentum // NOTE velocities and angular velocities are assumed relative to the fluid for (ii=0;iiforward_comm_pair(this); // Find initial residual compute_RU(x); // reverse communication of forces and torques if (newton_pair) comm->reverse_comm(); copy_uo_vec(inum,f,torque,RU); for (i=0;i<6*inum;i++) rcg[i] = bcg[i] - RU[i]; // Set initial conjugate direction for (i=0;i<6*inum;i++) pcg[i] = rcg[i]; // Find initial norm of the residual or norm of the RHS (either is fine) normi = dot_vec_vec(6*inum,bcg,bcg); MPI_Allreduce(&normi,&normig,1,MPI_DOUBLE,MPI_SUM,world); // Loop until convergence do { // find R*p copy_vec_uo(inum,pcg,v,omega); // set velocities for ghost particles comm->forward_comm_pair(this); compute_RU(x); // reverse communication of forces and torques if (newton_pair) comm->reverse_comm(); copy_uo_vec(inum,f,torque,RU); // Find alpha send[0] = dot_vec_vec(6*inum,rcg,rcg); send[1] = dot_vec_vec(6*inum,RU,pcg); MPI_Allreduce(send,recv,2,MPI_DOUBLE,MPI_SUM,world); alpha = recv[0]/recv[1]; rcg_dot_rcg = recv[0]; // Find new x for (i=0;i<6*inum;i++) xcg[i] = xcg[i] + alpha*pcg[i]; // find new residual for (i=0;i<6*inum;i++) rcg1[i] = rcg[i] - alpha*RU[i]; // find beta send[0] = dot_vec_vec(6*inum,rcg1,rcg1); MPI_Allreduce(send,recv,1,MPI_DOUBLE,MPI_SUM,world); beta = recv[0]/rcg_dot_rcg; // Find new conjugate direction for (i=0;i<6*inum;i++) pcg[i] = rcg1[i] + beta*pcg[i]; for (i=0;i<6*inum;i++) rcg[i] = rcg1[i]; // Find relative error error = sqrt(recv[0]/normig); } while (error > TOL); // update the final converged velocities in respective arrays copy_vec_uo(inum,xcg,v,omega); // set velocities for ghost particles comm->forward_comm_pair(this); // Compute the viscosity/pressure if (evflag) compute_Fh(x); // Find actual particle's velocities from relative velocities // Only non-zero component of fluid's vel : vx=gdot*y and wz=-gdot/2 for (ii=0;iiv; double **f = atom->f; double **omega = atom->omega; double **torque = atom->torque; double *radius = atom->radius; int *type = atom->type; int nlocal = atom->nlocal; int nghost = atom->nghost; int newton_pair = force->newton_pair; double radi; double vxmu2f = force->vxmu2f; double vi[3],vj[3],wi[3],wj[3],xl[3],a_sq,a_sh; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // This section of code adjusts R0/RT0/RS0 if necessary due to changes // in the volume fraction as a result of fix deform or moving walls double dims[3], wallcoord; if (flagVF) // Flag for volume fraction corrections if (flagdeform || flagwall == 2){ // Possible changes in volume fraction if (flagdeform && !flagwall) for (j = 0; j < 3; j++) dims[j] = domain->prd[j]; else if (flagwall == 2 || (flagdeform && flagwall == 1)){ double wallhi[3], walllo[3]; for (int j = 0; j < 3; j++){ wallhi[j] = domain->prd[j]; walllo[j] = 0; } for (int m = 0; m < wallfix->nwall; m++){ int dim = wallfix->wallwhich[m] / 2; int side = wallfix->wallwhich[m] % 2; if (wallfix->xstyle[m] == VARIABLE){ wallcoord = input->variable->compute_equal(wallfix->xindex[m]); } else wallcoord = wallfix->coord0[m]; if (side == 0) walllo[dim] = wallcoord; else wallhi[dim] = wallcoord; } for (int j = 0; j < 3; j++) dims[j] = wallhi[j] - walllo[j]; } double vol_T = dims[0]*dims[1]*dims[2]; double vol_f = vol_P/vol_T; if (flaglog == 0) { // R0 = 6*MY_PI*mu*rad*(1.0 + 2.16*vol_f); // RT0 = 8*MY_PI*mu*pow(rad,3); RS0 = 20.0/3.0*MY_PI*mu*pow(rad,3.0)* (1.0 + 3.33*vol_f + 2.80*vol_f*vol_f); } else { // R0 = 6*MY_PI*mu*rad*(1.0 + 2.725*vol_f - 6.583*vol_f*vol_f); // RT0 = 8*MY_PI*mu*pow(rad,3)*(1.0 + 0.749*vol_f - 2.469*vol_f*vol_f); RS0 = 20.0/3.0*MY_PI*mu*pow(rad,3.0)* (1.0 + 3.64*vol_f - 6.95*vol_f*vol_f); } } // end of R0 adjustment code // Set force to zero which is the final value after this pair interaction for (i=0;ireverse_comm(); // not really needed // Find additional contribution from the stresslets for (ii = 0; ii < inum; ii++) { i = ilist[ii]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; radi = radius[i]; jlist = firstneigh[i]; jnum = numneigh[i]; // Find the contribution to stress from isotropic RS0 // Set psuedo force to obtain the required contribution // need to set delx and fy only fx = 0.0; delx = radi; fy = vxmu2f*RS0*gdot/2.0/radi; dely = 0.0; fz = 0.0; delz = 0.0; if (evflag) ev_tally_xyz(i,i,nlocal,newton_pair,0.0,0.0,-fx,-fy,-fz,delx,dely,delz); // Find angular velocity wi[0] = omega[i][0]; wi[1] = omega[i][1]; wi[2] = omega[i][2]; if (!flagHI) continue; 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]; if (rsq < cutsq[itype][jtype]) { r = sqrt(rsq); // Use omega directly if it exists, else angmom // angular momentum = I*omega = 2/5 * M*R^2 * omega wj[0] = omega[j][0]; wj[1] = omega[j][1]; wj[2] = omega[j][2]; // loc of the point of closest approach on particle i from its cente xl[0] = -delx/r*radi; xl[1] = -dely/r*radi; xl[2] = -delz/r*radi; // velocity at the point of closest approach on both particles // v = v + omega_cross_xl // particle i vi[0] = v[i][0] + (wi[1]*xl[2] - wi[2]*xl[1]); vi[1] = v[i][1] + (wi[2]*xl[0] - wi[0]*xl[2]); vi[2] = v[i][2] + (wi[0]*xl[1] - wi[1]*xl[0]); // particle j vj[0] = v[j][0] - (wj[1]*xl[2] - wj[2]*xl[1]); vj[1] = v[j][1] - (wj[2]*xl[0] - wj[0]*xl[2]); vj[2] = v[j][2] - (wj[0]*xl[1] - wj[1]*xl[0]); // Relative velocity at the point of closest approach // include contribution from Einf of the fluid vr1 = vi[0] - vj[0] - 2.0*(Ef[0][0]*xl[0] + Ef[0][1]*xl[1] + Ef[0][2]*xl[2]); vr2 = vi[1] - vj[1] - 2.0*(Ef[1][0]*xl[0] + Ef[1][1]*xl[1] + Ef[1][2]*xl[2]); vr3 = vi[2] - vj[2] - 2.0*(Ef[2][0]*xl[0] + Ef[2][1]*xl[1] + Ef[2][2]*xl[2]); // Normal component (vr.n)n vnnr = (vr1*delx + vr2*dely + vr3*delz)/r; vn1 = vnnr*delx/r; vn2 = vnnr*dely/r; vn3 = vnnr*delz/r; // Tangential component vr - (vr.n)n vt1 = vr1 - vn1; vt2 = vr2 - vn2; vt3 = vr3 - vn3; // Find the scalar resistances a_sq, a_sh and a_pu h_sep = r - 2.0*radi; // If less than the minimum gap use the minimum gap instead if (r < cut_inner[itype][jtype]) h_sep = cut_inner[itype][jtype] - 2.0*radi; // Scale h_sep by radi h_sep = h_sep/radi; // Scalar resistances if (flaglog) { a_sq = 6.0*MY_PI*mu*radi*(1.0/4.0/h_sep + 9.0/40.0*log(1.0/h_sep)); a_sh = 6.0*MY_PI*mu*radi*(1.0/6.0*log(1.0/h_sep)); } else a_sq = 6.0*MY_PI*mu*radi*(1.0/4.0/h_sep); // Find force due to squeeze type motion fx = a_sq*vn1; fy = a_sq*vn2; fz = a_sq*vn3; // Find force due to all shear kind of motions if (flaglog) { fx = fx + a_sh*vt1; fy = fy + a_sh*vt2; fz = fz + a_sh*vt3; } // Scale forces to obtain in appropriate units fx = vxmu2f*fx; fy = vxmu2f*fy; fz = vxmu2f*fz; if (evflag) ev_tally_xyz(i,j,nlocal,newton_pair, 0.0,0.0,-fx,-fy,-fz,delx,dely,delz); } } } } /* ---------------------------------------------------------------------- computes R_FU * U ---------------------------------------------------------------------- */ void PairLubricateU::compute_RU() { int i,j,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,fx,fy,fz,tx,ty,tz; double rsq,r,h_sep,radi; double vr1,vr2,vr3,vnnr,vn1,vn2,vn3; double vt1,vt2,vt3,wdotn,wt1,wt2,wt3; int *ilist,*jlist,*numneigh,**firstneigh; double **x = atom->x; double **v = atom->v; double **f = atom->f; double **omega = atom->omega; double **torque = atom->torque; double *radius = atom->radius; int *type = atom->type; int nlocal = atom->nlocal; int nghost = atom->nghost; int newton_pair = force->newton_pair; double vxmu2f = force->vxmu2f; double vi[3],vj[3],wi[3],wj[3],xl[3],a_sq,a_sh,a_pu; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // This section of code adjusts R0/RT0/RS0 if necessary due to changes // in the volume fraction as a result of fix deform or moving walls double dims[3], wallcoord; if (flagVF) // Flag for volume fraction corrections if (flagdeform || flagwall == 2){ // Possible changes in volume fraction if (flagdeform && !flagwall) for (j = 0; j < 3; j++) dims[j] = domain->prd[j]; else if (flagwall == 2 || (flagdeform && flagwall == 1)){ double wallhi[3], walllo[3]; for (int j = 0; j < 3; j++){ wallhi[j] = domain->prd[j]; walllo[j] = 0; } for (int m = 0; m < wallfix->nwall; m++){ int dim = wallfix->wallwhich[m] / 2; int side = wallfix->wallwhich[m] % 2; if (wallfix->xstyle[m] == VARIABLE){ wallcoord = input->variable->compute_equal(wallfix->xindex[m]); } else wallcoord = wallfix->coord0[m]; if (side == 0) walllo[dim] = wallcoord; else wallhi[dim] = wallcoord; } for (int j = 0; j < 3; j++) dims[j] = wallhi[j] - walllo[j]; } double vol_T = dims[0]*dims[1]*dims[2]; double vol_f = vol_P/vol_T; if (flaglog == 0) { R0 = 6*MY_PI*mu*rad*(1.0 + 2.16*vol_f); RT0 = 8*MY_PI*mu*pow(rad,3.0); // RS0 = 20.0/3.0*MY_PI*mu*pow(rad,3)*(1.0 + 3.33*vol_f + 2.80*vol_f*vol_f); } else { R0 = 6*MY_PI*mu*rad*(1.0 + 2.725*vol_f - 6.583*vol_f*vol_f); RT0 = 8*MY_PI*mu*pow(rad,3.0)*(1.0 + 0.749*vol_f - 2.469*vol_f*vol_f); // RS0 = 20.0/3.0*MY_PI*mu*pow(rad,3)*(1.0 + 3.64*vol_f - 6.95*vol_f*vol_f); } } // end of R0 adjustment code // Initialize f to zero for (i=0;iv; double **f = atom->f; double **omega = atom->omega; double **torque = atom->torque; double *radius = atom->radius; int *type = atom->type; int nlocal = atom->nlocal; int nghost = atom->nghost; int newton_pair = force->newton_pair; double vxmu2f = force->vxmu2f; double vi[3],vj[3],wi[3],wj[3],xl[3],a_sq,a_sh,a_pu; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // This section of code adjusts R0/RT0/RS0 if necessary due to changes // in the volume fraction as a result of fix deform or moving walls double dims[3], wallcoord; if (flagVF) // Flag for volume fraction corrections if (flagdeform || flagwall == 2){ // Possible changes in volume fraction if (flagdeform && !flagwall) for (j = 0; j < 3; j++) dims[j] = domain->prd[j]; else if (flagwall == 2 || (flagdeform && flagwall == 1)){ double wallhi[3], walllo[3]; for (int j = 0; j < 3; j++){ wallhi[j] = domain->prd[j]; walllo[j] = 0; } for (int m = 0; m < wallfix->nwall; m++){ int dim = wallfix->wallwhich[m] / 2; int side = wallfix->wallwhich[m] % 2; if (wallfix->xstyle[m] == VARIABLE){ wallcoord = input->variable->compute_equal(wallfix->xindex[m]); } else wallcoord = wallfix->coord0[m]; if (side == 0) walllo[dim] = wallcoord; else wallhi[dim] = wallcoord; } for (int j = 0; j < 3; j++) dims[j] = wallhi[j] - walllo[j]; } double vol_T = dims[0]*dims[1]*dims[2]; double vol_f = vol_P/vol_T; if (flaglog == 0) { R0 = 6*MY_PI*mu*rad*(1.0 + 2.16*vol_f); RT0 = 8*MY_PI*mu*pow(rad,3.0); // RS0 = 20.0/3.0*MY_PI*mu*pow(rad,3)*(1.0 + 3.33*vol_f + 2.80*vol_f*vol_f); } else { R0 = 6*MY_PI*mu*rad*(1.0 + 2.725*vol_f - 6.583*vol_f*vol_f); RT0 = 8*MY_PI*mu*pow(rad,3.0)*(1.0 + 0.749*vol_f - 2.469*vol_f*vol_f); // RS0 = 20.0/3.0*MY_PI*mu*pow(rad,3)*(1.0 + 3.64*vol_f - 6.95*vol_f*vol_f); } } // end of R0 adjustment code // Initialize f to zero for (i=0;ix; double **f = atom->f; double **torque = atom->torque; double *radius = atom->radius; int *type = atom->type; int nlocal = atom->nlocal; int newton_pair = force->newton_pair; double vxmu2f = force->vxmu2f; double xl[3],a_sq,a_sh; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; if (!flagHI) return; for (ii = 0; ii < inum; ii++) { i = ilist[ii]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; radi = radius[i]; jlist = firstneigh[i]; jnum = numneigh[i]; // No contribution from isotropic terms due to E 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]; if (rsq < cutsq[itype][jtype]) { r = sqrt(rsq); // loc of the point of closest approach on particle i from its center xl[0] = -delx/r*radi; xl[1] = -dely/r*radi; xl[2] = -delz/r*radi; // Find the scalar resistances a_sq and a_sh h_sep = r - 2.0*radi; // If less than the minimum gap use the minimum gap instead if (r < cut_inner[itype][jtype]) h_sep = cut_inner[itype][jtype] - 2.0*radi; // Scale h_sep by radi h_sep = h_sep/radi; // Scalar resistance for Squeeze type motions if (flaglog) a_sq = 6*MY_PI*mu*radi*(1.0/4.0/h_sep + 9.0/40.0*log(1/h_sep)); else a_sq = 6*MY_PI*mu*radi*(1.0/4.0/h_sep); // Scalar resistance for Shear type motions if (flaglog) { a_sh = 6*MY_PI*mu*radi*(1.0/6.0*log(1/h_sep)); } // Relative velocity at the point of closest approach due to Ef only vr1 = -2.0*(Ef[0][0]*xl[0] + Ef[0][1]*xl[1] + Ef[0][2]*xl[2]); vr2 = -2.0*(Ef[1][0]*xl[0] + Ef[1][1]*xl[1] + Ef[1][2]*xl[2]); vr3 = -2.0*(Ef[2][0]*xl[0] + Ef[2][1]*xl[1] + Ef[2][2]*xl[2]); // Normal component (vr.n)n vnnr = (vr1*delx + vr2*dely + vr3*delz)/r; vn1 = vnnr*delx/r; vn2 = vnnr*dely/r; vn3 = vnnr*delz/r; // Tangential component vr - (vr.n)n vt1 = vr1 - vn1; vt2 = vr2 - vn2; vt3 = vr3 - vn3; // Find force due to squeeze type motion fx = a_sq*vn1; fy = a_sq*vn2; fz = a_sq*vn3; // Find force due to all shear kind of motions if (flaglog) { fx = fx + a_sh*vt1; fy = fy + a_sh*vt2; fz = fz + a_sh*vt3; } // Scale forces to obtain in appropriate units fx = vxmu2f*fx; fy = vxmu2f*fy; fz = vxmu2f*fz; // Add to the total forc f[i][0] -= fx; f[i][1] -= fy; f[i][2] -= fz; if (newton_pair || j < nlocal) { f[j][0] += fx; f[j][1] += fy; f[j][2] += fz; } // Find torque due to this force if (flaglog) { tx = xl[1]*fz - xl[2]*fy; ty = xl[2]*fx - xl[0]*fz; tz = xl[0]*fy - xl[1]*fx; // Why a scale factor ? torque[i][0] -= vxmu2f*tx; torque[i][1] -= vxmu2f*ty; torque[i][2] -= vxmu2f*tz; if (newton_pair || j < nlocal) { torque[j][0] -= vxmu2f*tx; torque[j][1] -= vxmu2f*ty; torque[j][2] -= vxmu2f*tz; } } } } } } /* ---------------------------------------------------------------------- This computes R_{FE}*E , where E is the rate of strain of tensor which is known apriori, as it depends only on the known fluid velocity. So, this part of the hydrodynamic interaction can be pre computed and transferred to the RHS ---------------------------------------------------------------------- */ void PairLubricateU::compute_RE(double **x) { int i,j,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,fx,fy,fz,tx,ty,tz; double rsq,r,h_sep,radi; double vr1,vr2,vr3,vnnr,vn1,vn2,vn3; double vt1,vt2,vt3; int *ilist,*jlist,*numneigh,**firstneigh; double **f = atom->f; double **torque = atom->torque; double *radius = atom->radius; int *type = atom->type; int nlocal = atom->nlocal; int newton_pair = force->newton_pair; double vxmu2f = force->vxmu2f; double xl[3],a_sq,a_sh; if (!flagHI) return; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; for (ii = 0; ii < inum; ii++) { i = ilist[ii]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; radi = radius[i]; jlist = firstneigh[i]; jnum = numneigh[i]; // No contribution from isotropic terms due to E 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]; if (rsq < cutsq[itype][jtype]) { r = sqrt(rsq); // loc of the point of closest approach on particle i from its center xl[0] = -delx/r*radi; xl[1] = -dely/r*radi; xl[2] = -delz/r*radi; // Find the scalar resistances a_sq and a_sh h_sep = r - 2.0*radi; // If less than the minimum gap use the minimum gap instead if (r < cut_inner[itype][jtype]) h_sep = cut_inner[itype][jtype] - 2.0*radi; // Scale h_sep by radi h_sep = h_sep/radi; // Scalar resistance for Squeeze type motions if (flaglog) a_sq = 6*MY_PI*mu*radi*(1.0/4.0/h_sep + 9.0/40.0*log(1/h_sep)); else a_sq = 6*MY_PI*mu*radi*(1.0/4.0/h_sep); // Scalar resistance for Shear type motions if (flaglog) { a_sh = 6*MY_PI*mu*radi*(1.0/6.0*log(1/h_sep)); } // Relative velocity at the point of closest approach due to Ef only vr1 = -2.0*(Ef[0][0]*xl[0] + Ef[0][1]*xl[1] + Ef[0][2]*xl[2]); vr2 = -2.0*(Ef[1][0]*xl[0] + Ef[1][1]*xl[1] + Ef[1][2]*xl[2]); vr3 = -2.0*(Ef[2][0]*xl[0] + Ef[2][1]*xl[1] + Ef[2][2]*xl[2]); // Normal component (vr.n)n vnnr = (vr1*delx + vr2*dely + vr3*delz)/r; vn1 = vnnr*delx/r; vn2 = vnnr*dely/r; vn3 = vnnr*delz/r; // Tangential component vr - (vr.n)n vt1 = vr1 - vn1; vt2 = vr2 - vn2; vt3 = vr3 - vn3; // Find force due to squeeze type motion fx = a_sq*vn1; fy = a_sq*vn2; fz = a_sq*vn3; // Find force due to all shear kind of motions if (flaglog) { fx = fx + a_sh*vt1; fy = fy + a_sh*vt2; fz = fz + a_sh*vt3; } // Scale forces to obtain in appropriate units fx = vxmu2f*fx; fy = vxmu2f*fy; fz = vxmu2f*fz; // Add to the total forc f[i][0] -= fx; f[i][1] -= fy; f[i][2] -= fz; if (newton_pair || j < nlocal) { f[j][0] += fx; f[j][1] += fy; f[j][2] += fz; } // Find torque due to this force if (flaglog) { tx = xl[1]*fz - xl[2]*fy; ty = xl[2]*fx - xl[0]*fz; tz = xl[0]*fy - xl[1]*fx; // Why a scale factor ? torque[i][0] -= vxmu2f*tx; torque[i][1] -= vxmu2f*ty; torque[i][2] -= vxmu2f*tz; if (newton_pair || j < nlocal) { torque[j][0] -= vxmu2f*tx; torque[j][1] -= vxmu2f*ty; torque[j][2] -= vxmu2f*tz; } } } } } } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairLubricateU::allocate() { allocated = 1; int n = atom->ntypes; setflag = 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; cutsq = memory->create(cutsq,n+1,n+1,"pair:cutsq"); memory->create(cut,n+1,n+1,"pair:cut"); memory->create(cut_inner,n+1,n+1,"pair:cut_inner"); } /*----------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairLubricateU::settings(int narg, char **arg) { if (narg != 5 && narg != 7) error->all(FLERR,"Illegal pair_style command"); mu = force->numeric(FLERR,arg[0]); flaglog = force->inumeric(FLERR,arg[1]); cut_inner_global = force->numeric(FLERR,arg[2]); cut_global = force->numeric(FLERR,arg[3]); gdot = force->numeric(FLERR,arg[4]); flagHI = flagVF = 1; if (narg == 7) { flagHI = force->inumeric(FLERR,arg[5]); flagVF = force->inumeric(FLERR,arg[6]); } if (flaglog == 1 && flagHI == 0) { error->warning(FLERR,"Cannot include log terms without 1/r terms; " "setting flagHI to 1."); flagHI = 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_inner[i][j] = cut_inner_global; cut[i][j] = cut_global; } } // store the rate of strain tensor Ef[0][0] = 0.0; Ef[0][1] = 0.5*gdot; Ef[0][2] = 0.0; Ef[1][0] = 0.5*gdot; Ef[1][1] = 0.0; Ef[1][2] = 0.0; Ef[2][0] = 0.0; Ef[2][1] = 0.0; Ef[2][2] = 0.0; } /*----------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairLubricateU::coeff(int narg, char **arg) { if (narg != 2 && 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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double cut_inner_one = cut_inner_global; double cut_one = cut_global; if (narg == 4) { cut_inner_one = force->numeric(FLERR,arg[2]); cut_one = force->numeric(FLERR,arg[3]); } int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { cut_inner[i][j] = cut_inner_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 PairLubricateU::init_style() { if (!atom->sphere_flag) error->all(FLERR,"Pair lubricateU requires atom style sphere"); if (comm->ghost_velocity == 0) error->all(FLERR,"Pair lubricateU requires ghost atoms store velocity"); neighbor->request(this,instance_me); // require that atom radii are identical within each type // require monodisperse system with same radii for all types double radtype; for (int i = 1; i <= atom->ntypes; i++) { if (!atom->radius_consistency(i,radtype)) error->all(FLERR,"Pair lubricateU requires monodisperse particles"); if (i > 1 && radtype != rad) error->all(FLERR,"Pair lubricateU requires monodisperse particles"); } // check for fix deform, if exists it must use "remap v" // If box will change volume, set appropriate flag so that volume // and v.f. corrections are re-calculated at every step. // // If available volume is different from box volume // due to walls, set volume appropriately; if walls will // move, set appropriate flag so that volume and v.f. corrections // are re-calculated at every step. flagdeform = flagwall = 0; for (int i = 0; i < modify->nfix; i++){ if (strcmp(modify->fix[i]->style,"deform") == 0) flagdeform = 1; else if (strstr(modify->fix[i]->style,"wall") != NULL) { if (flagwall) error->all(FLERR, "Cannot use multiple fix wall commands with " "pair lubricateU"); flagwall = 1; // Walls exist wallfix = (FixWall *) modify->fix[i]; if (wallfix->xflag) flagwall = 2; // Moving walls exist } } // set the isotropic constants depending on the volume fraction // vol_T = total volumeshearing = flagdeform = flagwall = 0; double vol_T, wallcoord; if (!flagwall) vol_T = domain->xprd*domain->yprd*domain->zprd; else { double wallhi[3], walllo[3]; for (int j = 0; j < 3; j++){ wallhi[j] = domain->prd[j]; walllo[j] = 0; } for (int m = 0; m < wallfix->nwall; m++){ int dim = wallfix->wallwhich[m] / 2; int side = wallfix->wallwhich[m] % 2; if (wallfix->xstyle[m] == VARIABLE){ wallfix->xindex[m] = input->variable->find(wallfix->xstr[m]); //Since fix->wall->init happens after pair->init_style wallcoord = input->variable->compute_equal(wallfix->xindex[m]); } else wallcoord = wallfix->coord0[m]; if (side == 0) walllo[dim] = wallcoord; else wallhi[dim] = wallcoord; } vol_T = (wallhi[0] - walllo[0]) * (wallhi[1] - walllo[1]) * (wallhi[2] - walllo[2]); } // assuming monodisperse spheres, vol_P = volume of the particles double tmp = 0.0; if (atom->radius) tmp = atom->radius[0]; MPI_Allreduce(&tmp,&rad,1,MPI_DOUBLE,MPI_MAX,world); vol_P = atom->natoms * (4.0/3.0)*MY_PI*pow(rad,3.0); // vol_f = volume fraction double vol_f = vol_P/vol_T; if (!flagVF) vol_f = 0; // set the isotropic constant if (flaglog == 0) { R0 = 6*MY_PI*mu*rad*(1.0 + 2.16*vol_f); RT0 = 8*MY_PI*mu*pow(rad,3.0); // not actually needed RS0 = 20.0/3.0*MY_PI*mu*pow(rad,3.0)*(1.0 + 3.33*vol_f + 2.80*vol_f*vol_f); } else { R0 = 6*MY_PI*mu*rad*(1.0 + 2.725*vol_f - 6.583*vol_f*vol_f); RT0 = 8*MY_PI*mu*pow(rad,3.0)*(1.0 + 0.749*vol_f - 2.469*vol_f*vol_f); RS0 = 20.0/3.0*MY_PI*mu*pow(rad,3.0)*(1.0 + 3.64*vol_f - 6.95*vol_f*vol_f); } } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairLubricateU::init_one(int i, int j) { if (setflag[i][j] == 0) { cut_inner[i][j] = mix_distance(cut_inner[i][i],cut_inner[j][j]); cut[i][j] = mix_distance(cut[i][i],cut[j][j]); } cut_inner[j][i] = cut_inner[i][j]; return cut[i][j]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLubricateU::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_inner[i][j],sizeof(double),1,fp); fwrite(&cut[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLubricateU::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_inner[i][j],sizeof(double),1,fp); fread(&cut[i][j],sizeof(double),1,fp); } MPI_Bcast(&cut_inner[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLubricateU::write_restart_settings(FILE *fp) { fwrite(&mu,sizeof(double),1,fp); fwrite(&flaglog,sizeof(int),1,fp); fwrite(&cut_inner_global,sizeof(double),1,fp); fwrite(&cut_global,sizeof(double),1,fp); fwrite(&offset_flag,sizeof(int),1,fp); fwrite(&mix_flag,sizeof(int),1,fp); fwrite(&flagHI,sizeof(int),1,fp); fwrite(&flagVF,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLubricateU::read_restart_settings(FILE *fp) { int me = comm->me; if (me == 0) { fread(&mu,sizeof(double),1,fp); fread(&flaglog,sizeof(int),1,fp); fread(&cut_inner_global,sizeof(double),1,fp); fread(&cut_global,sizeof(double),1,fp); fread(&offset_flag,sizeof(int),1,fp); fread(&mix_flag,sizeof(int),1,fp); fread(&flagHI,sizeof(int),1,fp); fread(&flagVF,sizeof(int),1,fp); } MPI_Bcast(&mu,1,MPI_DOUBLE,0,world); MPI_Bcast(&flaglog,1,MPI_INT,0,world); MPI_Bcast(&cut_inner_global,1,MPI_DOUBLE,0,world); 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); MPI_Bcast(&flagHI,1,MPI_INT,0,world); MPI_Bcast(&flagVF,1,MPI_INT,0,world); } /*---------------------------------------------------------------------------*/ void PairLubricateU::copy_vec_uo(int inum, double *xcg, double **v, double **omega) { int i,j,ii; int *ilist = list->ilist; for (ii=0;iiilist; for (ii=0;iiv; double **omega = atom->omega; m = 0; for (i = 0; i < n; i++) { j = list[i]; buf[m++] = v[j][0]; buf[m++] = v[j][1]; buf[m++] = v[j][2]; buf[m++] = omega[j][0]; buf[m++] = omega[j][1]; buf[m++] = omega[j][2]; } return m; } /* ---------------------------------------------------------------------- */ void PairLubricateU::unpack_forward_comm(int n, int first, double *buf) { int i,m,last; double **v = atom->v; double **omega = atom->omega; m = 0; last = first + n; for (i = first; i < last; i++) { v[i][0] = buf[m++]; v[i][1] = buf[m++]; v[i][2] = buf[m++]; omega[i][0] = buf[m++]; omega[i][1] = buf[m++]; omega[i][2] = buf[m++]; } } /* ---------------------------------------------------------------------- */ double PairLubricateU::dot_vec_vec(int N, double *x, double *y) { double dotp=0.0; for (int i = 0; i < N; i++) dotp += x[i]*y[i]; return dotp; } diff --git a/src/DIPOLE/pair_lj_cut_dipole_cut.cpp b/src/DIPOLE/pair_lj_cut_dipole_cut.cpp index 53c977f87..c57eb09e5 100644 --- a/src/DIPOLE/pair_lj_cut_dipole_cut.cpp +++ b/src/DIPOLE/pair_lj_cut_dipole_cut.cpp @@ -1,486 +1,486 @@ /* ---------------------------------------------------------------------- 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 #include #include "pair_lj_cut_dipole_cut.h" #include "atom.h" #include "neighbor.h" #include "neigh_list.h" #include "comm.h" #include "force.h" #include "memory.h" #include "error.h" #include "update.h" #include using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ PairLJCutDipoleCut::PairLJCutDipoleCut(LAMMPS *lmp) : Pair(lmp) { single_enable = 0; } /* ---------------------------------------------------------------------- */ PairLJCutDipoleCut::~PairLJCutDipoleCut() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut_lj); memory->destroy(cut_ljsq); memory->destroy(cut_coul); memory->destroy(cut_coulsq); memory->destroy(epsilon); memory->destroy(sigma); memory->destroy(lj1); memory->destroy(lj2); memory->destroy(lj3); memory->destroy(lj4); memory->destroy(offset); } } /* ---------------------------------------------------------------------- */ void PairLJCutDipoleCut::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fx,fy,fz; double rsq,rinv,r2inv,r6inv,r3inv,r5inv,r7inv; double forcecoulx,forcecouly,forcecoulz,crossx,crossy,crossz; double tixcoul,tiycoul,tizcoul,tjxcoul,tjycoul,tjzcoul; double fq,pdotp,pidotr,pjdotr,pre1,pre2,pre3,pre4; double forcelj,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; double **mu = atom->mu; double **torque = atom->torque; 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; rinv = sqrt(r2inv); // atom can have both a charge and dipole // i,j = charge-charge, dipole-dipole, dipole-charge, or charge-dipole forcecoulx = forcecouly = forcecoulz = 0.0; tixcoul = tiycoul = tizcoul = 0.0; tjxcoul = tjycoul = tjzcoul = 0.0; if (rsq < cut_coulsq[itype][jtype]) { if (qtmp != 0.0 && q[j] != 0.0) { r3inv = r2inv*rinv; pre1 = qtmp*q[j]*r3inv; forcecoulx += pre1*delx; forcecouly += pre1*dely; forcecoulz += pre1*delz; } if (mu[i][3] > 0.0 && mu[j][3] > 0.0) { r3inv = r2inv*rinv; r5inv = r3inv*r2inv; r7inv = r5inv*r2inv; pdotp = mu[i][0]*mu[j][0] + mu[i][1]*mu[j][1] + mu[i][2]*mu[j][2]; pidotr = mu[i][0]*delx + mu[i][1]*dely + mu[i][2]*delz; pjdotr = mu[j][0]*delx + mu[j][1]*dely + mu[j][2]*delz; pre1 = 3.0*r5inv*pdotp - 15.0*r7inv*pidotr*pjdotr; pre2 = 3.0*r5inv*pjdotr; pre3 = 3.0*r5inv*pidotr; pre4 = -1.0*r3inv; forcecoulx += pre1*delx + pre2*mu[i][0] + pre3*mu[j][0]; forcecouly += pre1*dely + pre2*mu[i][1] + pre3*mu[j][1]; forcecoulz += pre1*delz + pre2*mu[i][2] + pre3*mu[j][2]; crossx = pre4 * (mu[i][1]*mu[j][2] - mu[i][2]*mu[j][1]); crossy = pre4 * (mu[i][2]*mu[j][0] - mu[i][0]*mu[j][2]); crossz = pre4 * (mu[i][0]*mu[j][1] - mu[i][1]*mu[j][0]); tixcoul += crossx + pre2 * (mu[i][1]*delz - mu[i][2]*dely); tiycoul += crossy + pre2 * (mu[i][2]*delx - mu[i][0]*delz); tizcoul += crossz + pre2 * (mu[i][0]*dely - mu[i][1]*delx); tjxcoul += -crossx + pre3 * (mu[j][1]*delz - mu[j][2]*dely); tjycoul += -crossy + pre3 * (mu[j][2]*delx - mu[j][0]*delz); tjzcoul += -crossz + pre3 * (mu[j][0]*dely - mu[j][1]*delx); } if (mu[i][3] > 0.0 && q[j] != 0.0) { r3inv = r2inv*rinv; r5inv = r3inv*r2inv; pidotr = mu[i][0]*delx + mu[i][1]*dely + mu[i][2]*delz; pre1 = 3.0*q[j]*r5inv * pidotr; pre2 = q[j]*r3inv; forcecoulx += pre2*mu[i][0] - pre1*delx; forcecouly += pre2*mu[i][1] - pre1*dely; forcecoulz += pre2*mu[i][2] - pre1*delz; tixcoul += pre2 * (mu[i][1]*delz - mu[i][2]*dely); tiycoul += pre2 * (mu[i][2]*delx - mu[i][0]*delz); tizcoul += pre2 * (mu[i][0]*dely - mu[i][1]*delx); } if (mu[j][3] > 0.0 && qtmp != 0.0) { r3inv = r2inv*rinv; r5inv = r3inv*r2inv; pjdotr = mu[j][0]*delx + mu[j][1]*dely + mu[j][2]*delz; pre1 = 3.0*qtmp*r5inv * pjdotr; pre2 = qtmp*r3inv; forcecoulx += pre1*delx - pre2*mu[j][0]; forcecouly += pre1*dely - pre2*mu[j][1]; forcecoulz += pre1*delz - pre2*mu[j][2]; tjxcoul += -pre2 * (mu[j][1]*delz - mu[j][2]*dely); tjycoul += -pre2 * (mu[j][2]*delx - mu[j][0]*delz); tjzcoul += -pre2 * (mu[j][0]*dely - mu[j][1]*delx); } } // LJ interaction if (rsq < cut_ljsq[itype][jtype]) { r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); forcelj *= factor_lj * r2inv; } else forcelj = 0.0; // total force fq = factor_coul*qqrd2e; fx = fq*forcecoulx + delx*forcelj; fy = fq*forcecouly + dely*forcelj; fz = fq*forcecoulz + delz*forcelj; // force & torque accumulation f[i][0] += fx; f[i][1] += fy; f[i][2] += fz; torque[i][0] += fq*tixcoul; torque[i][1] += fq*tiycoul; torque[i][2] += fq*tizcoul; if (newton_pair || j < nlocal) { f[j][0] -= fx; f[j][1] -= fy; f[j][2] -= fz; torque[j][0] += fq*tjxcoul; torque[j][1] += fq*tjycoul; torque[j][2] += fq*tjzcoul; } if (eflag) { if (rsq < cut_coulsq[itype][jtype]) { ecoul = qtmp*q[j]*rinv; if (mu[i][3] > 0.0 && mu[j][3] > 0.0) ecoul += r3inv*pdotp - 3.0*r5inv*pidotr*pjdotr; if (mu[i][3] > 0.0 && q[j] != 0.0) ecoul += -q[j]*r3inv*pidotr; if (mu[j][3] > 0.0 && qtmp != 0.0) ecoul += qtmp*r3inv*pjdotr; ecoul *= factor_coul*qqrd2e; } 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_xyz(i,j,nlocal,newton_pair, evdwl,ecoul,fx,fy,fz,delx,dely,delz); } } } if (vflag_fdotr) virial_fdotr_compute(); } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairLJCutDipoleCut::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(cut_coul,n+1,n+1,"pair:cut_coul"); memory->create(cut_coulsq,n+1,n+1,"pair:cut_coulsq"); 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 PairLJCutDipoleCut::settings(int narg, char **arg) { if (narg < 1 || narg > 2) error->all(FLERR,"Incorrect args in pair_style command"); if (strcmp(update->unit_style,"electron") == 0) error->all(FLERR,"Cannot (yet) use 'electron' units with dipoles"); cut_lj_global = force->numeric(FLERR,arg[0]); if (narg == 1) cut_coul_global = cut_lj_global; else cut_coul_global = force->numeric(FLERR,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; cut_coul[i][j] = cut_coul_global; } } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairLJCutDipoleCut::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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(FLERR,arg[2]); double sigma_one = force->numeric(FLERR,arg[3]); double cut_lj_one = cut_lj_global; double cut_coul_one = cut_coul_global; if (narg >= 5) cut_coul_one = cut_lj_one = force->numeric(FLERR,arg[4]); if (narg == 6) cut_coul_one = force->numeric(FLERR,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; cut_lj[i][j] = cut_lj_one; cut_coul[i][j] = cut_coul_one; setflag[i][j] = 1; count++; } } if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairLJCutDipoleCut::init_style() { if (!atom->q_flag || !atom->mu_flag || !atom->torque_flag) error->all(FLERR,"Pair dipole/cut requires atom attributes q, mu, torque"); neighbor->request(this,instance_me); } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairLJCutDipoleCut::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]); cut_coul[i][j] = mix_distance(cut_coul[i][i],cut_coul[j][j]); } double cut = MAX(cut_lj[i][j],cut_coul[i][j]); cut_ljsq[i][j] = cut_lj[i][j] * cut_lj[i][j]; cut_coulsq[i][j] = cut_coul[i][j] * cut_coul[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]; cut_coulsq[j][i] = cut_coulsq[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]; return cut; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJCutDipoleCut::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); fwrite(&cut_coul[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJCutDipoleCut::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); fread(&cut_coul[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); MPI_Bcast(&cut_coul[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJCutDipoleCut::write_restart_settings(FILE *fp) { fwrite(&cut_lj_global,sizeof(double),1,fp); fwrite(&cut_coul_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 PairLJCutDipoleCut::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&cut_lj_global,sizeof(double),1,fp); fread(&cut_coul_global,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_global,1,MPI_DOUBLE,0,world); MPI_Bcast(&offset_flag,1,MPI_INT,0,world); MPI_Bcast(&mix_flag,1,MPI_INT,0,world); } diff --git a/src/DIPOLE/pair_lj_cut_dipole_long.cpp b/src/DIPOLE/pair_lj_cut_dipole_long.cpp index 3f44579b8..ae85b55ff 100644 --- a/src/DIPOLE/pair_lj_cut_dipole_long.cpp +++ b/src/DIPOLE/pair_lj_cut_dipole_long.cpp @@ -1,559 +1,559 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator www.cs.sandia.gov/~sjplimp/lammps.html Steve Plimpton, sjplimp@sandia.gov, Sandia National Laboratories 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 #include #include #include #include "pair_lj_cut_dipole_long.h" #include "atom.h" #include "comm.h" #include "neighbor.h" #include "neigh_list.h" #include "force.h" #include "kspace.h" #include "math_const.h" #include "memory.h" #include "error.h" #include "update.h" #include 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 /* ---------------------------------------------------------------------- */ PairLJCutDipoleLong::PairLJCutDipoleLong(LAMMPS *lmp) : Pair(lmp) { single_enable = 0; ewaldflag = dipoleflag = 1; respa_enable = 0; } /* ---------------------------------------------------------------------- free all arrays ------------------------------------------------------------------------- */ PairLJCutDipoleLong::~PairLJCutDipoleLong() { 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 PairLJCutDipoleLong::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double qtmp,xtmp,ytmp,ztmp,delx,dely,delz; double rsq,r,rinv,r2inv,r6inv; double forcecoulx,forcecouly,forcecoulz,fforce; double tixcoul,tiycoul,tizcoul,tjxcoul,tjycoul,tjzcoul; double fx,fy,fz,fdx,fdy,fdz,fax,fay,faz; double pdotp,pidotr,pjdotr,pre1,pre2,pre3; double grij,expm2,t,erfc; double g0,g1,g2,b0,b1,b2,b3,d0,d1,d2,d3; double zdix,zdiy,zdiz,zdjx,zdjy,zdjz,zaix,zaiy,zaiz,zajx,zajy,zajz; double g0b1_g1b2_g2b3,g0d1_g1d2_g2d3; double forcelj,factor_coul,factor_lj,facm1; double evdwl,ecoul; 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; double **mu = atom->mu; double **torque = atom->torque; 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; pre1 = 2.0 * g_ewald / MY_PIS; pre2 = 4.0 * pow(g_ewald,3.0) / MY_PIS; pre3 = 8.0 * pow(g_ewald,5.0) / MY_PIS; // loop over neighbors of my atoms for (ii = 0; ii < inum; ii++) { i = ilist[ii]; qtmp = atom->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; rinv = sqrt(r2inv); 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; pdotp = mu[i][0]*mu[j][0] + mu[i][1]*mu[j][1] + mu[i][2]*mu[j][2]; pidotr = mu[i][0]*delx + mu[i][1]*dely + mu[i][2]*delz; pjdotr = mu[j][0]*delx + mu[j][1]*dely + mu[j][2]*delz; g0 = qtmp*q[j]; g1 = qtmp*pjdotr - q[j]*pidotr + pdotp; g2 = -pidotr*pjdotr; if (factor_coul > 0.0) { b0 = erfc * rinv; b1 = (b0 + pre1*expm2) * r2inv; b2 = (3.0*b1 + pre2*expm2) * r2inv; b3 = (5.0*b2 + pre3*expm2) * r2inv; g0b1_g1b2_g2b3 = g0*b1 + g1*b2 + g2*b3; fdx = delx * g0b1_g1b2_g2b3 - b1 * (qtmp*mu[j][0] - q[j]*mu[i][0]) + b2 * (pjdotr*mu[i][0] + pidotr*mu[j][0]); fdy = dely * g0b1_g1b2_g2b3 - b1 * (qtmp*mu[j][1] - q[j]*mu[i][1]) + b2 * (pjdotr*mu[i][1] + pidotr*mu[j][1]); fdz = delz * g0b1_g1b2_g2b3 - b1 * (qtmp*mu[j][2] - q[j]*mu[i][2]) + b2 * (pjdotr*mu[i][2] + pidotr*mu[j][2]); zdix = delx * (q[j]*b1 + b2*pjdotr) - b1*mu[j][0]; zdiy = dely * (q[j]*b1 + b2*pjdotr) - b1*mu[j][1]; zdiz = delz * (q[j]*b1 + b2*pjdotr) - b1*mu[j][2]; zdjx = delx * (-qtmp*b1 + b2*pidotr) - b1*mu[i][0]; zdjy = dely * (-qtmp*b1 + b2*pidotr) - b1*mu[i][1]; zdjz = delz * (-qtmp*b1 + b2*pidotr) - b1*mu[i][2]; if (factor_coul < 1.0) { fdx *= factor_coul; fdy *= factor_coul; fdz *= factor_coul; zdix *= factor_coul; zdiy *= factor_coul; zdiz *= factor_coul; zdjx *= factor_coul; zdjy *= factor_coul; zdjz *= factor_coul; } } else { fdx = fdy = fdz = 0.0; zdix = zdiy = zdiz = 0.0; zdjx = zdjy = zdjz = 0.0; } if (factor_coul < 1.0) { d0 = (erfc - 1.0) * rinv; d1 = (d0 + pre1*expm2) * r2inv; d2 = (3.0*d1 + pre2*expm2) * r2inv; d3 = (5.0*d2 + pre3*expm2) * r2inv; g0d1_g1d2_g2d3 = g0*d1 + g1*d2 + g2*d3; fax = delx * g0d1_g1d2_g2d3 - d1 * (qtmp*mu[j][0] - q[j]*mu[i][0]) + d2 * (pjdotr*mu[i][0] + pidotr*mu[j][0]); fay = dely * g0d1_g1d2_g2d3 - d1 * (qtmp*mu[j][1] - q[j]*mu[i][1]) + d2 * (pjdotr*mu[i][1] + pidotr*mu[j][1]); faz = delz * g0d1_g1d2_g2d3 - d1 * (qtmp*mu[j][2] - q[j]*mu[i][2]) + d2 * (pjdotr*mu[i][2] + pidotr*mu[j][2]); zaix = delx * (q[j]*d1 + d2*pjdotr) - d1*mu[j][0]; zaiy = dely * (q[j]*d1 + d2*pjdotr) - d1*mu[j][1]; zaiz = delz * (q[j]*d1 + d2*pjdotr) - d1*mu[j][2]; zajx = delx * (-qtmp*d1 + d2*pidotr) - d1*mu[i][0]; zajy = dely * (-qtmp*d1 + d2*pidotr) - d1*mu[i][1]; zajz = delz * (-qtmp*d1 + d2*pidotr) - d1*mu[i][2]; if (factor_coul > 0.0) { facm1 = 1.0 - factor_coul; fax *= facm1; fay *= facm1; faz *= facm1; zaix *= facm1; zaiy *= facm1; zaiz *= facm1; zajx *= facm1; zajy *= facm1; zajz *= facm1; } } else { fax = fay = faz = 0.0; zaix = zaiy = zaiz = 0.0; zajx = zajy = zajz = 0.0; } forcecoulx = fdx + fax; forcecouly = fdy + fay; forcecoulz = fdz + faz; tixcoul = mu[i][1]*(zdiz + zaiz) - mu[i][2]*(zdiy + zaiy); tiycoul = mu[i][2]*(zdix + zaix) - mu[i][0]*(zdiz + zaiz); tizcoul = mu[i][0]*(zdiy + zaiy) - mu[i][1]*(zdix + zaix); tjxcoul = mu[j][1]*(zdjz + zajz) - mu[j][2]*(zdjy + zajy); tjycoul = mu[j][2]*(zdjx + zajx) - mu[j][0]*(zdjz + zajz); tjzcoul = mu[j][0]*(zdjy + zajy) - mu[j][1]*(zdjx + zajx); } else { forcecoulx = forcecouly = forcecoulz = 0.0; tixcoul = tiycoul = tizcoul = 0.0; tjxcoul = tjycoul = tjzcoul = 0.0; } // LJ interaction if (rsq < cut_ljsq[itype][jtype]) { r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); fforce = factor_lj * forcelj*r2inv; } else fforce = 0.0; // total force fx = qqrd2e*forcecoulx + delx*fforce; fy = qqrd2e*forcecouly + dely*fforce; fz = qqrd2e*forcecoulz + delz*fforce; // force & torque accumulation f[i][0] += fx; f[i][1] += fy; f[i][2] += fz; torque[i][0] += qqrd2e*tixcoul; torque[i][1] += qqrd2e*tiycoul; torque[i][2] += qqrd2e*tizcoul; if (newton_pair || j < nlocal) { f[j][0] -= fx; f[j][1] -= fy; f[j][2] -= fz; torque[j][0] += qqrd2e*tjxcoul; torque[j][1] += qqrd2e*tjycoul; torque[j][2] += qqrd2e*tjzcoul; } if (eflag) { if (rsq < cut_coulsq && factor_coul > 0.0) { ecoul = qqrd2e*(b0*g0 + b1*g1 + b2*g2); if (factor_coul < 1.0) { ecoul *= factor_coul; ecoul += (1-factor_coul) * qqrd2e * (d0*g0 + d1*g1 + d2*g2); } } 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_xyz(i,j,nlocal,newton_pair, evdwl,ecoul,fx,fy,fz,delx,dely,delz); } } } if (vflag_fdotr) virial_fdotr_compute(); } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairLJCutDipoleLong::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 PairLJCutDipoleLong::settings(int narg, char **arg) { if (narg < 1 || narg > 2) error->all(FLERR,"Incorrect args in pair_style command"); cut_lj_global = force->numeric(FLERR,arg[0]); if (narg == 1) cut_coul = cut_lj_global; else cut_coul = force->numeric(FLERR,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 PairLJCutDipoleLong::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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(FLERR,arg[2]); double sigma_one = force->numeric(FLERR,arg[3]); double cut_lj_one = cut_lj_global; if (narg == 5) cut_lj_one = force->numeric(FLERR,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 for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairLJCutDipoleLong::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]; return cut; } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairLJCutDipoleLong::init_style() { if (!atom->q_flag || !atom->mu_flag || !atom->torque_flag) error->all(FLERR,"Pair dipole/long requires atom attributes q, mu, torque"); if (strcmp(update->unit_style,"electron") == 0) error->all(FLERR,"Cannot (yet) use 'electron' units with dipoles"); // insure use of KSpace long-range solver, set g_ewald if (force->kspace == NULL) error->all(FLERR,"Pair style requires a KSpace style"); g_ewald = force->kspace->g_ewald; cut_coulsq = cut_coul * cut_coul; neighbor->request(this,instance_me); } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJCutDipoleLong::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 PairLJCutDipoleLong::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 PairLJCutDipoleLong::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 PairLJCutDipoleLong::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); } /* ---------------------------------------------------------------------- */ void *PairLJCutDipoleLong::extract(const char *str, int &dim) { if (strcmp(str,"cut_coul") == 0) { dim = 0; return (void *) &cut_coul; } else if (strcmp(str,"ewald_order") == 0) { ewald_order = 0; ewald_order |= 1<<1; ewald_order |= 1<<3; dim = 0; return (void *) &ewald_order; } else if (strcmp(str,"ewald_mix") == 0) { dim = 0; return (void *) &mix_flag; } return NULL; } diff --git a/src/DIPOLE/pair_lj_long_dipole_long.cpp b/src/DIPOLE/pair_lj_long_dipole_long.cpp index 248865ef7..ef865b66c 100644 --- a/src/DIPOLE/pair_lj_long_dipole_long.cpp +++ b/src/DIPOLE/pair_lj_long_dipole_long.cpp @@ -1,682 +1,682 @@ /* ---------------------------------------------------------------------- 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: Pieter J. in 't Veld and Stan Moore (Sandia) ------------------------------------------------------------------------- */ #include #include #include #include #include "math_const.h" #include "math_vector.h" #include "pair_lj_long_dipole_long.h" #include "atom.h" #include "comm.h" #include "neighbor.h" #include "neigh_list.h" #include "neigh_request.h" #include "force.h" #include "kspace.h" #include "update.h" #include "integrate.h" #include "respa.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 // ---------------------------------------------------------------------- PairLJLongDipoleLong::PairLJLongDipoleLong(LAMMPS *lmp) : Pair(lmp) { dispersionflag = ewaldflag = dipoleflag = 1; respa_enable = 0; single_enable = 0; } // ---------------------------------------------------------------------- // global settings // ---------------------------------------------------------------------- void PairLJLongDipoleLong::options(char **arg, int order) { const char *option[] = {"long", "cut", "off", NULL}; int i; if (!*arg) error->all(FLERR,"Illegal pair_style lj/long/dipole/long command"); for (i=0; option[i]&&strcmp(arg[0], option[i]); ++i); switch (i) { default: error->all(FLERR,"Illegal pair_style lj/long/dipole/long command"); case 0: ewald_order |= 1<all(FLERR,"Illegal pair_style command"); ewald_off = 0; ewald_order = 0; options(arg, 6); options(++arg, 3); options(arg, 1); if (!comm->me && ewald_order&(1<<6)) error->warning(FLERR,"Geometric mixing assumed for 1/r^6 coefficients"); if (!comm->me && ewald_order==((1<<3)|(1<<6))) error->warning(FLERR, "Using largest cut-off for lj/long/dipole/long long long"); if (!*(++arg)) error->all(FLERR,"Cut-offs missing in pair_style lj/long/dipole/long"); if (!((ewald_order^ewald_off)&(1<<3))) error->all(FLERR, "Coulombic cut not supported in pair_style lj/long/dipole/long"); cut_lj_global = force->numeric(FLERR,*(arg++)); if (narg == 4 && (ewald_order==74)) error->all(FLERR,"Only one cut-off allowed when requesting all long"); if (narg == 4) cut_coul = force->numeric(FLERR,*(arg++)); else cut_coul = cut_lj_global; if (allocated) { // reset explicit cuts 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; } } // ---------------------------------------------------------------------- // free all arrays // ---------------------------------------------------------------------- PairLJLongDipoleLong::~PairLJLongDipoleLong() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut_lj_read); memory->destroy(cut_lj); memory->destroy(cut_ljsq); memory->destroy(epsilon_read); memory->destroy(epsilon); memory->destroy(sigma_read); memory->destroy(sigma); memory->destroy(lj1); memory->destroy(lj2); memory->destroy(lj3); memory->destroy(lj4); memory->destroy(offset); } //if (ftable) free_tables(); } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairLJLongDipoleLong::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_read,n+1,n+1,"pair:cut_lj_read"); 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_read,n+1,n+1,"pair:epsilon_read"); memory->create(epsilon,n+1,n+1,"pair:epsilon"); memory->create(sigma_read,n+1,n+1,"pair:sigma_read"); 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"); } /* ---------------------------------------------------------------------- extract protected data from object ------------------------------------------------------------------------- */ void *PairLJLongDipoleLong::extract(const char *id, int &dim) { const char *ids[] = { "B", "sigma", "epsilon", "ewald_order", "ewald_cut", "ewald_mix", "cut_coul", "cut_vdwl", NULL}; void *ptrs[] = { lj4, sigma, epsilon, &ewald_order, &cut_coul, &mix_flag, &cut_coul, &cut_lj_global, NULL}; int i; for (i=0; ids[i]&&strcmp(ids[i], id); ++i); if (i <= 2) dim = 2; else dim = 0; return ptrs[i]; } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairLJLongDipoleLong::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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(FLERR,arg[2]); double sigma_one = force->numeric(FLERR,arg[3]); double cut_lj_one = cut_lj_global; if (narg == 5) cut_lj_one = force->numeric(FLERR,arg[4]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { epsilon_read[i][j] = epsilon_one; sigma_read[i][j] = sigma_one; cut_lj_read[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 PairLJLongDipoleLong::init_style() { const char *style3[] = {"ewald/disp", NULL}; const char *style6[] = {"ewald/disp", NULL}; int i; if (strcmp(update->unit_style,"electron") == 0) error->all(FLERR,"Cannot (yet) use 'electron' units with dipoles"); // require an atom style with charge defined if (!atom->q_flag && (ewald_order&(1<<1))) error->all(FLERR, "Invoking coulombic in pair style lj/long/dipole/long requires atom attribute q"); if (!atom->mu && (ewald_order&(1<<3))) error->all(FLERR,"Pair lj/long/dipole/long requires atom attributes mu, torque"); if (!atom->torque && (ewald_order&(1<<3))) error->all(FLERR,"Pair lj/long/dipole/long requires atom attributes mu, torque"); neighbor->request(this,instance_me); cut_coulsq = cut_coul * cut_coul; // ensure use of KSpace long-range solver, set g_ewald if (ewald_order&(1<<3)) { // r^-1 kspace if (force->kspace == NULL) error->all(FLERR,"Pair style requires a KSpace style"); for (i=0; style3[i]&&strcmp(force->kspace_style, style3[i]); ++i); if (!style3[i]) error->all(FLERR,"Pair style requires use of kspace_style ewald/disp"); } if (ewald_order&(1<<6)) { // r^-6 kspace if (force->kspace == NULL) error->all(FLERR,"Pair style requires a KSpace style"); for (i=0; style6[i]&&strcmp(force->kspace_style, style6[i]); ++i); if (!style6[i]) error->all(FLERR,"Pair style requires use of kspace_style ewald/disp"); } if (force->kspace) g_ewald = force->kspace->g_ewald; } /* ---------------------------------------------------------------------- neighbor callback to inform pair style of neighbor list to use regular or rRESPA ------------------------------------------------------------------------- */ void PairLJLongDipoleLong::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; if (id) error->all(FLERR,"Pair style lj/long/dipole/long does not currently support respa"); } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairLJLongDipoleLong::init_one(int i, int j) { if ((ewald_order&(1<<6))||(setflag[i][j] == 0)) { epsilon[i][j] = mix_energy(epsilon_read[i][i],epsilon_read[j][j], sigma_read[i][i],sigma_read[j][j]); sigma[i][j] = mix_distance(sigma_read[i][i],sigma_read[j][j]); if (ewald_order&(1<<6)) cut_lj[i][j] = cut_lj_global; else cut_lj[i][j] = mix_distance(cut_lj_read[i][i],cut_lj_read[j][j]); } else { sigma[i][j] = sigma_read[i][j]; epsilon[i][j] = epsilon_read[i][j]; cut_lj[i][j] = cut_lj_read[i][j]; } double cut = MAX(cut_lj[i][j], cut_coul); cutsq[i][j] = cut*cut; 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); // 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"); 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; cutsq[j][i] = cutsq[i][j]; 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]; return cut; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJLongDipoleLong::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_read[i][j],sizeof(double),1,fp); fwrite(&sigma_read[i][j],sizeof(double),1,fp); fwrite(&cut_lj_read[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJLongDipoleLong::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_read[i][j],sizeof(double),1,fp); fread(&sigma_read[i][j],sizeof(double),1,fp); fread(&cut_lj_read[i][j],sizeof(double),1,fp); } MPI_Bcast(&epsilon_read[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&sigma_read[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_lj_read[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJLongDipoleLong::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); fwrite(&ewald_order,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJLongDipoleLong::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); fread(&ewald_order,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); MPI_Bcast(&ewald_order,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- compute pair interactions ------------------------------------------------------------------------- */ void PairLJLongDipoleLong::compute(int eflag, int vflag) { double evdwl,ecoul,fpair; evdwl = ecoul = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; double **x = atom->x, *x0 = x[0]; double **mu = atom->mu, *mu0 = mu[0], *imu, *jmu; double **tq = atom->torque, *tq0 = tq[0], *tqi; double **f = atom->f, *f0 = f[0], *fi = f0, fx, fy, fz; double *q = atom->q, qi = 0, qj; 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; int i, j; int order3 = ewald_order&(1<<3), order6 = ewald_order&(1<<6); int *ineigh, *ineighn, *jneigh, *jneighn, typei, typej, ni; double *cutsqi, *cut_ljsqi, *lj1i, *lj2i, *lj3i, *lj4i, *offseti; double rsq, r2inv, force_coul, force_lj; double g2 = g_ewald*g_ewald, g6 = g2*g2*g2, g8 = g6*g2; double B0, B1, B2, B3, G0, G1, G2, mudi, mudj, muij; vector force_d = VECTOR_NULL, ti = VECTOR_NULL, tj = VECTOR_NULL; vector mui, muj, xi, d; double C1 = 2.0 * g_ewald / MY_PIS; double C2 = 2.0 * g2 * C1; double C3 = 2.0 * g2 * C2; ineighn = (ineigh = list->ilist)+list->inum; for (; ineighfirstneigh[i])+list->numneigh[i]; for (; jneigh= cutsqi[typej = type[j]]) continue; r2inv = 1.0/rsq; if (order3 && (rsq < cut_coulsq)) { // dipole memcpy(muj, jmu = mu0+(j<<2), sizeof(vector)); { // series real space register double r = sqrt(rsq); register double x = g_ewald*r; register double f = exp(-x*x)*qqrd2e; B0 = 1.0/(1.0+EWALD_P*x); // eqn 2.8 B0 *= ((((A5*B0+A4)*B0+A3)*B0+A2)*B0+A1)*f/r; B1 = (B0 + C1 * f) * r2inv; B2 = (3.0*B1 + C2 * f) * r2inv; B3 = (5.0*B2 + C3 * f) * r2inv; mudi = mui[0]*d[0]+mui[1]*d[1]+mui[2]*d[2]; mudj = muj[0]*d[0]+muj[1]*d[1]+muj[2]*d[2]; muij = mui[0]*muj[0]+mui[1]*muj[1]+mui[2]*muj[2]; G0 = qi*(qj = q[j]); // eqn 2.10 G1 = qi*mudj-qj*mudi+muij; G2 = -mudi*mudj; force_coul = G0*B1+G1*B2+G2*B3; mudi *= B2; mudj *= B2; // torque contribs ti[0] = mudj*d[0]+(qj*d[0]-muj[0])*B1; ti[1] = mudj*d[1]+(qj*d[1]-muj[1])*B1; ti[2] = mudj*d[2]+(qj*d[2]-muj[2])*B1; if (newton_pair || j < nlocal) { tj[0] = mudi*d[0]-(qi*d[0]+mui[0])*B1; tj[1] = mudi*d[1]-(qi*d[1]+mui[1])*B1; tj[2] = mudi*d[2]-(qi*d[2]+mui[2])*B1; } if (eflag) ecoul = G0*B0+G1*B1+G2*B2; if (ni > 0) { // adj part, eqn 2.13 force_coul -= (f = qqrd2e*(1.0-special_coul[ni])/r)*( (3.0*G1+15.0*G2*r2inv)*r2inv+G0)*r2inv; if (eflag) ecoul -= f*((G1+3.0*G2*r2inv)*r2inv+G0); B1 -= f*r2inv; } B0 = mudj+qj*B1; B3 = -qi*B1+mudi; // position independent if (ni > 0) B0 -= f*3.0*mudj*r2inv*r2inv/B2; if (ni > 0) B3 -= f*3.0*mudi*r2inv*r2inv/B2; force_d[0] = B0*mui[0]+B3*muj[0]; // force contribs force_d[1] = B0*mui[1]+B3*muj[1]; force_d[2] = B0*mui[2]+B3*muj[2]; if (ni > 0) { ti[0] -= f*(3.0*mudj*r2inv*r2inv*d[0]/B2+(qj*r2inv*d[0]-muj[0]*r2inv)); ti[1] -= f*(3.0*mudj*r2inv*r2inv*d[1]/B2+(qj*r2inv*d[1]-muj[1]*r2inv)); ti[2] -= f*(3.0*mudj*r2inv*r2inv*d[2]/B2+(qj*r2inv*d[2]-muj[2]*r2inv)); if (newton_pair || j < nlocal) { tj[0] -= f*(3.0*mudi*r2inv*r2inv*d[0]/B2-(qi*r2inv*d[0]+mui[0]*r2inv)); tj[1] -= f*(3.0*mudi*r2inv*r2inv*d[1]/B2-(qi*r2inv*d[1]+mui[1]*r2inv)); tj[2] -= f*(3.0*mudi*r2inv*r2inv*d[2]/B2-(qi*r2inv*d[2]+mui[2]*r2inv)); } } } // table real space } else { force_coul = ecoul = 0.0; memset(force_d, 0, 3*sizeof(double)); } if (rsq < cut_ljsqi[typej]) { // lj if (order6) { // long-range lj register double rn = r2inv*r2inv*r2inv; register double x2 = g2*rsq, a2 = 1.0/x2; x2 = a2*exp(-x2)*lj4i[typej]; if (ni < 0) { force_lj = (rn*=rn)*lj1i[typej]-g8*(((6.0*a2+6.0)*a2+3.0)*a2+1.0)*x2*rsq; if (eflag) evdwl = rn*lj3i[typej]-g6*((a2+1.0)*a2+0.5)*x2; } else { // special case register double f = special_lj[ni], t = rn*(1.0-f); force_lj = f*(rn *= rn)*lj1i[typej]- g8*(((6.0*a2+6.0)*a2+3.0)*a2+1.0)*x2*rsq+t*lj2i[typej]; if (eflag) evdwl = f*rn*lj3i[typej]-g6*((a2+1.0)*a2+0.5)*x2+t*lj4i[typej]; } } else { // cut lj register double rn = r2inv*r2inv*r2inv; if (ni < 0) { force_lj = rn*(rn*lj1i[typej]-lj2i[typej]); if (eflag) evdwl = rn*(rn*lj3i[typej]-lj4i[typej])-offseti[typej]; } else { // special case register double f = special_lj[ni]; force_lj = f*rn*(rn*lj1i[typej]-lj2i[typej]); if (eflag) evdwl = f*( rn*(rn*lj3i[typej]-lj4i[typej])-offseti[typej]); } } force_lj *= r2inv; } else force_lj = evdwl = 0.0; fpair = force_coul+force_lj; // force if (newton_pair || j < nlocal) { register double *fj = f0+(j+(j<<1)); fi[0] += fx = d[0]*fpair+force_d[0]; fj[0] -= fx; fi[1] += fy = d[1]*fpair+force_d[1]; fj[1] -= fy; fi[2] += fz = d[2]*fpair+force_d[2]; fj[2] -= fz; tqi[0] += mui[1]*ti[2]-mui[2]*ti[1]; // torque tqi[1] += mui[2]*ti[0]-mui[0]*ti[2]; tqi[2] += mui[0]*ti[1]-mui[1]*ti[0]; register double *tqj = tq0+(j+(j<<1)); tqj[0] += muj[1]*tj[2]-muj[2]*tj[1]; tqj[1] += muj[2]*tj[0]-muj[0]*tj[2]; tqj[2] += muj[0]*tj[1]-muj[1]*tj[0]; } else { fi[0] += fx = d[0]*fpair+force_d[0]; // force fi[1] += fy = d[1]*fpair+force_d[1]; fi[2] += fz = d[2]*fpair+force_d[2]; tqi[0] += mui[1]*ti[2]-mui[2]*ti[1]; // torque tqi[1] += mui[2]*ti[0]-mui[0]*ti[2]; tqi[2] += mui[0]*ti[1]-mui[1]*ti[0]; } if (evflag) ev_tally_xyz(i,j,nlocal,newton_pair, evdwl,ecoul,fx,fy,fz,d[0],d[1],d[2]); } } if (vflag_fdotr) virial_fdotr_compute(); } /* ---------------------------------------------------------------------- */ /* double PairLJLongDipoleLong::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r6inv, force_coul, force_lj; double g2 = g_ewald*g_ewald, g6 = g2*g2*g2, g8 = g6*g2, *q = atom->q; double eng = 0.0; double r2inv = 1.0/rsq; if ((ewald_order&(1<<3)) && (rsq < cut_coulsq)) { // coulombic double *mui = atom->mu[i], *muj = atom->mu[j]; double *xi = atom->x[i], *xj = atom->x[j]; double qi = q[i], qj = q[j]; double G0, G1, G2, B0, B1, B2, B3, mudi, mudj, muij; vector d = {xi[0]-xj[0], xi[1]-xj[1], xi[2]-xj[2]}; { // series real space register double r = sqrt(rsq); register double x = g_ewald*r; register double f = exp(-x*x)*qqrd2e; B0 = 1.0/(1.0+EWALD_P*x); // eqn 2.8 B0 *= ((((A5*B0+A4)*B0+A3)*B0+A2)*B0+A1)*f/r; B1 = (B0 + C1 * f) * r2inv; B2 = (3.0*B1 + C2 * f) * r2inv; B3 = (5.0*B2 + C3 * f) * r2inv; mudi = mui[0]*d[0]+mui[1]*d[1]+mui[2]*d[2]; mudj = muj[0]*d[0]+muj[1]*d[1]+muj[2]*d[2]; muij = mui[0]*muj[0]+mui[1]*muj[1]+mui[2]*muj[2]; G0 = qi*(qj = q[j]); // eqn 2.10 G1 = qi*mudj-qj*mudi+muij; G2 = -mudi*mudj; force_coul = G0*B1+G1*B2+G2*B3; eng += G0*B0+G1*B1+G2*B2; if (factor_coul < 1.0) { // adj part, eqn 2.13 force_coul -= (f = force->qqrd2e*(1.0-factor_coul)/r)*( (3.0*G1+6.0*muij+15.0*G2*r2inv)*r2inv+G0); eng -= f*((G1+3.0*G2*r2inv)*r2inv+G0); B1 -= f*r2inv; } B0 = mudj*B2-qj*B1; B3 = qi*B1+mudi*B2; // position independent //force_d[0] = B0*mui[0]+B3*muj[0]; // force contributions //force_d[1] = B0*mui[1]+B3*muj[1]; //force_d[2] = B0*mui[2]+B3*muj[2]; } // table real space } else force_coul = 0.0; if (rsq < cut_ljsq[itype][jtype]) { // lennard-jones r6inv = r2inv*r2inv*r2inv; if (ewald_order&0x40) { // long-range register double x2 = g2*rsq, a2 = 1.0/x2, t = r6inv*(1.0-factor_lj); x2 = a2*exp(-x2)*lj4[itype][jtype]; force_lj = factor_lj*(r6inv *= r6inv)*lj1[itype][jtype]- g8*(((6.0*a2+6.0)*a2+3.0)*a2+a2)*x2*rsq+t*lj2[itype][jtype]; eng += factor_lj*r6inv*lj3[itype][jtype]- g6*((a2+1.0)*a2+0.5)*x2+t*lj4[itype][jtype]; } else { // cut force_lj = factor_lj*r6inv*(lj1[itype][jtype]*r6inv-lj2[itype][jtype]); eng += factor_lj*(r6inv*(r6inv*lj3[itype][jtype]- lj4[itype][jtype])-offset[itype][jtype]); } } else force_lj = 0.0; fforce = (force_coul+force_lj)*r2inv; return eng; } */ diff --git a/src/GRANULAR/pair_gran_hooke_history.cpp b/src/GRANULAR/pair_gran_hooke_history.cpp index 2652381c9..edd12b4b2 100644 --- a/src/GRANULAR/pair_gran_hooke_history.cpp +++ b/src/GRANULAR/pair_gran_hooke_history.cpp @@ -1,801 +1,801 @@ /* ---------------------------------------------------------------------- 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: Leo Silbert (SNL), Gary Grest (SNL) ------------------------------------------------------------------------- */ #include #include #include #include #include "pair_gran_hooke_history.h" #include "atom.h" #include "atom_vec.h" #include "domain.h" #include "force.h" #include "update.h" #include "modify.h" #include "fix.h" #include "fix_shear_history.h" #include "comm.h" #include "neighbor.h" #include "neigh_list.h" #include "neigh_request.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ PairGranHookeHistory::PairGranHookeHistory(LAMMPS *lmp) : Pair(lmp) { single_enable = 1; no_virial_fdotr_compute = 1; history = 1; fix_history = NULL; single_extra = 10; svector = new double[10]; neighprev = 0; nmax = 0; mass_rigid = NULL; // set comm size needed by this Pair if used with fix rigid comm_forward = 1; } /* ---------------------------------------------------------------------- */ PairGranHookeHistory::~PairGranHookeHistory() { delete [] svector; if (fix_history) modify->delete_fix("SHEAR_HISTORY"); if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); delete [] onerad_dynamic; delete [] onerad_frozen; delete [] maxrad_dynamic; delete [] maxrad_frozen; } memory->destroy(mass_rigid); } /* ---------------------------------------------------------------------- */ void PairGranHookeHistory::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum; double xtmp,ytmp,ztmp,delx,dely,delz,fx,fy,fz; double radi,radj,radsum,rsq,r,rinv,rsqinv; double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3; double wr1,wr2,wr3; double vtr1,vtr2,vtr3,vrel; double mi,mj,meff,damp,ccel,tor1,tor2,tor3; double fn,fs,fs1,fs2,fs3; double shrmag,rsht; int *ilist,*jlist,*numneigh,**firstneigh; int *touch,**firsttouch; double *shear,*allshear,**firstshear; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; int shearupdate = 1; if (update->setupflag) shearupdate = 0; // update rigid body info for owned & ghost atoms if using FixRigid masses // body[i] = which body atom I is in, -1 if none // mass_body = mass of each rigid body if (fix_rigid && neighbor->ago == 0) { int tmp; int *body = (int *) fix_rigid->extract("body",tmp); double *mass_body = (double *) fix_rigid->extract("masstotal",tmp); if (atom->nmax > nmax) { memory->destroy(mass_rigid); nmax = atom->nmax; memory->create(mass_rigid,nmax,"pair:mass_rigid"); } int nlocal = atom->nlocal; for (i = 0; i < nlocal; i++) if (body[i] >= 0) mass_rigid[i] = mass_body[body[i]]; else mass_rigid[i] = 0.0; comm->forward_comm_pair(this); } double **x = atom->x; double **v = atom->v; double **f = atom->f; double **omega = atom->omega; double **torque = atom->torque; double *radius = atom->radius; double *rmass = atom->rmass; int *mask = atom->mask; int nlocal = atom->nlocal; int newton_pair = force->newton_pair; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; firsttouch = listgranhistory->firstneigh; firstshear = listgranhistory->firstdouble; // 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]; radi = radius[i]; touch = firsttouch[i]; allshear = firstshear[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; radj = radius[j]; radsum = radi + radj; if (rsq >= radsum*radsum) { // unset non-touching neighbors touch[jj] = 0; shear = &allshear[3*jj]; shear[0] = 0.0; shear[1] = 0.0; shear[2] = 0.0; } else { r = sqrt(rsq); rinv = 1.0/r; rsqinv = 1.0/rsq; // relative translational velocity vr1 = v[i][0] - v[j][0]; vr2 = v[i][1] - v[j][1]; vr3 = v[i][2] - v[j][2]; // normal component vnnr = vr1*delx + vr2*dely + vr3*delz; vn1 = delx*vnnr * rsqinv; vn2 = dely*vnnr * rsqinv; vn3 = delz*vnnr * rsqinv; // tangential component vt1 = vr1 - vn1; vt2 = vr2 - vn2; vt3 = vr3 - vn3; // relative rotational velocity wr1 = (radi*omega[i][0] + radj*omega[j][0]) * rinv; wr2 = (radi*omega[i][1] + radj*omega[j][1]) * rinv; wr3 = (radi*omega[i][2] + radj*omega[j][2]) * rinv; // meff = effective mass of pair of particles // if I or J part of rigid body, use body mass // if I or J is frozen, meff is other particle mi = rmass[i]; mj = rmass[j]; if (fix_rigid) { if (mass_rigid[i] > 0.0) mi = mass_rigid[i]; if (mass_rigid[j] > 0.0) mj = mass_rigid[j]; } meff = mi*mj / (mi+mj); if (mask[i] & freeze_group_bit) meff = mj; if (mask[j] & freeze_group_bit) meff = mi; // normal forces = Hookian contact + normal velocity damping damp = meff*gamman*vnnr*rsqinv; ccel = kn*(radsum-r)*rinv - damp; // relative velocities vtr1 = vt1 - (delz*wr2-dely*wr3); vtr2 = vt2 - (delx*wr3-delz*wr1); vtr3 = vt3 - (dely*wr1-delx*wr2); vrel = vtr1*vtr1 + vtr2*vtr2 + vtr3*vtr3; vrel = sqrt(vrel); // shear history effects touch[jj] = 1; shear = &allshear[3*jj]; if (shearupdate) { shear[0] += vtr1*dt; shear[1] += vtr2*dt; shear[2] += vtr3*dt; } shrmag = sqrt(shear[0]*shear[0] + shear[1]*shear[1] + shear[2]*shear[2]); // rotate shear displacements rsht = shear[0]*delx + shear[1]*dely + shear[2]*delz; rsht *= rsqinv; if (shearupdate) { shear[0] -= rsht*delx; shear[1] -= rsht*dely; shear[2] -= rsht*delz; } // tangential forces = shear + tangential velocity damping fs1 = - (kt*shear[0] + meff*gammat*vtr1); fs2 = - (kt*shear[1] + meff*gammat*vtr2); fs3 = - (kt*shear[2] + meff*gammat*vtr3); // rescale frictional displacements and forces if needed fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); fn = xmu * fabs(ccel*r); if (fs > fn) { if (shrmag != 0.0) { shear[0] = (fn/fs) * (shear[0] + meff*gammat*vtr1/kt) - meff*gammat*vtr1/kt; shear[1] = (fn/fs) * (shear[1] + meff*gammat*vtr2/kt) - meff*gammat*vtr2/kt; shear[2] = (fn/fs) * (shear[2] + meff*gammat*vtr3/kt) - meff*gammat*vtr3/kt; fs1 *= fn/fs; fs2 *= fn/fs; fs3 *= fn/fs; } else fs1 = fs2 = fs3 = 0.0; } // forces & torques fx = delx*ccel + fs1; fy = dely*ccel + fs2; fz = delz*ccel + fs3; f[i][0] += fx; f[i][1] += fy; f[i][2] += fz; tor1 = rinv * (dely*fs3 - delz*fs2); tor2 = rinv * (delz*fs1 - delx*fs3); tor3 = rinv * (delx*fs2 - dely*fs1); torque[i][0] -= radi*tor1; torque[i][1] -= radi*tor2; torque[i][2] -= radi*tor3; if (newton_pair || j < nlocal) { f[j][0] -= fx; f[j][1] -= fy; f[j][2] -= fz; torque[j][0] -= radj*tor1; torque[j][1] -= radj*tor2; torque[j][2] -= radj*tor3; } if (evflag) ev_tally_xyz(i,j,nlocal,newton_pair, 0.0,0.0,fx,fy,fz,delx,dely,delz); } } } if (vflag_fdotr) virial_fdotr_compute(); } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairGranHookeHistory::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"); onerad_dynamic = new double[n+1]; onerad_frozen = new double[n+1]; maxrad_dynamic = new double[n+1]; maxrad_frozen = new double[n+1]; } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairGranHookeHistory::settings(int narg, char **arg) { if (narg != 6) error->all(FLERR,"Illegal pair_style command"); kn = force->numeric(FLERR,arg[0]); if (strcmp(arg[1],"NULL") == 0) kt = kn * 2.0/7.0; else kt = force->numeric(FLERR,arg[1]); gamman = force->numeric(FLERR,arg[2]); if (strcmp(arg[3],"NULL") == 0) gammat = 0.5 * gamman; else gammat = force->numeric(FLERR,arg[3]); xmu = force->numeric(FLERR,arg[4]); dampflag = force->inumeric(FLERR,arg[5]); if (dampflag == 0) gammat = 0.0; if (kn < 0.0 || kt < 0.0 || gamman < 0.0 || gammat < 0.0 || xmu < 0.0 || xmu > 10000.0 || dampflag < 0 || dampflag > 1) error->all(FLERR,"Illegal pair_style command"); } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairGranHookeHistory::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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,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++) { setflag[i][j] = 1; count++; } } if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairGranHookeHistory::init_style() { int i; // error and warning checks if (!atom->radius_flag || !atom->rmass_flag) error->all(FLERR,"Pair granular requires atom attributes radius, rmass"); if (comm->ghost_velocity == 0) error->all(FLERR,"Pair granular requires ghost atoms store velocity"); // need a granular neigh list and optionally a granular history neigh list int irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->gran = 1; if (history) { irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->granhistory = 1; neighbor->requests[irequest]->dnum = 3; } dt = update->dt; // if shear history is stored: // if first init, create Fix needed for storing shear history if (history && fix_history == NULL) { char dnumstr[16]; sprintf(dnumstr,"%d",3); char **fixarg = new char*[4]; fixarg[0] = (char *) "SHEAR_HISTORY"; fixarg[1] = (char *) "all"; fixarg[2] = (char *) "SHEAR_HISTORY"; fixarg[3] = dnumstr; modify->add_fix(4,fixarg,1); delete [] fixarg; fix_history = (FixShearHistory *) modify->fix[modify->nfix-1]; fix_history->pair = this; neighbor->requests[irequest]->fix_history = fix_history; } // check for FixFreeze and set freeze_group_bit for (i = 0; i < modify->nfix; i++) if (strcmp(modify->fix[i]->style,"freeze") == 0) break; if (i < modify->nfix) freeze_group_bit = modify->fix[i]->groupbit; else freeze_group_bit = 0; // check for FixRigid so can extract rigid body masses fix_rigid = NULL; for (i = 0; i < modify->nfix; i++) if (modify->fix[i]->rigid_flag) break; if (i < modify->nfix) fix_rigid = modify->fix[i]; // check for FixPour and FixDeposit so can extract particle radii int ipour; for (ipour = 0; ipour < modify->nfix; ipour++) if (strcmp(modify->fix[ipour]->style,"pour") == 0) break; if (ipour == modify->nfix) ipour = -1; int idep; for (idep = 0; idep < modify->nfix; idep++) if (strcmp(modify->fix[idep]->style,"deposit") == 0) break; if (idep == modify->nfix) idep = -1; // set maxrad_dynamic and maxrad_frozen for each type // include future FixPour and FixDeposit particles as dynamic int itype; for (i = 1; i <= atom->ntypes; i++) { onerad_dynamic[i] = onerad_frozen[i] = 0.0; if (ipour >= 0) { itype = i; onerad_dynamic[i] = *((double *) modify->fix[ipour]->extract("radius",itype)); } if (idep >= 0) { itype = i; onerad_dynamic[i] = *((double *) modify->fix[idep]->extract("radius",itype)); } } double *radius = atom->radius; int *mask = atom->mask; int *type = atom->type; int nlocal = atom->nlocal; for (i = 0; i < nlocal; i++) if (mask[i] & freeze_group_bit) onerad_frozen[type[i]] = MAX(onerad_frozen[type[i]],radius[i]); else onerad_dynamic[type[i]] = MAX(onerad_dynamic[type[i]],radius[i]); MPI_Allreduce(&onerad_dynamic[1],&maxrad_dynamic[1],atom->ntypes, MPI_DOUBLE,MPI_MAX,world); MPI_Allreduce(&onerad_frozen[1],&maxrad_frozen[1],atom->ntypes, MPI_DOUBLE,MPI_MAX,world); // set fix which stores history info if (history) { int ifix = modify->find_fix("SHEAR_HISTORY"); if (ifix < 0) error->all(FLERR,"Could not find pair fix ID"); fix_history = (FixShearHistory *) modify->fix[ifix]; } } /* ---------------------------------------------------------------------- neighbor callback to inform pair style of neighbor list to use optional granular history list ------------------------------------------------------------------------- */ void PairGranHookeHistory::init_list(int id, NeighList *ptr) { if (id == 0) list = ptr; else if (id == 1) listgranhistory = ptr; } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairGranHookeHistory::init_one(int i, int j) { if (!allocated) allocate(); // cutoff = sum of max I,J radii for // dynamic/dynamic & dynamic/frozen interactions, but not frozen/frozen double cutoff = maxrad_dynamic[i]+maxrad_dynamic[j]; cutoff = MAX(cutoff,maxrad_frozen[i]+maxrad_dynamic[j]); cutoff = MAX(cutoff,maxrad_dynamic[i]+maxrad_frozen[j]); return cutoff; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairGranHookeHistory::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); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairGranHookeHistory::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); } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairGranHookeHistory::write_restart_settings(FILE *fp) { fwrite(&kn,sizeof(double),1,fp); fwrite(&kt,sizeof(double),1,fp); fwrite(&gamman,sizeof(double),1,fp); fwrite(&gammat,sizeof(double),1,fp); fwrite(&xmu,sizeof(double),1,fp); fwrite(&dampflag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairGranHookeHistory::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&kn,sizeof(double),1,fp); fread(&kt,sizeof(double),1,fp); fread(&gamman,sizeof(double),1,fp); fread(&gammat,sizeof(double),1,fp); fread(&xmu,sizeof(double),1,fp); fread(&dampflag,sizeof(int),1,fp); } MPI_Bcast(&kn,1,MPI_DOUBLE,0,world); MPI_Bcast(&kt,1,MPI_DOUBLE,0,world); MPI_Bcast(&gamman,1,MPI_DOUBLE,0,world); MPI_Bcast(&gammat,1,MPI_DOUBLE,0,world); MPI_Bcast(&xmu,1,MPI_DOUBLE,0,world); MPI_Bcast(&dampflag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- */ void PairGranHookeHistory::reset_dt() { dt = update->dt; } /* ---------------------------------------------------------------------- */ double PairGranHookeHistory::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double radi,radj,radsum; double r,rinv,rsqinv,delx,dely,delz; double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3,wr1,wr2,wr3; double mi,mj,meff,damp,ccel; double vtr1,vtr2,vtr3,vrel,shrmag,rsht; double fs1,fs2,fs3,fs,fn; double *radius = atom->radius; radi = radius[i]; radj = radius[j]; radsum = radi + radj; if (rsq >= radsum*radsum) { fforce = 0.0; for (int m = 0; m < single_extra; m++) svector[m] = 0.0; return 0.0; } r = sqrt(rsq); rinv = 1.0/r; rsqinv = 1.0/rsq; // relative translational velocity double **v = atom->v; vr1 = v[i][0] - v[j][0]; vr2 = v[i][1] - v[j][1]; vr3 = v[i][2] - v[j][2]; // normal component double **x = atom->x; delx = x[i][0] - x[j][0]; dely = x[i][1] - x[j][1]; delz = x[i][2] - x[j][2]; vnnr = vr1*delx + vr2*dely + vr3*delz; vn1 = delx*vnnr * rsqinv; vn2 = dely*vnnr * rsqinv; vn3 = delz*vnnr * rsqinv; // tangential component vt1 = vr1 - vn1; vt2 = vr2 - vn2; vt3 = vr3 - vn3; // relative rotational velocity double **omega = atom->omega; wr1 = (radi*omega[i][0] + radj*omega[j][0]) * rinv; wr2 = (radi*omega[i][1] + radj*omega[j][1]) * rinv; wr3 = (radi*omega[i][2] + radj*omega[j][2]) * rinv; // meff = effective mass of pair of particles // if I or J part of rigid body, use body mass // if I or J is frozen, meff is other particle double *rmass = atom->rmass; int *mask = atom->mask; mi = rmass[i]; mj = rmass[j]; if (fix_rigid) { // NOTE: insure mass_rigid is current for owned+ghost atoms? if (mass_rigid[i] > 0.0) mi = mass_rigid[i]; if (mass_rigid[j] > 0.0) mj = mass_rigid[j]; } meff = mi*mj / (mi+mj); if (mask[i] & freeze_group_bit) meff = mj; if (mask[j] & freeze_group_bit) meff = mi; // normal forces = Hookian contact + normal velocity damping damp = meff*gamman*vnnr*rsqinv; ccel = kn*(radsum-r)*rinv - damp; // relative velocities vtr1 = vt1 - (delz*wr2-dely*wr3); vtr2 = vt2 - (delx*wr3-delz*wr1); vtr3 = vt3 - (dely*wr1-delx*wr2); vrel = vtr1*vtr1 + vtr2*vtr2 + vtr3*vtr3; vrel = sqrt(vrel); // shear history effects // neighprev = index of found neigh on previous call // search entire jnum list of neighbors of I for neighbor J // start from neighprev, since will typically be next neighbor // reset neighprev to 0 as necessary int jnum = list->numneigh[i]; int *jlist = list->firstneigh[i]; double *allshear = list->listgranhistory->firstdouble[i]; for (int jj = 0; jj < jnum; jj++) { neighprev++; if (neighprev >= jnum) neighprev = 0; if (jlist[neighprev] == j) break; } double *shear = &allshear[3*neighprev]; shrmag = sqrt(shear[0]*shear[0] + shear[1]*shear[1] + shear[2]*shear[2]); // rotate shear displacements rsht = shear[0]*delx + shear[1]*dely + shear[2]*delz; rsht *= rsqinv; // tangential forces = shear + tangential velocity damping fs1 = - (kt*shear[0] + meff*gammat*vtr1); fs2 = - (kt*shear[1] + meff*gammat*vtr2); fs3 = - (kt*shear[2] + meff*gammat*vtr3); // rescale frictional displacements and forces if needed fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); fn = xmu * fabs(ccel*r); if (fs > fn) { if (shrmag != 0.0) { fs1 *= fn/fs; fs2 *= fn/fs; fs3 *= fn/fs; fs *= fn/fs; } else fs1 = fs2 = fs3 = fs = 0.0; } // set force and return no energy fforce = ccel; // set single_extra quantities svector[0] = fs1; svector[1] = fs2; svector[2] = fs3; svector[3] = fs; svector[4] = vn1; svector[5] = vn2; svector[6] = vn3; svector[7] = vt1; svector[8] = vt2; svector[9] = vt3; return 0.0; } /* ---------------------------------------------------------------------- */ int PairGranHookeHistory::pack_forward_comm(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; m = 0; for (i = 0; i < n; i++) { j = list[i]; buf[m++] = mass_rigid[j]; } return m; } /* ---------------------------------------------------------------------- */ void PairGranHookeHistory::unpack_forward_comm(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) mass_rigid[i] = buf[m++]; } /* ---------------------------------------------------------------------- memory usage of local atom-based arrays ------------------------------------------------------------------------- */ double PairGranHookeHistory::memory_usage() { double bytes = nmax * sizeof(double); return bytes; } diff --git a/src/KIM/pair_kim.cpp b/src/KIM/pair_kim.cpp index 9140b73f3..b35e90511 100644 --- a/src/KIM/pair_kim.cpp +++ b/src/KIM/pair_kim.cpp @@ -1,1429 +1,1429 @@ /* ---------------------------------------------------------------------- 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: Ryan S. Elliott, Valeriu Smirichinski, Ellad Tadmor ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Designed for use with the openkim-api-v1.5.0 package and for use with the kim-api-v1.6.0 (and newer) package ------------------------------------------------------------------------- */ #include #include // includes from LAMMPS #include "pair_kim.h" #include "pair_kim_version.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 "memory.h" #include "domain.h" #include "error.h" // includes from KIM #include "KIM_API.h" #include "KIM_API_status.h" #ifndef KIM_API_VERSION_MAJOR // support v1.5.0 #define KIM_API_VERSION_MAJOR 1 #define KIM_API_VERSION_MINOR 5 #define KIM_API_VERSION_PATCH 0 #endif using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ PairKIM::PairKIM(LAMMPS *lmp) : Pair(lmp), settings_call_count(0), init_style_call_count(0), kim_modelname(0), lmps_map_species_to_unique(0), lmps_unique_elements(0), lmps_num_unique_elements(0), lmps_units(METAL), pkim(0), kim_ind_coordinates(-1), kim_ind_numberOfParticles(-1), kim_ind_numberContributingParticles(-1), kim_ind_numberOfSpecies(-1), kim_ind_particleSpecies(-1), kim_ind_get_neigh(-1), kim_ind_neighObject(-1), kim_ind_cutoff(-1), kim_ind_energy(-1), kim_ind_particleEnergy(-1), kim_ind_forces(-1), kim_ind_virial(-1), kim_ind_particleVirial(-1), kim_particle_codes(0), lmps_local_tot_num_atoms(0), kim_global_cutoff(0.0), lmps_maxalloc(0), kim_particleSpecies(0), lmps_force_tmp(0), lmps_stripped_neigh_list(0), kim_iterator_position(0), Rij(0) { // Initialize Pair data members to appropriate values single_enable = 0; // We do not provide the Single() function restartinfo = 0; // We do not write any restart info one_coeff = 1; // We only allow one coeff * * call // BEGIN: initial values that determine the KIM state // (used by kim_free(), etc.) kim_model_init_ok = false; kim_init_ok = false; // END return; } /* ---------------------------------------------------------------------- */ PairKIM::~PairKIM() { // clean up kim_modelname if (kim_modelname != 0) delete [] kim_modelname; // clean up lammps atom species number to unique particle names mapping if (lmps_unique_elements) for (int i = 0; i < lmps_num_unique_elements; i++) delete [] lmps_unique_elements[i]; delete [] lmps_unique_elements; // clean up local memory used to support KIM interface memory->destroy(kim_particleSpecies); memory->destroy(lmps_force_tmp); memory->destroy(lmps_stripped_neigh_list); // clean up allocated memory for standard Pair class usage // also, we allocate lmps_map_species_to_uniuqe in the allocate() function if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); delete [] lmps_map_species_to_unique; } // clean up Rij array memory->destroy(Rij); // clean up KIM interface (if necessary) kim_free(); return; } /* ---------------------------------------------------------------------- */ void PairKIM::compute(int eflag , int vflag) { int kimerror; if (eflag || vflag) ev_setup(eflag,vflag); else ev_unset(); // grow kim_particleSpecies array if necessary // needs to be atom->nmax in length if (atom->nmax > lmps_maxalloc) { memory->destroy(kim_particleSpecies); memory->destroy(lmps_force_tmp); lmps_maxalloc = atom->nmax; memory->create(kim_particleSpecies,lmps_maxalloc,"pair:kim_particleSpecies"); memory->create(lmps_force_tmp,lmps_maxalloc,3,"pair:lmps_force_tmp"); } // kim_particleSpecies = KIM atom species for each LAMMPS atom // set ielement to valid 0 if lmps_map_species_to_unique[] stores an un-used -1 int *species = atom->type; int nall = atom->nlocal + atom->nghost; int ielement; for (int i = 0; i < nall; i++) { ielement = lmps_map_species_to_unique[species[i]]; ielement = MAX(ielement,0); // @@ this (above line) provides bogus info // @@ (when lmps_map_species_to_unique[species[i]]==-1) to KIM, but // @@ I guess this only happens when lmps_hybrid==true, // @@ and we are sure that iterator mode will // @@ not use these atoms.... (?) kim_particleSpecies[i] = kim_particle_codes[ielement]; } // pass current atom pointers to KIM set_volatiles(); pkim->setm_compute_by_index(&kimerror,3*3, kim_ind_particleEnergy, eflag_atom, (int) kim_model_has_particleEnergy, kim_ind_particleVirial, vflag_atom, (int) kim_model_has_particleVirial, kim_ind_virial, vflag_global!=0, no_virial_fdotr_compute); kim_error(__LINE__,"setm_compute_by_index",kimerror); // compute via KIM model kimerror = pkim->model_compute(); kim_error(__LINE__,"PairKIM::pkim->model_compute() error",kimerror); // assemble force and particleVirial if needed if (!lmps_using_newton) comm->reverse_comm_pair(this); // sum lmps_force_tmp to f if running in hybrid mode if (lmps_hybrid) { double **f = atom->f; for (int i = 0; i < nall; i++) { f[i][0] += lmps_force_tmp[i][0]; f[i][1] += lmps_force_tmp[i][1]; f[i][2] += lmps_force_tmp[i][2]; } } if ((no_virial_fdotr_compute == 1) && (vflag_global)) { // flip sign and order of virial if KIM is computing it for (int i = 0; i < 3; ++i) virial[i] = -1.0*virial[i]; double tmp = virial[3]; virial[3] = -virial[5]; virial[4] = -virial[4]; virial[5] = -tmp; } else { // compute virial via LAMMPS fdotr mechanism if (vflag_fdotr) virial_fdotr_compute(); } if ((kim_model_has_particleVirial) && (vflag_atom)) { // flip sign and order of virial if KIM is computing it double tmp; for (int i = 0; i < nall; ++i) { for (int j = 0; j < 3; ++j) vatom[i][j] = -1.0*vatom[i][j]; tmp = vatom[i][3]; vatom[i][3] = -vatom[i][5]; vatom[i][4] = -vatom[i][4]; vatom[i][5] = -tmp; } } return; } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairKIM::allocate() { int n = atom->ntypes; // allocate standard Pair class arrays 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"); // allocate mapping array lmps_map_species_to_unique = new int[n+1]; allocated = 1; return; } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairKIM::settings(int narg, char **arg) { // This is called when "pair_style kim ..." is read from input // may be called multiple times ++settings_call_count; init_style_call_count = 0; if (narg < 2) error->all(FLERR,"Illegal pair_style command"); // arg[0] is the virial handling option: "LAMMPSvirial" or "KIMvirial" // arg[1] is the KIM Model name // arg[2] is the print-kim-file flag: 0/1 do-not/do print (default 0) // ensure we are in a clean state for KIM (needed on repeated call) // first time called will do nothing... kim_free(); // make sure things are allocated if (allocated != 1) allocate(); // clear setflag to ensure coeff() is called after settings() int n = atom->ntypes; for (int i = 1; i <= n; i++) for (int j = i; j <= n; j++) setflag[i][j] = 0; // set lmps_* bool flags set_lmps_flags(); // set virial handling if (strcmp(arg[0],"LAMMPSvirial") == 0) { no_virial_fdotr_compute = 0; } else if (strcmp(arg[0],"KIMvirial") == 0) { no_virial_fdotr_compute = 1; } else { error->all(FLERR,"Unrecognized virial argument in pair_style command"); } // set KIM Model name int nmlen = strlen(arg[1]); if (kim_modelname != 0) { delete [] kim_modelname; kim_modelname = 0; } kim_modelname = new char[nmlen+1]; strcpy(kim_modelname, arg[1]); // set print_kim_file if ((2 == narg) || ('0' == *(arg[2]))) { print_kim_file = false; } else { print_kim_file = true; } return; } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairKIM::coeff(int narg, char **arg) { // This is called when "pair_coeff ..." is read from input // may be called multiple times int i,j,n; if (!allocated) allocate(); if (narg != 2 + atom->ntypes) error->all(FLERR,"Incorrect args for pair coefficients"); int ilo,ihi,jlo,jhi; - force->bounds(arg[0],atom->ntypes,ilo,ihi); - force->bounds(arg[1],atom->ntypes,jlo,jhi); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); // read args that map atom species to KIM elements // lmps_map_species_to_unique[i] = // which element the Ith atom type is, -1 if NULL // lmps_num_unique_elements = # of unique elements // lmps_unique_elements = list of element names // if called multiple times: update lmps_unique_elements if (lmps_unique_elements) { for (i = 0; i < lmps_num_unique_elements; i++) delete [] lmps_unique_elements[i]; delete [] lmps_unique_elements; } lmps_unique_elements = new char*[atom->ntypes]; for (i = 0; i < atom->ntypes; i++) lmps_unique_elements[i] = 0; lmps_num_unique_elements = 0; for (i = 2; i < narg; i++) { if (strcmp(arg[i],"NULL") == 0) { if (!lmps_hybrid) error->all(FLERR,"Invalid args for non-hybrid pair coefficients"); lmps_map_species_to_unique[i-1] = -1; continue; } for (j = 0; j < lmps_num_unique_elements; j++) if (strcmp(arg[i],lmps_unique_elements[j]) == 0) break; lmps_map_species_to_unique[i-1] = j; if (j == lmps_num_unique_elements) { n = strlen(arg[i]) + 1; lmps_unique_elements[j] = new char[n]; strcpy(lmps_unique_elements[j],arg[i]); lmps_num_unique_elements++; } } int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { if (lmps_map_species_to_unique[i] >= 0 && lmps_map_species_to_unique[j] >= 0) { setflag[i][j] = 1; count++; } } } if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); return; } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairKIM::init_style() { // This is called for each "run ...", "minimize ...", etc. read from input ++init_style_call_count; if (domain->dimension != 3) error->all(FLERR,"PairKIM only works with 3D problems"); int kimerror; // KIM and Model initialization (only once) // also sets kim_ind_* and kim_* bool flags if (!kim_init_ok) { kim_init(); kimerror = pkim->model_init(); if (kimerror != KIM_STATUS_OK) kim_error(__LINE__, "KIM API:model_init() failed", kimerror); else { kim_model_init_ok = true; // allocate enough memory to ensure we are safe // (by using neighbor->oneatom) if (kim_model_using_Rij) memory->create(Rij,3*(neighbor->oneatom),"pair:Rij"); } } // request none, half, or full neighbor list // depending on KIM model requirement int irequest = neighbor->request(this,instance_me); if (kim_model_using_cluster) { neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->full = 0; } else { // make sure comm_reverse expects (at most) 9 values when newton is off if (!lmps_using_newton) comm_reverse_off = 9; if (kim_model_using_half) { neighbor->requests[irequest]->half = 1; neighbor->requests[irequest]->full = 0; // make sure half lists also include local-ghost pairs if (lmps_using_newton) neighbor->requests[irequest]->newton = 2; } else { neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->full = 1; // make sure full lists also include local-ghost pairs if (lmps_using_newton) neighbor->requests[irequest]->newton = 0; } } return; } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairKIM::init_one(int i, int j) { // This is called once of each (unordered) i,j pair for each // "run ...", "minimize ...", etc. read from input if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set"); return kim_global_cutoff; } /* ---------------------------------------------------------------------- */ void PairKIM::reinit() { // This is called by fix-adapt // Call parent class implementation Pair::reinit(); // Then reinit KIM model int kimerror; kimerror = pkim->model_reinit(); kim_error(__LINE__,"model_reinit unsuccessful", kimerror); } /* ---------------------------------------------------------------------- */ int PairKIM::pack_reverse_comm(int n, int first, double *buf) { int i,m,last; double *fp; if (lmps_hybrid) fp = &(lmps_force_tmp[0][0]); else fp = &(atom->f[0][0]); m = 0; last = first + n; if ((kim_model_has_forces) && ((vflag_atom == 0) || (!kim_model_has_particleVirial))) { for (i = first; i < last; i++) { buf[m++] = fp[3*i+0]; buf[m++] = fp[3*i+1]; buf[m++] = fp[3*i+2]; } return m; } else if ((kim_model_has_forces) && (vflag_atom == 1) && (kim_model_has_particleVirial)) { double *va=&(vatom[0][0]); for (i = first; i < last; i++) { buf[m++] = fp[3*i+0]; buf[m++] = fp[3*i+1]; buf[m++] = fp[3*i+2]; buf[m++] = va[6*i+0]; buf[m++] = va[6*i+1]; buf[m++] = va[6*i+2]; buf[m++] = va[6*i+3]; buf[m++] = va[6*i+4]; buf[m++] = va[6*i+5]; } return m; } else if ((!kim_model_has_forces) && (vflag_atom == 1) && (kim_model_has_particleVirial)) { double *va=&(vatom[0][0]); for (i = first; i < last; i++) { buf[m++] = va[6*i+0]; buf[m++] = va[6*i+1]; buf[m++] = va[6*i+2]; buf[m++] = va[6*i+3]; buf[m++] = va[6*i+4]; buf[m++] = va[6*i+5]; } return m; } else return 0; } /* ---------------------------------------------------------------------- */ void PairKIM::unpack_reverse_comm(int n, int *list, double *buf) { int i,j,m; double *fp; if (lmps_hybrid) fp = &(lmps_force_tmp[0][0]); else fp = &(atom->f[0][0]); m = 0; if ((kim_model_has_forces) && ((vflag_atom == 0) || (!kim_model_has_particleVirial))) { for (i = 0; i < n; i++) { j = list[i]; fp[3*j+0]+= buf[m++]; fp[3*j+1]+= buf[m++]; fp[3*j+2]+= buf[m++]; } } else if ((kim_model_has_forces) && (vflag_atom == 1) && (kim_model_has_particleVirial)) { double *va=&(vatom[0][0]); for (i = 0; i < n; i++) { j = list[i]; fp[3*j+0]+= buf[m++]; fp[3*j+1]+= buf[m++]; fp[3*j+2]+= buf[m++]; va[j*6+0]+=buf[m++]; va[j*6+1]+=buf[m++]; va[j*6+2]+=buf[m++]; va[j*6+3]+=buf[m++]; va[j*6+4]+=buf[m++]; va[j*6+5]+=buf[m++]; } } else if ((!kim_model_has_forces) && (vflag_atom == 1) && (kim_model_has_particleVirial)) { double *va=&(vatom[0][0]); for (i = 0; i < n; i++) { j = list[i]; va[j*6+0]+=buf[m++]; va[j*6+1]+=buf[m++]; va[j*6+2]+=buf[m++]; va[j*6+3]+=buf[m++]; va[j*6+4]+=buf[m++]; va[j*6+5]+=buf[m++]; } } else ;// do nothing return; } /* ---------------------------------------------------------------------- memory usage of local atom-based arrays ------------------------------------------------------------------------- */ double PairKIM::memory_usage() { double bytes = lmps_maxalloc * sizeof(int); return bytes; } /* ---------------------------------------------------------------------- KIM-specific interface ------------------------------------------------------------------------- */ void PairKIM::kim_error(int ln, const char* msg, int errcode) { if (errcode == KIM_STATUS_OK) return; KIM_API_model::report_error(ln,(char *) __FILE__, (char *) msg,errcode); error->all(__FILE__,ln,"Internal KIM error"); return; } /* ---------------------------------------------------------------------- */ int PairKIM::get_neigh(void **kimmdl,int *mode,int *request, int *atom, int *numnei, int **nei1atom, double **pRij) { KIM_API_model *pkim = (KIM_API_model *) *kimmdl; int kimerror; PairKIM *self = (PairKIM *) pkim->get_sim_buffer(&kimerror); if (self->kim_model_using_Rij) { *pRij = &(self->Rij[0]); } else { *pRij = 0; } // subvert KIM api by using direct access to self->list // // get neighObj from KIM API obj // NeighList * neiobj = (NeighList * ) // (*pkim).get_data_by_index(self->kim_ind_neighObject, &kimerror); NeighList * neiobj = self->list; // subvert KIM api by using direct acces to self->lmps_local_tot_num_atoms // //int * pnAtoms = (int *) // (*pkim).get_data_by_index(self->kim_ind_numberOfParticles, &kimerror); //int nAtoms = *pnAtoms; int nAtoms = self->lmps_local_tot_num_atoms; int j, jj, inum, *ilist, *numneigh, **firstneigh; inum = neiobj->inum; //# of I atoms neighbors are stored for ilist = neiobj->ilist; //local indices of I atoms numneigh = neiobj->numneigh; // # of J neighbors for each I atom firstneigh = neiobj->firstneigh; // ptr to 1st J int value of each I atom if (*mode==0){ //iterator mode if (*request==1) { //increment iterator if (self->kim_iterator_position < inum) { *atom = ilist[self->kim_iterator_position]; *numnei = numneigh[*atom]; // strip off neighbor mask for molecular systems if (!self->lmps_using_molecular) *nei1atom = firstneigh[*atom]; else { int n = *numnei; int *ptr = firstneigh[*atom]; int *lmps_stripped_neigh_list = self->lmps_stripped_neigh_list; for (int i = 0; i < n; i++) lmps_stripped_neigh_list[i] = *(ptr++) & NEIGHMASK; *nei1atom = lmps_stripped_neigh_list; } // set Rij if needed if (self->kim_model_using_Rij) { double* x = (double *) (*pkim).get_data_by_index(self->kim_ind_coordinates, &kimerror); for (jj=0; jj < *numnei; jj++) { int i = *atom; j = (*nei1atom)[jj]; self->Rij[jj*3 +0] = -x[i*3+0] + x[j*3+0]; self->Rij[jj*3 +1] = -x[i*3+1] + x[j*3+1]; self->Rij[jj*3 +2] = -x[i*3+2] + x[j*3+2]; } } // increment iterator self->kim_iterator_position++; return KIM_STATUS_OK; //successful increment } else if (self->kim_iterator_position == inum) { *numnei = 0; return KIM_STATUS_NEIGH_ITER_PAST_END; //reached end by iterator } else if (self->kim_iterator_position > inum || inum < 0){ self->error->one(FLERR, "KIM neighbor iterator exceeded range"); } } else if (*request == 0){ //restart iterator self->kim_iterator_position = 0; *numnei = 0; return KIM_STATUS_NEIGH_ITER_INIT_OK; //succsesful restart } } else if (*mode == 1){//locator mode //... if (*request < inum) { *atom = *request; *numnei = numneigh[*atom]; // strip off neighbor mask for molecular systems if (!self->lmps_using_molecular) *nei1atom = firstneigh[*atom]; else { int n = *numnei; int *ptr = firstneigh[*atom]; int *lmps_stripped_neigh_list = self->lmps_stripped_neigh_list; for (int i = 0; i < n; i++) lmps_stripped_neigh_list[i] = *(ptr++) & NEIGHMASK; *nei1atom = lmps_stripped_neigh_list; } // set Rij if needed if (self->kim_model_using_Rij){ double* x = (double *) (*pkim).get_data_by_index(self->kim_ind_coordinates, &kimerror); for(int jj=0; jj < *numnei; jj++){ int i = *atom; int j = (*nei1atom)[jj]; self->Rij[jj*3 +0] = -x[i*3+0] + x[j*3+0]; self->Rij[jj*3 +1] = -x[i*3+1] + x[j*3+1]; self->Rij[jj*3 +2] = -x[i*3+2] + x[j*3+2]; } } return KIM_STATUS_OK; //successful end } else if (*request >= nAtoms || inum < 0) return KIM_STATUS_NEIGH_INVALID_REQUEST; else if (*request >= inum) { *atom = *request; *numnei = 0; return KIM_STATUS_OK; //successfull but no neighbors in the list } } else return KIM_STATUS_NEIGH_INVALID_MODE; //invalid mode return -16; //should not get here: unspecified error } /* ---------------------------------------------------------------------- */ void PairKIM::kim_free() { int kimerror; if (kim_model_init_ok) { kimerror = pkim->model_destroy(); kim_model_init_ok = false; } if (kim_init_ok) { pkim->free(&kimerror); kim_init_ok = false; } if (pkim != 0) { delete pkim; pkim = 0; } if (kim_particle_codes_ok) { delete [] kim_particle_codes; kim_particle_codes = 0; kim_particle_codes_ok = false; } return; } /* ---------------------------------------------------------------------- */ void PairKIM::kim_init() { int kimerror; // // determine KIM Model capabilities (used in this function below) set_kim_model_has_flags(); // create appropriate KIM descriptor file char* test_descriptor_string = 0; // allocate memory for test_descriptor_string and write descriptor file write_descriptor(&test_descriptor_string); // print descriptor if (print_kim_file) { error->message(FLERR, test_descriptor_string); } // initialize KIM model pkim = new KIM_API_model(); kimerror = pkim->string_init(test_descriptor_string, kim_modelname); if (kimerror != KIM_STATUS_OK) kim_error(__LINE__,"KIM initialization failed", kimerror); else { kim_init_ok = true; delete [] test_descriptor_string; test_descriptor_string = 0; } // determine kim_model_using_* true/false values // // check for half or full list kim_model_using_half = (pkim->is_half_neighbors(&kimerror)); // const char* NBC_method; kimerror = pkim->get_NBC_method(&NBC_method); kim_error(__LINE__,"NBC method not set",kimerror); // check for CLUSTER mode kim_model_using_cluster = (strcmp(NBC_method,"CLUSTER")==0); // check if Rij needed for get_neigh kim_model_using_Rij = ((strcmp(NBC_method,"NEIGH_RVEC_H")==0) || (strcmp(NBC_method,"NEIGH_RVEC_F")==0)); // get correct index of each variable in kim_api object pkim->getm_index(&kimerror, 3*13, "coordinates", &kim_ind_coordinates, 1, "cutoff", &kim_ind_cutoff, 1, "numberOfParticles", &kim_ind_numberOfParticles, 1, #if KIM_API_VERSION_MAJOR == 1 && KIM_API_VERSON_MINOR == 5 "numberParticleTypes", &kim_ind_numberOfSpecies, 1, "particleTypes", &kim_ind_particleSpecies, 1, #else "numberOfSpecies", &kim_ind_numberOfSpecies, 1, "particleSpecies", &kim_ind_particleSpecies, 1, #endif "numberContributingParticles", &kim_ind_numberContributingParticles, kim_model_using_half, "particleEnergy", &kim_ind_particleEnergy, (int) kim_model_has_particleEnergy, "energy", &kim_ind_energy, (int) kim_model_has_energy, "forces", &kim_ind_forces, (int) kim_model_has_forces, "neighObject", &kim_ind_neighObject, (int) !kim_model_using_cluster, "get_neigh", &kim_ind_get_neigh, (int) !kim_model_using_cluster, "particleVirial", &kim_ind_particleVirial, (int) kim_model_has_particleVirial, "virial", &kim_ind_virial, no_virial_fdotr_compute); kim_error(__LINE__,"getm_index",kimerror); // setup mapping between LAMMPS unique elements and KIM species codes kim_particle_codes = new int[lmps_num_unique_elements]; kim_particle_codes_ok = true; for(int i = 0; i < lmps_num_unique_elements; i++){ int kimerror; kim_particle_codes[i] = pkim->get_species_code(lmps_unique_elements[i], &kimerror); kim_error(__LINE__, "create_kim_particle_codes: symbol not found ", kimerror); } // set pointer values in KIM API object that will not change during run set_statics(); return; } /* ---------------------------------------------------------------------- */ void PairKIM::set_statics() { // set total number of atoms lmps_local_tot_num_atoms = (int) (atom->nghost + atom->nlocal); int kimerror; pkim->setm_data_by_index(&kimerror, 4*6, kim_ind_numberOfSpecies, 1, (void *) &(atom->ntypes), 1, kim_ind_cutoff, 1, (void *) &(kim_global_cutoff), 1, kim_ind_numberOfParticles, 1, (void *) &lmps_local_tot_num_atoms, 1, kim_ind_numberContributingParticles, 1, (void *) &(atom->nlocal), (int) kim_model_using_half, kim_ind_energy, 1, (void *) &(eng_vdwl), (int) kim_model_has_energy, kim_ind_virial, 1, (void *) &(virial[0]), no_virial_fdotr_compute); kim_error(__LINE__, "setm_data_by_index", kimerror); if (!kim_model_using_cluster) { kimerror = pkim->set_method_by_index(kim_ind_get_neigh, 1, (func_ptr) &get_neigh); kim_error(__LINE__, "set_method_by_index", kimerror); } pkim->set_sim_buffer((void *)this, &kimerror); kim_error(__LINE__, "set_sim_buffer", kimerror); return; } /* ---------------------------------------------------------------------- */ void PairKIM::set_volatiles() { int kimerror; lmps_local_tot_num_atoms = (int) (atom->nghost + atom->nlocal); intptr_t nall = (intptr_t) lmps_local_tot_num_atoms; pkim->setm_data_by_index(&kimerror, 4*2, kim_ind_coordinates, 3*nall, (void*) &(atom->x[0][0]), 1, kim_ind_particleSpecies, nall, (void*) kim_particleSpecies, 1); kim_error(__LINE__, "setm_data_by_index", kimerror); if (kim_model_has_particleEnergy && (eflag_atom == 1)) { kimerror = pkim->set_data_by_index(kim_ind_particleEnergy, nall, (void*) eatom); kim_error(__LINE__, "set_data_by_index", kimerror); } if (kim_model_has_particleVirial && (vflag_atom == 1)) { kimerror = pkim->set_data_by_index(kim_ind_particleVirial, 6*nall, (void*) &(vatom[0][0])); kim_error(__LINE__, "set_data_by_index", kimerror); } if (kim_model_has_forces) { if (lmps_hybrid) kimerror = pkim->set_data_by_index(kim_ind_forces, nall*3, (void*) &(lmps_force_tmp[0][0])); else kimerror = pkim->set_data_by_index(kim_ind_forces, nall*3, (void*) &(atom->f[0][0])); kim_error(__LINE__, "setm_data_by_index", kimerror); } // subvert the KIM api by direct access to this->list in get_neigh // //if (!kim_model_using_cluster) // kimerror = pkim->set_data_by_index(kim_ind_neighObject, 1, // (void*) this->list); if (kim_model_has_particleVirial) { if(vflag_atom != 1) { pkim->set_compute_by_index(kim_ind_particleVirial, KIM_COMPUTE_FALSE, &kimerror); } else { pkim->set_compute_by_index(kim_ind_particleVirial, KIM_COMPUTE_TRUE, &kimerror); } } if (no_virial_fdotr_compute == 1) { pkim->set_compute_by_index(kim_ind_virial, ((vflag_global != 1) ? KIM_COMPUTE_FALSE : KIM_COMPUTE_TRUE), &kimerror); } return; } /* ---------------------------------------------------------------------- */ void PairKIM::set_lmps_flags() { // determint if newton is on or off lmps_using_newton = (force->newton_pair == 1); // setup lmps_stripped_neigh_list for neighbors of one atom, if needed lmps_using_molecular = (atom->molecular > 0); if (lmps_using_molecular) { memory->destroy(lmps_stripped_neigh_list); memory->create(lmps_stripped_neigh_list,neighbor->oneatom, "pair:lmps_stripped_neigh_list"); } // determine if running with pair hybrid lmps_hybrid = (force->pair_match("hybrid",0)); // support cluster mode if everything is just right lmps_support_cluster = ((domain->xperiodic == 0 && domain->yperiodic == 0 && domain->zperiodic == 0 ) && (comm->nprocs == 1) ); // determine unit system and set lmps_units flag if ((strcmp(update->unit_style,"real")==0)) lmps_units = REAL; else if ((strcmp(update->unit_style,"metal")==0)) lmps_units = METAL; else if ((strcmp(update->unit_style,"si")==0)) lmps_units = SI; else if ((strcmp(update->unit_style,"cgs")==0)) lmps_units = CGS; else if ((strcmp(update->unit_style,"electron")==0)) lmps_units = ELECTRON; else if ((strcmp(update->unit_style,"lj")==0)) error->all(FLERR,"LAMMPS unit_style lj not supported by KIM models"); else error->all(FLERR,"Unknown unit_style"); return; } /* ---------------------------------------------------------------------- */ void PairKIM::set_kim_model_has_flags() { KIM_API_model mdl; int kimerror; // get KIM API object representing the KIM Model only kimerror = mdl.model_info(kim_modelname); kim_error(__LINE__,"KIM initialization failed", kimerror); // determine if the KIM Model can compute the total energy mdl.get_index((char*) "energy", &kimerror); kim_model_has_energy = (kimerror == KIM_STATUS_OK); if (!kim_model_has_energy) error->warning(FLERR,"KIM Model does not provide `energy'; " "Potential energy will be zero"); // determine if the KIM Model can compute the forces mdl.get_index((char*) "forces", &kimerror); kim_model_has_forces = (kimerror == KIM_STATUS_OK); if (!kim_model_has_forces) error->warning(FLERR,"KIM Model does not provide `forces'; " "Forces will be zero"); // determine if the KIM Model can compute the particleEnergy mdl.get_index((char*) "particleEnergy", &kimerror); kim_model_has_particleEnergy = (kimerror == KIM_STATUS_OK); if (!kim_model_has_particleEnergy) error->warning(FLERR,"KIM Model does not provide `particleEnergy'; " "energy per atom will be zero"); // determine if the KIM Model can compute the particleVerial mdl.get_index((char*) "particleVirial", &kimerror); kim_model_has_particleVirial = (kimerror == KIM_STATUS_OK); mdl.get_index((char*) "process_dEdr", &kimerror); kim_model_has_particleVirial = kim_model_has_particleVirial || (kimerror == KIM_STATUS_OK); if (!kim_model_has_particleVirial) error->warning(FLERR,"KIM Model does not provide `particleVirial'; " "virial per atom will be zero"); // tear down KIM API object mdl.free(&kimerror); // now destructor will do the remaining tear down for mdl return; } /* ---------------------------------------------------------------------- */ void PairKIM::write_descriptor(char** test_descriptor_string) { // allocate memory if (*test_descriptor_string != 0) error->all(FLERR, "Test_descriptor_string already allocated"); // assuming 75 lines at 100 characters each (should be plenty) *test_descriptor_string = new char[100*75]; // initialize strcpy(*test_descriptor_string, ""); // Write Test name and units strcat(*test_descriptor_string, "#\n" "# BEGINNING OF KIM DESCRIPTOR FILE\n" "#\n" "# This file is automatically generated from LAMMPS pair_style " "kim command\n"); char tmp_version[100]; sprintf(tmp_version,"# This is pair-kim-v%i.%i.%i", PAIR_KIM_VERSION_MAJOR, PAIR_KIM_VERSION_MINOR, PAIR_KIM_VERSION_PATCH); strcat(*test_descriptor_string, tmp_version); #ifdef PAIR_KIM_VERSION_PRERELEASE sprintf(tmp_version,"-%s", PAIR_KIM_VERSION_PRERELEASE); strcat(*test_descriptor_string, tmp_version); #endif #ifdef PAIR_KIM_VERSION_BUILD_METADATA sprintf(tmp_version,"+%s", PAIR_KIM_VERSION_BUILD_METADATA); #endif strcat(*test_descriptor_string, "\n" "# The call number is (pair_style).(init_style): "); char tmp_num[100]; sprintf(tmp_num, "%i.%i\n", settings_call_count, init_style_call_count); strcat(*test_descriptor_string, tmp_num); strcat(*test_descriptor_string, "#\n" "\n" #if KIM_API_VERSION_MAJOR == 1 && KIM_API_VERSION_MINOR == 5 #else "KIM_API_Version := 1.6.0\n\n" #endif "# Base units\n"); switch (lmps_units) { case REAL: strcat(*test_descriptor_string, "Unit_length := A\n" "Unit_energy := kcal/mol\n" "Unit_charge := e\n" "Unit_temperature := K\n" "Unit_time := fs\n\n"); break; case METAL: strcat(*test_descriptor_string, "Unit_length := A\n" "Unit_energy := eV\n" "Unit_charge := e\n" "Unit_temperature := K\n" "Unit_time := ps\n\n"); break; case SI: strcat(*test_descriptor_string, "Unit_length := m\n" "Unit_energy := J\n" "Unit_charge := C\n" "Unit_temperature := K\n" "Unit_time := s\n\n"); break; case CGS: strcat(*test_descriptor_string, "Unit_length := cm\n" "Unit_energy := erg\n" "Unit_charge := statC\n" "Unit_temperature := K\n" "Unit_time := s\n\n"); break; case ELECTRON: strcat(*test_descriptor_string, "Unit_length := Bohr\n" "Unit_energy := Hartree\n" "Unit_charge := e\n" "Unit_temperature := K\n" "Unit_time := fs\n\n"); break; } // Write Supported species section strcat(*test_descriptor_string, "\n" #if KIM_API_VERSION_MAJOR == 1 && KIM_API_VERSON_MINOR == 5 "SUPPORTED_ATOM/PARTICLES_TYPES:\n" #else "PARTICLE_SPECIES:\n" #endif "# Symbol/name Type code\n"); int code=1; char* tmp_line = 0; tmp_line = new char[100]; for (int i=0; i < lmps_num_unique_elements; i++){ sprintf(tmp_line, "%-24s%-16s%-3i\n", lmps_unique_elements[i], "spec", code++); strcat(*test_descriptor_string, tmp_line); } delete [] tmp_line; tmp_line = 0; strcat(*test_descriptor_string, "\n"); // Write conventions section strcat(*test_descriptor_string, "\n" "CONVENTIONS:\n" "# Name Type\n" "ZeroBasedLists flag\n"); // can use iterator or locator neighbor mode, unless in hybrid mode if (lmps_hybrid) strcat(*test_descriptor_string, "Neigh_IterAccess flag\n"); else strcat(*test_descriptor_string, "Neigh_BothAccess flag\n\n"); strcat(*test_descriptor_string, "NEIGH_PURE_H flag\n" "NEIGH_PURE_F flag\n" "NEIGH_RVEC_H flag\n" "NEIGH_RVEC_F flag\n"); // @@ add code for MI_OPBC_? support ???? if (lmps_support_cluster) { strcat(*test_descriptor_string, "CLUSTER flag\n\n"); } else { strcat(*test_descriptor_string, "\n"); } // Write input section strcat(*test_descriptor_string, "\n" "MODEL_INPUT:\n" "# Name Type Unit Shape\n" "numberOfParticles integer none []\n" "numberContributingParticles integer none []\n" #if KIM_API_VERSION_MAJOR == 1 && KIM_API_VERSON_MINOR == 5 "numberParticleTypes integer none []\n" "particleTypes integer none " #else "numberOfSpecies integer none []\n" "particleSpecies integer none " #endif "[numberOfParticles]\n" "coordinates double length " "[numberOfParticles,3]\n" "neighObject pointer none []\n" "get_neigh method none []\n"); // Write output section strcat(*test_descriptor_string, "\n" "MODEL_OUPUT:\n" "# Name Type Unit Shape\n" "compute method none []\n" "destroy method none []\n" "cutoff double length []\n"); if (!kim_model_has_energy) strcat(*test_descriptor_string,"# "); strcat(*test_descriptor_string, "energy double energy []\n"); if (!kim_model_has_forces) strcat(*test_descriptor_string, "# "); strcat(*test_descriptor_string, "forces double force " "[numberOfParticles,3]\n"); if (!kim_model_has_particleEnergy) strcat(*test_descriptor_string, "# "); strcat(*test_descriptor_string, "particleEnergy double energy " "[numberOfParticles]\n"); if (no_virial_fdotr_compute != 1) strcat(*test_descriptor_string, "# "); strcat(*test_descriptor_string, "virial double energy [6]\n"); if (!kim_model_has_particleVirial) strcat(*test_descriptor_string, "# "); strcat(*test_descriptor_string, "particleVirial double energy " "[numberOfParticles,6]\n" "\n"); strcat(*test_descriptor_string, "#\n" "# END OF KIM DESCRIPTOR FILE\n" "#\n"); return; } void *PairKIM::extract(const char *str, int &dim) { void *paramData; int kimerror=0; int ier; int dummyint; int isIndexed = 0; int maxLine = 1024; int rank; int validParam = 0; int numParams; int *speciesIndex = new int[maxLine]; char *paramStr = new char[maxLine]; char *paramName; char *indexStr; char message[maxLine]; int offset; double* paramPtr; // set dim to 0, we will always deal with scalars to circumvent lammps species // indexing dim = 0; // copy the input str into paramStr for parsing strcpy(paramStr, str); // get the name of the parameter (whatever is before ":") paramName = strtok(paramStr, ":"); if (0 == strcmp(paramName, str)) paramName = (char*) str; else isIndexed = 1; // parse the rest of the string into tokens deliminated by "," and convert // them to integers, saving them into speciesIndex int count = -1; if (isIndexed == 1) { while((indexStr = strtok(NULL, ",")) != NULL) { count++; ier = sscanf(indexStr, "%d", &speciesIndex[count]); if (ier != 1) { ier = -1; break; } } } if (ier == -1) { delete [] speciesIndex, speciesIndex = 0; delete [] paramStr, paramStr = 0; kim_error(__LINE__,"error in PairKIM::extract(), invalid parameter-indicie format", KIM_STATUS_FAIL); } // check to make sure that the requested parameter is a valid free parameter kimerror = pkim->get_num_params(&numParams, &dummyint); kim_error(__LINE__, "get_num_free_params", kimerror); char **freeParamNames = new char*[numParams]; for (int k = 0; k < numParams; k++) { kimerror = pkim->get_free_parameter(k, (const char**) &freeParamNames[k]); kim_error(__LINE__, "get_free_parameter", kimerror); if (0 == strcmp(paramName, freeParamNames[k])) { validParam = 1; break; } } delete [] freeParamNames, freeParamNames = 0; if (validParam == 0) { sprintf(message, "Invalid parameter to adapt: \"%s\" is not a FREE_PARAM", paramName); delete [] speciesIndex, speciesIndex = 0; delete [] paramStr, paramStr = 0; kim_error(__LINE__, message, KIM_STATUS_FAIL); } // get the parameter arry from pkim object paramData = pkim->get_data(paramName, &kimerror); if (kimerror == KIM_STATUS_FAIL) { delete [] speciesIndex, speciesIndex = 0; delete [] paramStr, paramStr = 0; } kim_error(__LINE__,"get_data",kimerror); // get rank and shape of parameter rank = (*pkim).get_rank(paramName, &kimerror); if (kimerror == KIM_STATUS_FAIL) { delete [] speciesIndex, speciesIndex = 0; delete [] paramStr, paramStr = 0; } kim_error(__LINE__,"get_rank",kimerror); int *shape = new int[maxLine]; dummyint = (*pkim).get_shape(paramName, shape, &kimerror); if (kimerror == KIM_STATUS_FAIL) { delete [] speciesIndex, speciesIndex = 0; delete [] paramStr, paramStr = 0; delete [] shape, shape = 0; } kim_error(__LINE__,"get_shape",kimerror); delete [] paramStr, paramStr = 0; // check that number of inputs is rank, and that input indicies are less than // their respective dimensions in shape if ((count+1) != rank) { sprintf(message, "Number of input indicies not equal to rank of specified parameter (%d)", rank); kimerror = KIM_STATUS_FAIL; delete [] speciesIndex, speciesIndex = 0; delete [] shape, shape = 0; kim_error(__LINE__,message, kimerror); } if (isIndexed == 1) { for (int i=0; i <= count; i++) { if (shape[i] <= speciesIndex[i] || speciesIndex[i] < 0) { kimerror = KIM_STATUS_FAIL; break; } } } delete [] shape, shape = 0; if (kimerror == KIM_STATUS_FAIL) { sprintf(message, "One or more parameter indicies out of bounds"); delete [] speciesIndex, speciesIndex = 0; kim_error(__LINE__, message, kimerror); } // Cast it to a double paramPtr = static_cast(paramData); // If it is indexed (not just a scalar for the whole model), then get pointer // corresponding to specified indicies by calculating the adress offset using // specified indicies and the shape if (isIndexed == 1) { offset = 0; for (int i = 0; i < (rank-1); i++) { offset = (offset + speciesIndex[i]) * shape[i+1]; } offset = offset + speciesIndex[(rank - 1)]; paramPtr = (paramPtr + offset); } delete [] speciesIndex, speciesIndex = 0; return ((void*) paramPtr); } diff --git a/src/KOKKOS/pair_table_kokkos.cpp b/src/KOKKOS/pair_table_kokkos.cpp index fec6512a3..278c5b0a2 100644 --- a/src/KOKKOS/pair_table_kokkos.cpp +++ b/src/KOKKOS/pair_table_kokkos.cpp @@ -1,1384 +1,1384 @@ /* ---------------------------------------------------------------------- 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 #include #include #include #include "pair_table_kokkos.h" #include "kokkos.h" #include "atom.h" #include "force.h" #include "comm.h" #include "neighbor.h" #include "neigh_list.h" #include "neigh_request.h" #include "memory.h" #include "error.h" #include "atom_masks.h" using namespace LAMMPS_NS; enum{NONE,RLINEAR,RSQ,BMP}; enum{FULL,HALFTHREAD,HALF}; #define MAXLINE 1024 /* ---------------------------------------------------------------------- */ template PairTableKokkos::PairTableKokkos(LAMMPS *lmp) : Pair(lmp) { update_table = 0; atomKK = (AtomKokkos *) atom; ntables = 0; tables = NULL; execution_space = ExecutionSpaceFromDevice::space; datamask_read = X_MASK | F_MASK | TYPE_MASK | ENERGY_MASK | VIRIAL_MASK; datamask_modify = F_MASK | ENERGY_MASK | VIRIAL_MASK; h_table = new TableHost(); d_table = new TableDevice(); } /* ---------------------------------------------------------------------- */ template PairTableKokkos::~PairTableKokkos() { /* 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); }*/ delete h_table; delete d_table; } /* ---------------------------------------------------------------------- */ template void PairTableKokkos::compute(int eflag_in, int vflag_in) { if(update_table) create_kokkos_tables(); if(tabstyle == LOOKUP) compute_style(eflag_in,vflag_in); if(tabstyle == LINEAR) compute_style(eflag_in,vflag_in); if(tabstyle == SPLINE) compute_style(eflag_in,vflag_in); if(tabstyle == BITMAP) compute_style(eflag_in,vflag_in); } template template void PairTableKokkos::compute_style(int eflag_in, int vflag_in) { eflag = eflag_in; vflag = vflag_in; if (neighflag == FULL || neighflag == FULLCLUSTER) no_virial_fdotr_compute = 1; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; atomKK->sync(execution_space,datamask_read); //k_cutsq.template sync(); //k_params.template sync(); if (eflag || vflag) atomKK->modified(execution_space,datamask_modify); else atomKK->modified(execution_space,F_MASK); x = c_x = atomKK->k_x.view(); f = atomKK->k_f.view(); type = atomKK->k_type.view(); nlocal = atom->nlocal; nall = atom->nlocal + atom->nghost; special_lj[0] = force->special_lj[0]; special_lj[1] = force->special_lj[1]; special_lj[2] = force->special_lj[2]; special_lj[3] = force->special_lj[3]; newton_pair = force->newton_pair; d_cutsq = d_table->cutsq; // loop over neighbors of my atoms EV_FLOAT ev; if(atom->ntypes > MAX_TYPES_STACKPARAMS) { if (neighflag == FULL) { PairComputeFunctor,FULL,false,S_TableCompute > ff(this,(NeighListKokkos*) list); if (eflag || vflag) Kokkos::parallel_reduce(list->inum,ff,ev); else Kokkos::parallel_for(list->inum,ff); } else if (neighflag == HALFTHREAD) { PairComputeFunctor,HALFTHREAD,false,S_TableCompute > ff(this,(NeighListKokkos*) list); if (eflag || vflag) Kokkos::parallel_reduce(list->inum,ff,ev); else Kokkos::parallel_for(list->inum,ff); } else if (neighflag == HALF) { PairComputeFunctor,HALF,false,S_TableCompute > f(this,(NeighListKokkos*) list); if (eflag || vflag) Kokkos::parallel_reduce(list->inum,f,ev); else Kokkos::parallel_for(list->inum,f); } else if (neighflag == N2) { PairComputeFunctor,N2,false,S_TableCompute > f(this,(NeighListKokkos*) list); if (eflag || vflag) Kokkos::parallel_reduce(nlocal,f,ev); else Kokkos::parallel_for(nlocal,f); } else if (neighflag == FULLCLUSTER) { typedef PairComputeFunctor,FULLCLUSTER,false,S_TableCompute > f_type; f_type f(this,(NeighListKokkos*) list); #ifdef KOKKOS_HAVE_CUDA const int teamsize = Kokkos::Impl::is_same::value ? 32 : 1; #else const int teamsize = 1; #endif const int nteams = (list->inum*+teamsize-1)/teamsize; Kokkos::TeamPolicy config(nteams,teamsize,NeighClusterSize); if (eflag || vflag) Kokkos::parallel_reduce(config,f,ev); else Kokkos::parallel_for(config,f); } } else { if (neighflag == FULL) { PairComputeFunctor,FULL,true,S_TableCompute > f(this,(NeighListKokkos*) list); if (eflag || vflag) Kokkos::parallel_reduce(list->inum,f,ev); else Kokkos::parallel_for(list->inum,f); } else if (neighflag == HALFTHREAD) { PairComputeFunctor,HALFTHREAD,true,S_TableCompute > f(this,(NeighListKokkos*) list); if (eflag || vflag) Kokkos::parallel_reduce(list->inum,f,ev); else Kokkos::parallel_for(list->inum,f); } else if (neighflag == HALF) { PairComputeFunctor,HALF,true,S_TableCompute > f(this,(NeighListKokkos*) list); if (eflag || vflag) Kokkos::parallel_reduce(list->inum,f,ev); else Kokkos::parallel_for(list->inum,f); } else if (neighflag == N2) { PairComputeFunctor,N2,true,S_TableCompute > f(this,(NeighListKokkos*) list); if (eflag || vflag) Kokkos::parallel_reduce(nlocal,f,ev); else Kokkos::parallel_for(nlocal,f); } else if (neighflag == FULLCLUSTER) { typedef PairComputeFunctor,FULLCLUSTER,true,S_TableCompute > f_type; f_type f(this,(NeighListKokkos*) list); #ifdef KOKKOS_HAVE_CUDA const int teamsize = Kokkos::Impl::is_same::value ? 32 : 1; #else const int teamsize = 1; #endif const int nteams = (list->inum*+teamsize-1)/teamsize; Kokkos::TeamPolicy config(nteams,teamsize,NeighClusterSize); if (eflag || vflag) Kokkos::parallel_reduce(config,f,ev); else Kokkos::parallel_for(config,f); } } if (eflag) eng_vdwl += ev.evdwl; if (vflag_global) { virial[0] += ev.v[0]; virial[1] += ev.v[1]; virial[2] += ev.v[2]; virial[3] += ev.v[3]; virial[4] += ev.v[4]; virial[5] += ev.v[5]; } if (vflag_fdotr) pair_virial_fdotr_compute(this); } template template KOKKOS_INLINE_FUNCTION F_FLOAT PairTableKokkos:: compute_fpair(const F_FLOAT& rsq, const int& i, const int&j, const int& itype, const int& jtype) const { (void) i; (void) j; union_int_float_t rsq_lookup; double fpair; const int tidx = d_table_const.tabindex(itype,jtype); //const Table* const tb = &tables[tabindex[itype][jtype]]; //if (rsq < d_table_const.innersq(tidx)) // error->one(FLERR,"Pair distance < table inner cutoff"); if (Specialisation::TabStyle == LOOKUP) { const int itable = static_cast ((rsq - d_table_const.innersq(tidx)) * d_table_const.invdelta(tidx)); //if (itable >= tlm1) // error->one(FLERR,"Pair distance > table outer cutoff"); fpair = d_table_const.f(tidx,itable); } else if (Specialisation::TabStyle == LINEAR) { const int itable = static_cast ((rsq - d_table_const.innersq(tidx)) * d_table_const.invdelta(tidx)); //if (itable >= tlm1) // error->one(FLERR,"Pair distance > table outer cutoff"); const double fraction = (rsq - d_table_const.rsq(tidx,itable)) * d_table_const.invdelta(tidx); fpair = d_table_const.f(tidx,itable) + fraction*d_table_const.df(tidx,itable); } else if (Specialisation::TabStyle == SPLINE) { const int itable = static_cast ((rsq - d_table_const.innersq(tidx)) * d_table_const.invdelta(tidx)); //if (itable >= tlm1) // error->one(FLERR,"Pair distance > table outer cutoff"); const double b = (rsq - d_table_const.rsq(tidx,itable)) * d_table_const.invdelta(tidx); const double a = 1.0 - b; fpair = a * d_table_const.f(tidx,itable) + b * d_table_const.f(tidx,itable+1) + ((a*a*a-a)*d_table_const.f2(tidx,itable) + (b*b*b-b)*d_table_const.f2(tidx,itable+1)) * d_table_const.deltasq6(tidx); } else { rsq_lookup.f = rsq; int itable = rsq_lookup.i & d_table_const.nmask(tidx); itable >>= d_table_const.nshiftbits(tidx); const double fraction = (rsq_lookup.f - d_table_const.rsq(tidx,itable)) * d_table_const.drsq(tidx,itable); fpair = d_table_const.f(tidx,itable) + fraction*d_table_const.df(tidx,itable); } return fpair; } template template KOKKOS_INLINE_FUNCTION F_FLOAT PairTableKokkos:: compute_evdwl(const F_FLOAT& rsq, const int& i, const int&j, const int& itype, const int& jtype) const { (void) i; (void) j; double evdwl; union_int_float_t rsq_lookup; const int tidx = d_table_const.tabindex(itype,jtype); //const Table* const tb = &tables[tabindex[itype][jtype]]; //if (rsq < d_table_const.innersq(tidx)) // error->one(FLERR,"Pair distance < table inner cutoff"); if (Specialisation::TabStyle == LOOKUP) { const int itable = static_cast ((rsq - d_table_const.innersq(tidx)) * d_table_const.invdelta(tidx)); //if (itable >= tlm1) // error->one(FLERR,"Pair distance > table outer cutoff"); evdwl = d_table_const.e(tidx,itable); } else if (Specialisation::TabStyle == LINEAR) { const int itable = static_cast ((rsq - d_table_const.innersq(tidx)) * d_table_const.invdelta(tidx)); //if (itable >= tlm1) // error->one(FLERR,"Pair distance > table outer cutoff"); const double fraction = (rsq - d_table_const.rsq(tidx,itable)) * d_table_const.invdelta(tidx); evdwl = d_table_const.e(tidx,itable) + fraction*d_table_const.de(tidx,itable); } else if (Specialisation::TabStyle == SPLINE) { const int itable = static_cast ((rsq - d_table_const.innersq(tidx)) * d_table_const.invdelta(tidx)); //if (itable >= tlm1) // error->one(FLERR,"Pair distance > table outer cutoff"); const double b = (rsq - d_table_const.rsq(tidx,itable)) * d_table_const.invdelta(tidx); const double a = 1.0 - b; evdwl = a * d_table_const.e(tidx,itable) + b * d_table_const.e(tidx,itable+1) + ((a*a*a-a)*d_table_const.e2(tidx,itable) + (b*b*b-b)*d_table_const.e2(tidx,itable+1)) * d_table_const.deltasq6(tidx); } else { rsq_lookup.f = rsq; int itable = rsq_lookup.i & d_table_const.nmask(tidx); itable >>= d_table_const.nshiftbits(tidx); const double fraction = (rsq_lookup.f - d_table_const.rsq(tidx,itable)) * d_table_const.drsq(tidx,itable); evdwl = d_table_const.e(tidx,itable) + fraction*d_table_const.de(tidx,itable); } return evdwl; } template void PairTableKokkos::create_kokkos_tables() { const int tlm1 = tablength-1; memory->create_kokkos(d_table->nshiftbits,h_table->nshiftbits,ntables,"Table::nshiftbits"); memory->create_kokkos(d_table->nmask,h_table->nmask,ntables,"Table::nmask"); memory->create_kokkos(d_table->innersq,h_table->innersq,ntables,"Table::innersq"); memory->create_kokkos(d_table->invdelta,h_table->invdelta,ntables,"Table::invdelta"); memory->create_kokkos(d_table->deltasq6,h_table->deltasq6,ntables,"Table::deltasq6"); if(tabstyle == LOOKUP) { memory->create_kokkos(d_table->e,h_table->e,ntables,tlm1,"Table::e"); memory->create_kokkos(d_table->f,h_table->f,ntables,tlm1,"Table::f"); } if(tabstyle == LINEAR) { memory->create_kokkos(d_table->rsq,h_table->rsq,ntables,tablength,"Table::rsq"); memory->create_kokkos(d_table->e,h_table->e,ntables,tablength,"Table::e"); memory->create_kokkos(d_table->f,h_table->f,ntables,tablength,"Table::f"); memory->create_kokkos(d_table->de,h_table->de,ntables,tlm1,"Table::de"); memory->create_kokkos(d_table->df,h_table->df,ntables,tlm1,"Table::df"); } if(tabstyle == SPLINE) { memory->create_kokkos(d_table->rsq,h_table->rsq,ntables,tablength,"Table::rsq"); memory->create_kokkos(d_table->e,h_table->e,ntables,tablength,"Table::e"); memory->create_kokkos(d_table->f,h_table->f,ntables,tablength,"Table::f"); memory->create_kokkos(d_table->e2,h_table->e2,ntables,tablength,"Table::e2"); memory->create_kokkos(d_table->f2,h_table->f2,ntables,tablength,"Table::f2"); } if(tabstyle == BITMAP) { int ntable = 1 << tablength; memory->create_kokkos(d_table->rsq,h_table->rsq,ntables,ntable,"Table::rsq"); memory->create_kokkos(d_table->e,h_table->e,ntables,ntable,"Table::e"); memory->create_kokkos(d_table->f,h_table->f,ntables,ntable,"Table::f"); memory->create_kokkos(d_table->de,h_table->de,ntables,ntable,"Table::de"); memory->create_kokkos(d_table->df,h_table->df,ntables,ntable,"Table::df"); memory->create_kokkos(d_table->drsq,h_table->drsq,ntables,ntable,"Table::drsq"); } for(int i=0; i < ntables; i++) { Table* tb = &tables[i]; h_table->nshiftbits[i] = tb->nshiftbits; h_table->nmask[i] = tb->nmask; h_table->innersq[i] = tb->innersq; h_table->invdelta[i] = tb->invdelta; h_table->deltasq6[i] = tb->deltasq6; for(int j = 0; jrsq.dimension_1(); j++) h_table->rsq(i,j) = tb->rsq[j]; for(int j = 0; jdrsq.dimension_1(); j++) h_table->drsq(i,j) = tb->drsq[j]; for(int j = 0; je.dimension_1(); j++) h_table->e(i,j) = tb->e[j]; for(int j = 0; jde.dimension_1(); j++) h_table->de(i,j) = tb->de[j]; for(int j = 0; jf.dimension_1(); j++) h_table->f(i,j) = tb->f[j]; for(int j = 0; jdf.dimension_1(); j++) h_table->df(i,j) = tb->df[j]; for(int j = 0; je2.dimension_1(); j++) h_table->e2(i,j) = tb->e2[j]; for(int j = 0; jf2.dimension_1(); j++) h_table->f2(i,j) = tb->f2[j]; } Kokkos::deep_copy(d_table->nshiftbits,h_table->nshiftbits); Kokkos::deep_copy(d_table->nmask,h_table->nmask); Kokkos::deep_copy(d_table->innersq,h_table->innersq); Kokkos::deep_copy(d_table->invdelta,h_table->invdelta); Kokkos::deep_copy(d_table->deltasq6,h_table->deltasq6); Kokkos::deep_copy(d_table->rsq,h_table->rsq); Kokkos::deep_copy(d_table->drsq,h_table->drsq); Kokkos::deep_copy(d_table->e,h_table->e); Kokkos::deep_copy(d_table->de,h_table->de); Kokkos::deep_copy(d_table->f,h_table->f); Kokkos::deep_copy(d_table->df,h_table->df); Kokkos::deep_copy(d_table->e2,h_table->e2); Kokkos::deep_copy(d_table->f2,h_table->f2); Kokkos::deep_copy(d_table->tabindex,h_table->tabindex); d_table_const.nshiftbits = d_table->nshiftbits; d_table_const.nmask = d_table->nmask; d_table_const.innersq = d_table->innersq; d_table_const.invdelta = d_table->invdelta; d_table_const.deltasq6 = d_table->deltasq6; d_table_const.rsq = d_table->rsq; d_table_const.drsq = d_table->drsq; d_table_const.e = d_table->e; d_table_const.de = d_table->de; d_table_const.f = d_table->f; d_table_const.df = d_table->df; d_table_const.e2 = d_table->e2; d_table_const.f2 = d_table->f2; Kokkos::deep_copy(d_table->cutsq,h_table->cutsq); update_table = 0; } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ template void PairTableKokkos::allocate() { allocated = 1; const int nt = atom->ntypes + 1; memory->create(setflag,nt,nt,"pair:setflag"); memory->create_kokkos(d_table->cutsq,h_table->cutsq,cutsq,nt,nt,"pair:cutsq"); memory->create_kokkos(d_table->tabindex,h_table->tabindex,tabindex,nt,nt,"pair:tabindex"); d_table_const.cutsq = d_table->cutsq; d_table_const.tabindex = d_table->tabindex; memset(&setflag[0][0],0,nt*nt*sizeof(int)); memset(&cutsq[0][0],0,nt*nt*sizeof(double)); memset(&tabindex[0][0],0,nt*nt*sizeof(int)); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ template void PairTableKokkos::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(FLERR,arg[1]); if (tablength < 2) error->all(FLERR,"Illegal number of pair table entries"); // optional keywords // assert the tabulation is compatible with a specific long-range solver int iarg = 2; while (iarg < narg) { if (strcmp(arg[iarg],"ewald") == 0) ewaldflag = 1; else if (strcmp(arg[iarg],"pppm") == 0) pppmflag = 1; else if (strcmp(arg[iarg],"msm") == 0) msmflag = 1; else if (strcmp(arg[iarg],"dispersion") == 0) dispersionflag = 1; else if (strcmp(arg[iarg],"tip4p") == 0) tip4pflag = 1; else error->all(FLERR,"Illegal pair_style command"); iarg++; } // 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); d_table_const.tabindex = d_table->tabindex = typename ArrayTypes::t_int_2d(); h_table->tabindex = typename ArrayTypes::t_int_2d(); d_table_const.cutsq = d_table->cutsq = typename ArrayTypes::t_ffloat_2d(); h_table->cutsq = typename ArrayTypes::t_ffloat_2d(); } allocated = 0; ntables = 0; tables = NULL; } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ template void PairTableKokkos::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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,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(FLERR,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 ------------------------------------------------------------------------- */ template double PairTableKokkos::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]; if(i void PairTableKokkos::read_table(Table *tb, char *file, char *keyword) { char line[MAXLINE]; // open file FILE *fp = force->open_potential(file); 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 char *word = strtok(line," \t\n\r"); if (strcmp(word,keyword) == 0) 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 == RLINEAR) 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 ------------------------------------------------------------------------- */ template void PairTableKokkos::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 ------------------------------------------------------------------------- */ template void PairTableKokkos::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 ------------------------------------------------------------------------- */ template void PairTableKokkos::param_extract(Table *tb, char *line) { tb->ninput = 0; tb->rflag = NONE; 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 = RLINEAR; 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 { 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 ------------------------------------------------------------------------- */ template void PairTableKokkos::compute_table(Table *tb) { update_table = 1; 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 = dh/dg at inner and at cut // h(r) = e(r) and g(r) = r^2 // dh/dg = (de/dr) / 2r = -f/2r double ep0 = - tb->f[0] / (2.0 * sqrt(tb->innersq)); double epn = - tb->f[tlm1] / (2.0 * tb->cut); 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 ------------------------------------------------------------------------- */ template void PairTableKokkos::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 ------------------------------------------------------------------------- */ template void PairTableKokkos::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 ------------------------------------------------------------------------- */ template void PairTableKokkos::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; } /* ---------------------------------------------------------------------- */ template double PairTableKokkos::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 ------------------------------------------------------------------------- */ template void PairTableKokkos::write_restart(FILE *fp) { write_restart_settings(fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ template void PairTableKokkos::read_restart(FILE *fp) { read_restart_settings(fp); allocate(); } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ template void PairTableKokkos::write_restart_settings(FILE *fp) { fwrite(&tabstyle,sizeof(int),1,fp); fwrite(&tablength,sizeof(int),1,fp); fwrite(&ewaldflag,sizeof(int),1,fp); fwrite(&pppmflag,sizeof(int),1,fp); fwrite(&msmflag,sizeof(int),1,fp); fwrite(&dispersionflag,sizeof(int),1,fp); fwrite(&tip4pflag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ template void PairTableKokkos::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&tabstyle,sizeof(int),1,fp); fread(&tablength,sizeof(int),1,fp); fread(&ewaldflag,sizeof(int),1,fp); fread(&pppmflag,sizeof(int),1,fp); fread(&msmflag,sizeof(int),1,fp); fread(&dispersionflag,sizeof(int),1,fp); fread(&tip4pflag,sizeof(int),1,fp); } MPI_Bcast(&tabstyle,1,MPI_INT,0,world); MPI_Bcast(&tablength,1,MPI_INT,0,world); MPI_Bcast(&ewaldflag,1,MPI_INT,0,world); MPI_Bcast(&pppmflag,1,MPI_INT,0,world); MPI_Bcast(&msmflag,1,MPI_INT,0,world); MPI_Bcast(&dispersionflag,1,MPI_INT,0,world); MPI_Bcast(&tip4pflag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- */ template double PairTableKokkos::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 ------------------------------------------------------------------------- */ template void *PairTableKokkos::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"); dim = 0; return &tables[0].cut; } template void PairTableKokkos::init_style() { neighbor->request(this,instance_me); neighflag = lmp->kokkos->neighflag; int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> kokkos_host = Kokkos::Impl::is_same::value && !Kokkos::Impl::is_same::value; neighbor->requests[irequest]-> kokkos_device = Kokkos::Impl::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->full_cluster = 0; } else if (neighflag == HALF || neighflag == HALFTHREAD) { neighbor->requests[irequest]->full = 0; neighbor->requests[irequest]->half = 1; neighbor->requests[irequest]->full_cluster = 0; } else if (neighflag == N2) { neighbor->requests[irequest]->full = 0; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->full_cluster = 0; } else if (neighflag == FULLCLUSTER) { neighbor->requests[irequest]->full_cluster = 1; neighbor->requests[irequest]->full = 1; neighbor->requests[irequest]->half = 0; } else { error->all(FLERR,"Cannot use chosen neighbor list style with lj/cut/kk"); } } /* template template KOKKOS_INLINE_FUNCTION void PairTableKokkos:: ev_tally(EV_FLOAT &ev, const int &i, const int &j, const F_FLOAT &fpair, const F_FLOAT &delx, const F_FLOAT &dely, const F_FLOAT &delz) const { const int EFLAG = eflag; const int NEWTON_PAIR = newton_pair; const int VFLAG = vflag_either; if (EFLAG) { if (eflag_atom) { E_FLOAT epairhalf = 0.5 * (ev.evdwl + ev.ecoul); if (NEWTON_PAIR || i < nlocal) eatom[i] += epairhalf; if (NEWTON_PAIR || j < nlocal) eatom[j] += epairhalf; } } if (VFLAG) { const E_FLOAT v0 = delx*delx*fpair; const E_FLOAT v1 = dely*dely*fpair; const E_FLOAT v2 = delz*delz*fpair; const E_FLOAT v3 = delx*dely*fpair; const E_FLOAT v4 = delx*delz*fpair; const E_FLOAT v5 = dely*delz*fpair; if (vflag_global) { if (NEIGHFLAG) { if (NEWTON_PAIR) { ev.v[0] += v0; ev.v[1] += v1; ev.v[2] += v2; ev.v[3] += v3; ev.v[4] += v4; ev.v[5] += v5; } else { if (i < nlocal) { ev.v[0] += 0.5*v0; ev.v[1] += 0.5*v1; ev.v[2] += 0.5*v2; ev.v[3] += 0.5*v3; ev.v[4] += 0.5*v4; ev.v[5] += 0.5*v5; } if (j < nlocal) { ev.v[0] += 0.5*v0; ev.v[1] += 0.5*v1; ev.v[2] += 0.5*v2; ev.v[3] += 0.5*v3; ev.v[4] += 0.5*v4; ev.v[5] += 0.5*v5; } } } else { ev.v[0] += 0.5*v0; ev.v[1] += 0.5*v1; ev.v[2] += 0.5*v2; ev.v[3] += 0.5*v3; ev.v[4] += 0.5*v4; ev.v[5] += 0.5*v5; } } if (vflag_atom) { if (NEWTON_PAIR || i < nlocal) { d_vatom(i,0) += 0.5*v0; d_vatom(i,1) += 0.5*v1; d_vatom(i,2) += 0.5*v2; d_vatom(i,3) += 0.5*v3; d_vatom(i,4) += 0.5*v4; d_vatom(i,5) += 0.5*v5; } if (NEWTON_PAIR || (NEIGHFLAG && j < nlocal)) { d_vatom(j,0) += 0.5*v0; d_vatom(j,1) += 0.5*v1; d_vatom(j,2) += 0.5*v2; d_vatom(j,3) += 0.5*v3; d_vatom(j,4) += 0.5*v4; d_vatom(j,5) += 0.5*v5; } } } } */ template void PairTableKokkos::cleanup_copy() { // WHY needed: this prevents parent copy from deallocating any arrays allocated = 0; cutsq = NULL; eatom = NULL; vatom = NULL; h_table=NULL; d_table=NULL; } namespace LAMMPS_NS { template class PairTableKokkos; #ifdef KOKKOS_HAVE_CUDA template class PairTableKokkos; #endif } diff --git a/src/KSPACE/pair_born_coul_long.cpp b/src/KSPACE/pair_born_coul_long.cpp index 15bcd1081..14d43f4c6 100644 --- a/src/KSPACE/pair_born_coul_long.cpp +++ b/src/KSPACE/pair_born_coul_long.cpp @@ -1,582 +1,582 @@ /* ---------------------------------------------------------------------- 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 #include #include #include #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) { ewaldflag = pppmflag = 1; ftable = NULL; writedata = 1; } /* ---------------------------------------------------------------------- */ 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); } if (ftable) free_tables(); } /* ---------------------------------------------------------------------- */ void PairBornCoulLong::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itable,itype,jtype; double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair; double fraction,table; 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; 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]) { r = sqrt(rsq); 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) { 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 = 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(FLERR,arg[0]); if (narg == 1) cut_coul = cut_lj_global; else cut_coul = force->numeric(FLERR,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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double a_one = force->numeric(FLERR,arg[2]); double rho_one = force->numeric(FLERR,arg[3]); double sigma_one = force->numeric(FLERR,arg[4]); if (rho_one <= 0) error->all(FLERR,"Incorrect args for pair coefficients"); double c_one = force->numeric(FLERR,arg[5]); double d_one = force->numeric(FLERR,arg[6]); double cut_lj_one = cut_lj_global; if (narg == 8) cut_lj_one = force->numeric(FLERR,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((sigma[i][j]-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 requires a KSpace style"); g_ewald = force->kspace->g_ewald; neighbor->request(this,instance_me); // setup force tables if (ncoultablebits) init_tables(cut_coul,NULL); } /* ---------------------------------------------------------------------- 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); fwrite(&tail_flag,sizeof(int),1,fp); fwrite(&ncoultablebits,sizeof(int),1,fp); fwrite(&tabinner,sizeof(double),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); fread(&tail_flag,sizeof(int),1,fp); fread(&ncoultablebits,sizeof(int),1,fp); fread(&tabinner,sizeof(double),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); MPI_Bcast(&tail_flag,1,MPI_INT,0,world); MPI_Bcast(&ncoultablebits,1,MPI_INT,0,world); MPI_Bcast(&tabinner,1,MPI_DOUBLE,0,world); } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void PairBornCoulLong::write_data(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) fprintf(fp,"%d %g %g %g %g %g\n",i, a[i][i],rho[i][i],sigma[i][i],c[i][i],d[i][i]); } /* ---------------------------------------------------------------------- proc 0 writes all pairs to data file ------------------------------------------------------------------------- */ void PairBornCoulLong::write_data_all(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) fprintf(fp,"%d %d %g %g %g %g %g %g\n",i,j, a[i][j],rho[i][j],sigma[i][j],c[i][j],d[i][j],cut_lj[i][j]); } /* ---------------------------------------------------------------------- */ 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 fraction,table,forcecoul,forceborn,phicoul,phiborn; 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[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) { 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]) { 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(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.cpp b/src/KSPACE/pair_buck_coul_long.cpp index 683e5bf00..9cd8485e5 100644 --- a/src/KSPACE/pair_buck_coul_long.cpp +++ b/src/KSPACE/pair_buck_coul_long.cpp @@ -1,553 +1,553 @@ /* ---------------------------------------------------------------------- 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 #include #include #include #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) { ewaldflag = pppmflag = 1; writedata = 1; ftable = NULL; } /* ---------------------------------------------------------------------- */ PairBuckCoulLong::~PairBuckCoulLong() { if (!copymode) { 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); } if (ftable) free_tables(); } } /* ---------------------------------------------------------------------- */ void PairBuckCoulLong::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itable,itype,jtype; double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair; double fraction,table; 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; 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]) { r = sqrt(rsq); 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) { 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 = 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(FLERR,arg[0]); if (narg == 1) cut_coul = cut_lj_global; else cut_coul = force->numeric(FLERR,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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double a_one = force->numeric(FLERR,arg[2]); double rho_one = force->numeric(FLERR,arg[3]); if (rho_one <= 0) error->all(FLERR,"Incorrect args for pair coefficients"); double c_one = force->numeric(FLERR,arg[4]); double cut_lj_one = cut_lj_global; if (narg == 6) cut_lj_one = force->numeric(FLERR,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 requires a KSpace style"); g_ewald = force->kspace->g_ewald; neighbor->request(this,instance_me); // setup force tables if (ncoultablebits) init_tables(cut_coul,NULL); } /* ---------------------------------------------------------------------- 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); fwrite(&tail_flag,sizeof(int),1,fp); fwrite(&ncoultablebits,sizeof(int),1,fp); fwrite(&tabinner,sizeof(double),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); fread(&tail_flag,sizeof(int),1,fp); fread(&ncoultablebits,sizeof(int),1,fp); fread(&tabinner,sizeof(double),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); MPI_Bcast(&tail_flag,1,MPI_INT,0,world); MPI_Bcast(&ncoultablebits,1,MPI_INT,0,world); MPI_Bcast(&tabinner,1,MPI_DOUBLE,0,world); } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void PairBuckCoulLong::write_data(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) fprintf(fp,"%d %g %g %g\n",i,a[i][i],rho[i][i],c[i][i]); } /* ---------------------------------------------------------------------- proc 0 writes all pairs to data file ------------------------------------------------------------------------- */ void PairBuckCoulLong::write_data_all(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) fprintf(fp,"%d %d %g %g %g %g\n",i,j, a[i][j],rho[i][j],c[i][j],cut_lj[i][j]); } /* ---------------------------------------------------------------------- */ 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 fraction,table,forcecoul,forcebuck,phicoul,phibuck; 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[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) { 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]) { phibuck = a[itype][jtype]*rexp - c[itype][jtype]*r6inv - offset[itype][jtype]; eng += factor_lj*phibuck; } return eng; } /* ---------------------------------------------------------------------- */ 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_long_coul_long.cpp b/src/KSPACE/pair_buck_long_coul_long.cpp index 52d250fbe..7b42bb47d 100644 --- a/src/KSPACE/pair_buck_long_coul_long.cpp +++ b/src/KSPACE/pair_buck_long_coul_long.cpp @@ -1,1053 +1,1053 @@ /* ---------------------------------------------------------------------- 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: Pieter J. in 't Veld (SNL) ------------------------------------------------------------------------- */ #include #include #include #include #include "math_vector.h" #include "pair_buck_long_coul_long.h" #include "atom.h" #include "comm.h" #include "neighbor.h" #include "neigh_list.h" #include "neigh_request.h" #include "force.h" #include "kspace.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 /* ---------------------------------------------------------------------- */ PairBuckLongCoulLong::PairBuckLongCoulLong(LAMMPS *lmp) : Pair(lmp) { dispersionflag = ewaldflag = pppmflag = 1; respa_enable = 1; writedata = 1; ftable = NULL; fdisptable = NULL; } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairBuckLongCoulLong::options(char **arg, int order) { const char *option[] = {"long", "cut", "off", NULL}; int i; if (!*arg) error->all(FLERR,"Illegal pair_style buck/long/coul/long command"); for (i=0; option[i]&&strcmp(arg[0], option[i]); ++i); switch (i) { default: error->all(FLERR,"Illegal pair_style buck/long/coul/long command"); case 0: ewald_order |= 1<all(FLERR,"Illegal pair_style command"); ewald_order = 0; ewald_off = 0; options(arg,6); options(++arg,1); if (!comm->me && ewald_order == ((1<<1) | (1<<6))) error->warning(FLERR,"Using largest cutoff for buck/long/coul/long"); if (!*(++arg)) error->all(FLERR,"Cutoffs missing in pair_style buck/long/coul/long"); if (ewald_off & (1<<6)) error->all(FLERR,"LJ6 off not supported in pair_style buck/long/coul/long"); if (!((ewald_order^ewald_off) & (1<<1))) error->all(FLERR, "Coulomb cut not supported in pair_style buck/long/coul/coul"); cut_buck_global = force->numeric(FLERR,*(arg++)); if (narg == 4 && ((ewald_order & 0x42) == 0x42)) error->all(FLERR,"Only one cutoff allowed when requesting all long"); if (narg == 4) cut_coul = force->numeric(FLERR,*arg); else cut_coul = cut_buck_global; 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_buck[i][j] = cut_buck_global; } } /* ---------------------------------------------------------------------- free all arrays ------------------------------------------------------------------------- */ PairBuckLongCoulLong::~PairBuckLongCoulLong() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut_buck_read); memory->destroy(cut_buck); memory->destroy(cut_bucksq); memory->destroy(buck_a_read); memory->destroy(buck_a); memory->destroy(buck_c_read); memory->destroy(buck_c); memory->destroy(buck_rho_read); memory->destroy(buck_rho); memory->destroy(buck1); memory->destroy(buck2); memory->destroy(rhoinv); memory->destroy(offset); } if (ftable) free_tables(); } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairBuckLongCoulLong::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_buck_read,n+1,n+1,"pair:cut_buck_read"); memory->create(cut_buck,n+1,n+1,"pair:cut_buck"); memory->create(cut_bucksq,n+1,n+1,"pair:cut_bucksq"); memory->create(buck_a_read,n+1,n+1,"pair:buck_a_read"); memory->create(buck_a,n+1,n+1,"pair:buck_a"); memory->create(buck_c_read,n+1,n+1,"pair:buck_c_read"); memory->create(buck_c,n+1,n+1,"pair:buck_c"); memory->create(buck_rho_read,n+1,n+1,"pair:buck_rho_read"); memory->create(buck_rho,n+1,n+1,"pair:buck_rho"); memory->create(buck1,n+1,n+1,"pair:buck1"); memory->create(buck2,n+1,n+1,"pair:buck2"); memory->create(rhoinv,n+1,n+1,"pair:rhoinv"); memory->create(offset,n+1,n+1,"pair:offset"); } /* ---------------------------------------------------------------------- extract protected data from object ------------------------------------------------------------------------- */ void *PairBuckLongCoulLong::extract(const char *id, int &dim) { const char *ids[] = { "B", "ewald_order", "ewald_cut", "ewald_mix", "cut_coul", "cut_LJ", NULL}; void *ptrs[] = { buck_c, &ewald_order, &cut_coul, &mix_flag, &cut_coul, &cut_buck_global, NULL}; int i; for (i=0; ids[i]&&strcmp(ids[i], id); ++i); if (i == 0) dim = 2; else dim = 0; return ptrs[i]; } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairBuckLongCoulLong::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++),atom->ntypes,ilo,ihi); - force->bounds(*(arg++),atom->ntypes,jlo,jhi); + force->bounds(FLERR,*(arg++),atom->ntypes,ilo,ihi); + force->bounds(FLERR,*(arg++),atom->ntypes,jlo,jhi); double buck_a_one = force->numeric(FLERR,*(arg++)); double buck_rho_one = force->numeric(FLERR,*(arg++)); double buck_c_one = force->numeric(FLERR,*(arg++)); double cut_buck_one = cut_buck_global; if (narg == 6) cut_buck_one = force->numeric(FLERR,*(arg++)); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { buck_a_read[i][j] = buck_a_one; buck_c_read[i][j] = buck_c_one; buck_rho_read[i][j] = buck_rho_one; cut_buck_read[i][j] = cut_buck_one; setflag[i][j] = 1; count++; } } if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairBuckLongCoulLong::init_style() { // require an atom style with charge defined if (!atom->q_flag && (ewald_order&(1<<1))) error->all(FLERR,"Pair style buck/long/coul/long requires atom attribute q"); // request regular or rRESPA neighbor lists if neighrequest_flag != 0 if (force->kspace->neighrequest_flag) { 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,instance_me); else if (respa == 1) { irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respainner = 1; irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 3; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respaouter = 1; } else { irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respainner = 1; irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 2; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respamiddle = 1; irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 3; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respaouter = 1; } } else irequest = neighbor->request(this,instance_me); } 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; // ensure use of KSpace long-range solver, set two g_ewalds if (force->kspace == NULL) error->all(FLERR,"Pair style requires a KSpace style"); if (ewald_order&(1<<1)) g_ewald = force->kspace->g_ewald; if (ewald_order&(1<<6)) g_ewald_6 = force->kspace->g_ewald_6; // setup force tables if (ncoultablebits) init_tables(cut_coul,cut_respa); if (ndisptablebits) init_tables_disp(cut_buck_global); } /* ---------------------------------------------------------------------- neighbor callback to inform pair style of neighbor list to use regular or rRESPA ------------------------------------------------------------------------- */ void PairBuckLongCoulLong::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 PairBuckLongCoulLong::init_one(int i, int j) { if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set"); if (ewald_order&(1<<6)) cut_buck[i][j] = cut_buck_global; else cut_buck[i][j] = cut_buck_read[i][j]; buck_a[i][j] = buck_a_read[i][j]; buck_c[i][j] = buck_c_read[i][j]; buck_rho[i][j] = buck_rho_read[i][j]; double cut = MAX(cut_buck[i][j],cut_coul); cutsq[i][j] = cut*cut; cut_bucksq[i][j] = cut_buck[i][j] * cut_buck[i][j]; buck1[i][j] = buck_a[i][j]/buck_rho[i][j]; buck2[i][j] = 6.0*buck_c[i][j]; rhoinv[i][j] = 1.0/buck_rho[i][j]; // check interior rRESPA cutoff if (cut_respa && MIN(cut_buck[i][j],cut_coul) < cut_respa[3]) error->all(FLERR,"Pair cutoff < Respa interior cutoff"); if (offset_flag) { double rexp = exp(-cut_buck[i][j]/buck_rho[i][j]); offset[i][j] = buck_a[i][j]*rexp - buck_c[i][j]/pow(cut_buck[i][j],6.0); } else offset[i][j] = 0.0; cutsq[j][i] = cutsq[i][j]; cut_bucksq[j][i] = cut_bucksq[i][j]; buck_a[j][i] = buck_a[i][j]; buck_c[j][i] = buck_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]; return cut; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairBuckLongCoulLong::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(&buck_a_read[i][j],sizeof(double),1,fp); fwrite(&buck_rho_read[i][j],sizeof(double),1,fp); fwrite(&buck_c_read[i][j],sizeof(double),1,fp); fwrite(&cut_buck_read[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairBuckLongCoulLong::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(&buck_a_read[i][j],sizeof(double),1,fp); fread(&buck_rho_read[i][j],sizeof(double),1,fp); fread(&buck_c_read[i][j],sizeof(double),1,fp); fread(&cut_buck_read[i][j],sizeof(double),1,fp); } MPI_Bcast(&buck_a_read[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&buck_rho_read[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&buck_c_read[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_buck_read[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairBuckLongCoulLong::write_restart_settings(FILE *fp) { fwrite(&cut_buck_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); fwrite(&ncoultablebits,sizeof(int),1,fp); fwrite(&tabinner,sizeof(double),1,fp); fwrite(&ewald_order,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairBuckLongCoulLong::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&cut_buck_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); fread(&ncoultablebits,sizeof(int),1,fp); fread(&tabinner,sizeof(double),1,fp); fread(&ewald_order,sizeof(int),1,fp); } MPI_Bcast(&cut_buck_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); MPI_Bcast(&ncoultablebits,1,MPI_INT,0,world); MPI_Bcast(&tabinner,1,MPI_DOUBLE,0,world); MPI_Bcast(&ewald_order,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void PairBuckLongCoulLong::write_data(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) fprintf(fp,"%d %g %g %g\n",i, buck_a_read[i][i],buck_rho_read[i][i],buck_c_read[i][i]); } /* ---------------------------------------------------------------------- proc 0 writes all pairs to data file ------------------------------------------------------------------------- */ void PairBuckLongCoulLong::write_data_all(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) fprintf(fp,"%d %d %g %g %g\n",i,j, buck_a_read[i][j],buck_rho_read[i][j],buck_c_read[i][j]); } /* ---------------------------------------------------------------------- compute pair interactions ------------------------------------------------------------------------- */ void PairBuckLongCoulLong::compute(int eflag, int vflag) { double evdwl,ecoul,fpair; evdwl = ecoul = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; double **x = atom->x, *x0 = x[0]; double **f = atom->f, *f0 = f[0], *fi = f0; 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; int i, j, order1 = ewald_order&(1<<1), order6 = ewald_order&(1<<6); int *ineigh, *ineighn, *jneigh, *jneighn, typei, typej, ni; double qi = 0.0, qri = 0.0, *cutsqi, *cut_bucksqi, *buck1i, *buck2i, *buckai, *buckci, *rhoinvi, *offseti; double r, rsq, r2inv, force_coul, force_buck; double g2 = g_ewald_6*g_ewald_6, g6 = g2*g2*g2, g8 = g6*g2; vector xi, d; ineighn = (ineigh = list->ilist)+list->inum; for (; ineighfirstneigh[i])+list->numneigh[i]; for (; jneigh= cutsqi[typej = type[j]]) continue; r2inv = 1.0/rsq; r = sqrt(rsq); if (order1 && (rsq < cut_coulsq)) { // coulombic if (!ncoultablebits || rsq <= tabinnersq) { // series real space register double x = g_ewald*r; register double s = qri*q[j], t = 1.0/(1.0+EWALD_P*x); if (ni == 0) { s *= g_ewald*exp(-x*x); force_coul = (t *= ((((t*A5+A4)*t+A3)*t+A2)*t+A1)*s/x)+EWALD_F*s; if (eflag) ecoul = t; } else { // special case register double f = s*(1.0-special_coul[ni])/r; s *= g_ewald*exp(-x*x); force_coul = (t *= ((((t*A5+A4)*t+A3)*t+A2)*t+A1)*s/x)+EWALD_F*s-f; if (eflag) ecoul = t-f; } } // table real space else { register union_int_float_t t; t.f = rsq; register const int k = (t.i & ncoulmask) >> ncoulshiftbits; register double f = (rsq-rtable[k])*drtable[k], qiqj = qi*q[j]; if (ni == 0) { force_coul = qiqj*(ftable[k]+f*dftable[k]); if (eflag) ecoul = qiqj*(etable[k]+f*detable[k]); } else { // special case t.f = (1.0-special_coul[ni])*(ctable[k]+f*dctable[k]); force_coul = qiqj*(ftable[k]+f*dftable[k]-t.f); if (eflag) ecoul = qiqj*(etable[k]+f*detable[k]-t.f); } } } else force_coul = ecoul = 0.0; if (rsq < cut_bucksqi[typej]) { // buckingham register double rn = r2inv*r2inv*r2inv, expr = exp(-r*rhoinvi[typej]); if (order6) { // long-range if (!ndisptablebits || rsq <= tabinnerdispsq) { register double x2 = g2*rsq, a2 = 1.0/x2; x2 = a2*exp(-x2)*buckci[typej]; if (ni == 0) { force_buck = r*expr*buck1i[typej]-g8*(((6.0*a2+6.0)*a2+3.0)*a2+1.0)*x2*rsq; if (eflag) evdwl = expr*buckai[typej]-g6*((a2+1.0)*a2+0.5)*x2; } else { // special case register double f = special_lj[ni], t = rn*(1.0-f); force_buck = f*r*expr*buck1i[typej]- g8*(((6.0*a2+6.0)*a2+3.0)*a2+1.0)*x2*rsq+t*buck2i[typej]; if (eflag) evdwl = f*expr*buckai[typej] - g6*((a2+1.0)*a2+0.5)*x2+t*buckci[typej]; } } else { //table real space register union_int_float_t disp_t; disp_t.f = rsq; register const int disp_k = (disp_t.i & ndispmask)>>ndispshiftbits; register double f_disp = (rsq-rdisptable[disp_k])*drdisptable[disp_k]; if (ni == 0) { force_buck = r*expr*buck1i[typej]-(fdisptable[disp_k]+f_disp*dfdisptable[disp_k])*buckci[typej]; if (eflag) evdwl = expr*buckai[typej]-(edisptable[disp_k]+f_disp*dedisptable[disp_k])*buckci[typej]; } else { //speial case register double f = special_lj[ni], t = rn*(1.0-f); force_buck = f*r*expr*buck1i[typej] -(fdisptable[disp_k]+f_disp*dfdisptable[disp_k])*buckci[typej] +t*buck2i[typej]; if (eflag) evdwl = f*expr*buckai[typej] -(edisptable[disp_k]+f_disp*dedisptable[disp_k])*buckci[typej]+t*buckci[typej]; } } } else { // cut if (ni == 0) { force_buck = r*expr*buck1i[typej]-rn*buck2i[typej]; if (eflag) evdwl = expr*buckai[typej] - rn*buckci[typej]-offseti[typej]; } else { // special case register double f = special_lj[ni]; force_buck = f*(r*expr*buck1i[typej]-rn*buck2i[typej]); if (eflag) evdwl = f*(expr*buckai[typej]-rn*buckci[typej]-offseti[typej]); } } } else force_buck = evdwl = 0.0; fpair = (force_coul+force_buck)*r2inv; if (newton_pair || j < nlocal) { register double *fj = f0+(j+(j<<1)), f; fi[0] += f = d[0]*fpair; fj[0] -= f; fi[1] += f = d[1]*fpair; fj[1] -= f; fi[2] += f = d[2]*fpair; fj[2] -= f; } else { fi[0] += d[0]*fpair; fi[1] += d[1]*fpair; fi[2] += d[2]*fpair; } if (evflag) ev_tally(i,j,nlocal,newton_pair, evdwl,ecoul,fpair,d[0],d[1],d[2]); } } if (vflag_fdotr) virial_fdotr_compute(); } /* ---------------------------------------------------------------------- */ void PairBuckLongCoulLong::compute_inner() { double r, rsq, r2inv, force_coul = 0.0, force_buck, fpair; int *type = atom->type; int nlocal = atom->nlocal; double *x0 = atom->x[0], *f0 = atom->f[0], *fi = f0, *q = atom->q; double *special_coul = force->special_coul; double *special_lj = force->special_lj; int newton_pair = force->newton_pair; double qqrd2e = force->qqrd2e; 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; int *ineigh, *ineighn, *jneigh, *jneighn, typei, typej, ni; int i, j, order1 = (ewald_order|(ewald_off^-1))&(1<<1); double qri, *cut_bucksqi, *buck1i, *buck2i, *rhoinvi; vector xi, d; ineighn = (ineigh = listinner->ilist) + listinner->inum; for (; ineighfirstneigh[i])+listinner->numneigh[i]; for (; jneigh= cut_out_off_sq) continue; r2inv = 1.0/rsq; r = sqrt(rsq); if (order1 && (rsq < cut_coulsq)) // coulombic force_coul = ni == 0 ? qri*q[j]/r : qri*q[j]/r*special_coul[ni]; if (rsq < cut_bucksqi[typej = type[j]]) { // buckingham register double rn = r2inv*r2inv*r2inv, expr = exp(-r*rhoinvi[typej]); force_buck = ni == 0 ? (r*expr*buck1i[typej]-rn*buck2i[typej]) : (r*expr*buck1i[typej]-rn*buck2i[typej])*special_lj[ni]; } else force_buck = 0.0; fpair = (force_coul + force_buck) * r2inv; if (rsq > cut_out_on_sq) { // switching register double rsw = (sqrt(rsq) - cut_out_on)/cut_out_diff; fpair *= 1.0 + rsw*rsw*(2.0*rsw-3.0); } if (newton_pair || j < nlocal) { // force update register double *fj = f0+(j+(j<<1)), f; fi[0] += f = d[0]*fpair; fj[0] -= f; fi[1] += f = d[1]*fpair; fj[1] -= f; fi[2] += f = d[2]*fpair; fj[2] -= f; } else { fi[0] += d[0]*fpair; fi[1] += d[1]*fpair; fi[2] += d[2]*fpair; } } } } /* ---------------------------------------------------------------------- */ void PairBuckLongCoulLong::compute_middle() { double r, rsq, r2inv, force_coul = 0.0, force_buck, fpair; int *type = atom->type; int nlocal = atom->nlocal; double *x0 = atom->x[0], *f0 = atom->f[0], *fi = f0, *q = atom->q; double *special_coul = force->special_coul; double *special_lj = force->special_lj; int newton_pair = force->newton_pair; double qqrd2e = force->qqrd2e; 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; int *ineigh, *ineighn, *jneigh, *jneighn, typei, typej, ni; int i, j, order1 = (ewald_order|(ewald_off^-1))&(1<<1); double qri, *cut_bucksqi, *buck1i, *buck2i, *rhoinvi; vector xi, d; ineighn = (ineigh = listmiddle->ilist)+listmiddle->inum; for (; ineighfirstneigh[i])+listmiddle->numneigh[i]; for (; jneigh= cut_out_off_sq) continue; if (rsq <= cut_in_off_sq) continue; r2inv = 1.0/rsq; r = sqrt(rsq); if (order1 && (rsq < cut_coulsq)) // coulombic force_coul = ni == 0 ? qri*q[j]/r : qri*q[j]/r*special_coul[ni]; if (rsq < cut_bucksqi[typej = type[j]]) { // buckingham register double rn = r2inv*r2inv*r2inv, expr = exp(-r*rhoinvi[typej]); force_buck = ni == 0 ? (r*expr*buck1i[typej]-rn*buck2i[typej]) : (r*expr*buck1i[typej]-rn*buck2i[typej])*special_lj[ni]; } else force_buck = 0.0; fpair = (force_coul + force_buck) * r2inv; if (rsq < cut_in_on_sq) { // switching register double rsw = (sqrt(rsq) - cut_in_off)/cut_in_diff; fpair *= rsw*rsw*(3.0 - 2.0*rsw); } if (rsq > cut_out_on_sq) { register double rsw = (sqrt(rsq) - cut_out_on)/cut_out_diff; fpair *= 1.0 + rsw*rsw*(2.0*rsw-3.0); } if (newton_pair || j < nlocal) { // force update register double *fj = f0+(j+(j<<1)), f; fi[0] += f = d[0]*fpair; fj[0] -= f; fi[1] += f = d[1]*fpair; fj[1] -= f; fi[2] += f = d[2]*fpair; fj[2] -= f; } else { fi[0] += d[0]*fpair; fi[1] += d[1]*fpair; fi[2] += d[2]*fpair; } } } } /* ---------------------------------------------------------------------- */ void PairBuckLongCoulLong::compute_outer(int eflag, int vflag) { double evdwl,ecoul,fpair,fvirial; evdwl = ecoul = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x, *x0 = x[0]; double **f = atom->f, *f0 = f[0], *fi = f0; 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; int i, j, order1 = ewald_order&(1<<1), order6 = ewald_order&(1<<6); int *ineigh, *ineighn, *jneigh, *jneighn, typei, typej, ni, respa_flag; double qi = 0.0, qri = 0.0, *cutsqi, *cut_bucksqi, *buck1i, *buck2i, *buckai, *buckci, *rhoinvi, *offseti; double r, rsq, r2inv, force_coul, force_buck; double g2 = g_ewald_6*g_ewald_6, g6 = g2*g2*g2, g8 = g6*g2; double respa_buck = 0.0, respa_coul = 0.0, frespa = 0.0; vector xi, d; 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; ineighn = (ineigh = listouter->ilist)+listouter->inum; for (; ineighfirstneigh[i])+listouter->numneigh[i]; for (; jneigh= cutsqi[typej = type[j]]) continue; r2inv = 1.0/rsq; r = sqrt(rsq); frespa = 1.0; //check whether and how to compute respa corrections respa_coul = 0.0; respa_buck = 0.0; respa_flag = rsq < cut_in_on_sq ? 1 : 0; if (respa_flag && (rsq > cut_in_off_sq)) { register double rsw = (r-cut_in_off)/cut_in_diff; frespa = 1-rsw*rsw*(3.0-2.0*rsw); } if (order1 && (rsq < cut_coulsq)) { // coulombic if (!ncoultablebits || rsq <= tabinnersq) { // series real space register double s = qri*q[j]; if (respa_flag) // correct for respa respa_coul = ni == 0 ? frespa*s/r : frespa*s/r*special_coul[ni]; register double x = g_ewald*r, t = 1.0/(1.0+EWALD_P*x); if (ni == 0) { s *= g_ewald*exp(-x*x); force_coul = (t *= ((((t*A5+A4)*t+A3)*t+A2)*t+A1)*s/x)+EWALD_F*s-respa_coul; if (eflag) ecoul = t; } else { // correct for special register double ri = s*(1.0-special_coul[ni])/r; s *= g_ewald*exp(-x*x); force_coul = (t *= ((((t*A5+A4)*t+A3)*t+A2)*t+A1)*s/x)+EWALD_F*s-ri-respa_coul; if (eflag) ecoul = t-ri; } } // table real space else { if (respa_flag) { register double s = qri*q[j]; respa_coul = ni == 0 ? frespa*s/r : frespa*s/r*special_coul[ni]; } register union_int_float_t t; t.f = rsq; register const int k = (t.i & ncoulmask) >> ncoulshiftbits; register double f = (rsq-rtable[k])*drtable[k], qiqj = qi*q[j]; if (ni == 0) { force_coul = qiqj*(ftable[k]+f*dftable[k]); if (eflag) ecoul = qiqj*(etable[k]+f*detable[k]); } else { // correct for special t.f = (1.0-special_coul[ni])*(ctable[k]+f*dctable[k]); force_coul = qiqj*(ftable[k]+f*dftable[k]-t.f); if (eflag) { t.f = (1.0-special_coul[ni])*(ptable[k]+f*dptable[k]); ecoul = qiqj*(etable[k]+f*detable[k]-t.f); } } } } else force_coul = respa_coul = ecoul = 0.0; if (rsq < cut_bucksqi[typej]) { // buckingham register double rn = r2inv*r2inv*r2inv, expr = exp(-r*rhoinvi[typej]); if (respa_flag) respa_buck = ni == 0 ? // correct for respa frespa*(r*expr*buck1i[typej]-rn*buck2i[typej]) : frespa*(r*expr*buck1i[typej]-rn*buck2i[typej])*special_lj[ni]; if (order6) { // long-range form if (!ndisptablebits || rsq <= tabinnerdispsq) { register double x2 = g2*rsq, a2 = 1.0/x2; x2 = a2*exp(-x2)*buckci[typej]; if (ni == 0) { force_buck = r*expr*buck1i[typej]-g8*(((6.0*a2+6.0)*a2+3.0)*a2+1.0)*x2*rsq-respa_buck; if (eflag) evdwl = expr*buckai[typej]-g6*((a2+1.0)*a2+0.5)*x2; } else { // correct for special register double f = special_lj[ni], t = rn*(1.0-f); force_buck = f*r*expr*buck1i[typej]- g8*(((6.0*a2+6.0)*a2+3.0)*a2+1.0)*x2*rsq+t*buck2i[typej]-respa_buck; if (eflag) evdwl = f*expr*buckai[typej] - g6*((a2+1.0)*a2+0.5)*x2+t*buckci[typej]; } } else { // table real space register union_int_float_t disp_t; disp_t.f = rsq; register const int disp_k = (disp_t.i & ndispmask)>>ndispshiftbits; register double f_disp = (rsq-rdisptable[disp_k])*drdisptable[disp_k]; register double rn = r2inv*r2inv*r2inv; if (ni == 0) { force_buck = r*expr*buck1i[typej]-(fdisptable[disp_k]+f_disp*dfdisptable[disp_k])*buckci[typej]-respa_buck; if (eflag) evdwl = expr*buckai[typej]-(edisptable[disp_k]+f_disp*dedisptable[disp_k])*buckci[typej]; } else { //special case register double f = special_lj[ni], t = rn*(1.0-f); force_buck = f*r*expr*buck1i[typej]-(fdisptable[disp_k]+f_disp*dfdisptable[disp_k])*buckci[typej]+t*buck2i[typej]-respa_buck; if (eflag) evdwl = f*expr*buckai[typej]-(edisptable[disp_k]+f_disp*dedisptable[disp_k])*buckci[typej]+t*buckci[typej]; } } } else { // cut form if (ni == 0) { force_buck = r*expr*buck1i[typej]-rn*buck2i[typej]-respa_buck; if (eflag) evdwl = expr*buckai[typej]-rn*buckci[typej]-offseti[typej]; } else { // correct for special register double f = special_lj[ni]; force_buck = f*(r*expr*buck1i[typej]-rn*buck2i[typej])-respa_buck; if (eflag) evdwl = f*(expr*buckai[typej]-rn*buckci[typej]-offseti[typej]); } } } else force_buck = respa_buck = evdwl = 0.0; fpair = (force_coul+force_buck)*r2inv; if (newton_pair || j < nlocal) { register double *fj = f0+(j+(j<<1)), f; fi[0] += f = d[0]*fpair; fj[0] -= f; fi[1] += f = d[1]*fpair; fj[1] -= f; fi[2] += f = d[2]*fpair; fj[2] -= f; } else { fi[0] += d[0]*fpair; fi[1] += d[1]*fpair; fi[2] += d[2]*fpair; } if (evflag) { fvirial = (force_coul + force_buck + respa_coul + respa_buck)*r2inv; ev_tally(i,j,nlocal,newton_pair, evdwl,ecoul,fvirial,d[0],d[1],d[2]); } } } } /* ---------------------------------------------------------------------- */ double PairBuckLongCoulLong::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_buck, double &fforce) { double f, r, r2inv, r6inv, force_coul, force_buck; double g2 = g_ewald_6*g_ewald_6, g6 = g2*g2*g2, g8 = g6*g2, *q = atom->q; r = sqrt(rsq); r2inv = 1.0/rsq; double eng = 0.0; if ((ewald_order&2) && (rsq < cut_coulsq)) { // coulombic if (!ncoultablebits || rsq <= tabinnersq) { // series real space register double x = g_ewald*r; register double s = force->qqrd2e*q[i]*q[j], t = 1.0/(1.0+EWALD_P*x); f = s*(1.0-factor_coul)/r; s *= g_ewald*exp(-x*x); force_coul = (t *= ((((t*A5+A4)*t+A3)*t+A2)*t+A1)*s/x)+EWALD_F*s-f; eng += t-f; } else { // table real space register union_int_float_t t; t.f = rsq; register const int k = (t.i & ncoulmask) >> ncoulshiftbits; register double f = (rsq-rtable[k])*drtable[k], qiqj = q[i]*q[j]; t.f = (1.0-factor_coul)*(ctable[k]+f*dctable[k]); force_coul = qiqj*(ftable[k]+f*dftable[k]-t.f); eng += qiqj*(etable[k]+f*detable[k]-t.f); } } else force_coul = 0.0; if (rsq < cut_bucksq[itype][jtype]) { // buckingham register double expr = factor_buck*exp(-sqrt(rsq)*rhoinv[itype][jtype]); r6inv = r2inv*r2inv*r2inv; if (ewald_order&64) { // long-range register double x2 = g2*rsq, a2 = 1.0/x2, t = r6inv*(1.0-factor_buck); x2 = a2*exp(-x2)*buck_c[itype][jtype]; force_buck = buck1[itype][jtype]*r*expr- g8*(((6.0*a2+6.0)*a2+3.0)*a2+a2)*x2*rsq+t*buck2[itype][jtype]; eng += buck_a[itype][jtype]*expr- g6*((a2+1.0)*a2+0.5)*x2+t*buck_c[itype][jtype]; } else { // cut force_buck = buck1[itype][jtype]*r*expr-factor_buck*buck_c[itype][jtype]*r6inv; eng += buck_a[itype][jtype]*expr- factor_buck*(buck_c[itype][jtype]*r6inv-offset[itype][jtype]); } } else force_buck = 0.0; fforce = (force_coul+force_buck)*r2inv; return eng; } diff --git a/src/KSPACE/pair_coul_long.cpp b/src/KSPACE/pair_coul_long.cpp index c1cd14523..988694153 100644 --- a/src/KSPACE/pair_coul_long.cpp +++ b/src/KSPACE/pair_coul_long.cpp @@ -1,400 +1,400 @@ /* ---------------------------------------------------------------------- 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 #include #include #include #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) { ewaldflag = pppmflag = 1; ftable = NULL; qdist = 0.0; } /* ---------------------------------------------------------------------- */ PairCoulLong::~PairCoulLong() { if (!copymode) { 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(FLERR,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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,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,instance_me); 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 requires a KSpace style"); g_ewald = force->kspace->g_ewald; // setup force tables if (ncoultablebits) init_tables(cut_coul,NULL); } /* ---------------------------------------------------------------------- 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+2.0*qdist; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairCoulLong::write_restart(FILE *fp) { write_restart_settings(fp); for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) { fwrite(&setflag[i][j],sizeof(int),1,fp); if (setflag[i][j]) fwrite(&scale[i][j],sizeof(double),1,fp); } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairCoulLong::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(&scale[i][j],sizeof(double),1,fp); MPI_Bcast(&scale[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- 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); fwrite(&ncoultablebits,sizeof(int),1,fp); fwrite(&tabinner,sizeof(double),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); fread(&ncoultablebits,sizeof(int),1,fp); fread(&tabinner,sizeof(double),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); MPI_Bcast(&ncoultablebits,1,MPI_INT,0,world); MPI_Bcast(&tabinner,1,MPI_DOUBLE,0,world); } /* ---------------------------------------------------------------------- */ 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(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_lj_charmm_coul_long.cpp b/src/KSPACE/pair_lj_charmm_coul_long.cpp index 7fad9c5ee..bd020a439 100644 --- a/src/KSPACE/pair_lj_charmm_coul_long.cpp +++ b/src/KSPACE/pair_lj_charmm_coul_long.cpp @@ -1,1032 +1,1032 @@ /* ---------------------------------------------------------------------- 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 #include #include #include #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; #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; ewaldflag = pppmflag = 1; ftable = NULL; implicit = 0; mix_flag = ARITHMETIC; writedata = 1; } /* ---------------------------------------------------------------------- */ PairLJCharmmCoulLong::~PairLJCharmmCoulLong() { if (!copymode) { 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); memory->destroy(offset); } 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_inv; switch2 = 12.0*rsq * (cut_ljsq-rsq) * (rsq-cut_lj_innersq) * denom_lj_inv; 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_inv; 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; // 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_inv; 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; // 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_inv; switch2 = 12.0*rsq * (cut_ljsq-rsq) * (rsq-cut_lj_innersq) * denom_lj_inv; 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_inv; fpair *= rsw*rsw*(3.0 - 2.0*rsw); } if (rsq > cut_out_on_sq) { rsw = (sqrt(rsq) - cut_out_on)*cut_out_diff_inv; 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; // 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_inv; switch2 = 12.0*rsq * (cut_ljsq-rsq) * (rsq-cut_lj_innersq) * denom_lj_inv; 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_inv; 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_inv; switch2 = 12.0*rsq * (cut_ljsq-rsq) * (rsq-cut_lj_innersq) * denom_lj_inv; philj = r6inv * (lj3[itype][jtype]*r6inv - lj4[itype][jtype]); forcelj = forcelj*switch1 + philj*switch2; } } else if (rsq <= cut_in_on_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_inv; switch2 = 12.0*rsq * (cut_ljsq-rsq) * (rsq-cut_lj_innersq) * denom_lj_inv; 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"); memory->create(offset,n+1,n+1,"pair:offset"); } /* ---------------------------------------------------------------------- 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(FLERR,arg[0]); cut_lj = force->numeric(FLERR,arg[1]); if (narg == 2) cut_coul = cut_lj; else cut_coul = force->numeric(FLERR,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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(FLERR,arg[2]); double sigma_one = force->numeric(FLERR,arg[3]); double eps14_one = epsilon_one; double sigma14_one = sigma_one; if (narg == 6) { eps14_one = force->numeric(FLERR,arg[4]); sigma14_one = force->numeric(FLERR,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,instance_me); else if (respa == 1) { irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respainner = 1; irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 3; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respaouter = 1; } else { irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respainner = 1; irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 2; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respamiddle = 1; irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 3; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respaouter = 1; } } else irequest = neighbor->request(this,instance_me); // 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) ); denom_lj_inv = 1.0 / denom_lj; // set & error check interior rRESPA cutoffs if (strstr(update->integrate_style,"respa") && ((Respa *) update->integrate)->level_inner >= 0) { cut_respa = ((Respa *) update->integrate)->cutoff; cut_in_off = cut_respa[0]; cut_in_on = cut_respa[1]; cut_out_on = cut_respa[2]; cut_out_off = cut_respa[3]; cut_in_diff = cut_in_on - cut_in_off; cut_out_diff = cut_out_off - cut_out_on; cut_in_diff_inv = 1.0 / (cut_in_diff); cut_out_diff_inv = 1.0 / (cut_out_diff); cut_in_off_sq = cut_in_off*cut_in_off; cut_in_on_sq = cut_in_on*cut_in_on; cut_out_on_sq = cut_out_on*cut_out_on; cut_out_off_sq = cut_out_off*cut_out_off; 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 requires a KSpace style"); g_ewald = force->kspace->g_ewald; // setup force tables if (ncoultablebits) init_tables(cut_coul,cut_respa); } /* ---------------------------------------------------------------------- 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; } /* ---------------------------------------------------------------------- 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); fwrite(&ncoultablebits,sizeof(int),1,fp); fwrite(&tabinner,sizeof(double),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); fread(&ncoultablebits,sizeof(int),1,fp); fread(&tabinner,sizeof(double),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); MPI_Bcast(&ncoultablebits,1,MPI_INT,0,world); MPI_Bcast(&tabinner,1,MPI_DOUBLE,0,world); } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void PairLJCharmmCoulLong::write_data(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) fprintf(fp,"%d %g %g %g %g\n", i,epsilon[i][i],sigma[i][i],eps14[i][i],sigma14[i][i]); } /* ---------------------------------------------------------------------- proc 0 writes all pairs to data file ------------------------------------------------------------------------- */ void PairLJCharmmCoulLong::write_data_all(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) fprintf(fp,"%d %d %g %g %g %g\n",i,j, epsilon[i][j],sigma[i][j],eps14[i][j],sigma14[i][j]); } /* ---------------------------------------------------------------------- */ 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_inv; switch2 = 12.0*rsq * (cut_ljsq-rsq) * (rsq-cut_lj_innersq) * denom_lj_inv; 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_inv; philj *= switch1; } eng += factor_lj*philj; } return eng; } /* ---------------------------------------------------------------------- */ 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_cut_coul_long.cpp b/src/KSPACE/pair_lj_cut_coul_long.cpp index 866db6ba6..0d0649fe6 100644 --- a/src/KSPACE/pair_lj_cut_coul_long.cpp +++ b/src/KSPACE/pair_lj_cut_coul_long.cpp @@ -1,983 +1,983 @@ /* ---------------------------------------------------------------------- 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 #include #include #include #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) { ewaldflag = pppmflag = 1; respa_enable = 1; writedata = 1; ftable = NULL; qdist = 0.0; } /* ---------------------------------------------------------------------- */ 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) { r6inv = r2inv*r2inv*r2inv; 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(FLERR,arg[0]); if (narg == 1) cut_coul = cut_lj_global; else cut_coul = force->numeric(FLERR,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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(FLERR,arg[2]); double sigma_one = force->numeric(FLERR,arg[3]); double cut_lj_one = cut_lj_global; if (narg == 5) cut_lj_one = force->numeric(FLERR,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,instance_me); else if (respa == 1) { irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respainner = 1; irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 3; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respaouter = 1; } else { irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respainner = 1; irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 2; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respamiddle = 1; irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 3; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respaouter = 1; } } else irequest = neighbor->request(this,instance_me); 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 requires a KSpace style"); g_ewald = force->kspace->g_ewald; // setup force tables if (ncoultablebits) init_tables(cut_coul,cut_respa); } /* ---------------------------------------------------------------------- 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]); } // include TIP4P qdist in full cutoff, qdist = 0.0 if not TIP4P double cut = MAX(cut_lj[i][j],cut_coul+2.0*qdist); 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; } /* ---------------------------------------------------------------------- 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); fwrite(&tail_flag,sizeof(int),1,fp); fwrite(&ncoultablebits,sizeof(int),1,fp); fwrite(&tabinner,sizeof(double),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); fread(&tail_flag,sizeof(int),1,fp); fread(&ncoultablebits,sizeof(int),1,fp); fread(&tabinner,sizeof(double),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); MPI_Bcast(&tail_flag,1,MPI_INT,0,world); MPI_Bcast(&ncoultablebits,1,MPI_INT,0,world); MPI_Bcast(&tabinner,1,MPI_DOUBLE,0,world); } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void PairLJCutCoulLong::write_data(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) fprintf(fp,"%d %g %g\n",i,epsilon[i][i],sigma[i][i]); } /* ---------------------------------------------------------------------- proc 0 writes all pairs to data file ------------------------------------------------------------------------- */ void PairLJCutCoulLong::write_data_all(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) fprintf(fp,"%d %d %g %g %g\n",i,j,epsilon[i][j],sigma[i][j],cut_lj[i][j]); } /* ---------------------------------------------------------------------- */ 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(const char *str, int &dim) { dim = 0; if (strcmp(str,"cut_coul") == 0) return (void *) &cut_coul; dim = 2; if (strcmp(str,"epsilon") == 0) return (void *) epsilon; if (strcmp(str,"sigma") == 0) return (void *) sigma; return NULL; } diff --git a/src/KSPACE/pair_lj_long_coul_long.cpp b/src/KSPACE/pair_lj_long_coul_long.cpp index 3675ea76d..3b4ed7978 100644 --- a/src/KSPACE/pair_lj_long_coul_long.cpp +++ b/src/KSPACE/pair_lj_long_coul_long.cpp @@ -1,1041 +1,1041 @@ /* ---------------------------------------------------------------------- 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: Pieter J. in 't Veld (SNL) Tabulation for long-range dispersion added by Wayne Mitchell (Loyola University New Orleans) ------------------------------------------------------------------------- */ #include #include #include #include #include "math_vector.h" #include "pair_lj_long_coul_long.h" #include "atom.h" #include "comm.h" #include "neighbor.h" #include "neigh_list.h" #include "neigh_request.h" #include "force.h" #include "kspace.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 /* ---------------------------------------------------------------------- */ PairLJLongCoulLong::PairLJLongCoulLong(LAMMPS *lmp) : Pair(lmp) { dispersionflag = ewaldflag = pppmflag = 1; respa_enable = 1; writedata = 1; ftable = NULL; fdisptable = NULL; qdist = 0.0; } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairLJLongCoulLong::options(char **arg, int order) { const char *option[] = {"long", "cut", "off", NULL}; int i; if (!*arg) error->all(FLERR,"Illegal pair_style lj/long/coul/long command"); for (i=0; option[i]&&strcmp(arg[0], option[i]); ++i); switch (i) { default: error->all(FLERR,"Illegal pair_style lj/long/coul/long command"); case 0: ewald_order |= 1<all(FLERR,"Illegal pair_style command"); ewald_off = 0; ewald_order = 0; options(arg, 6); options(++arg, 1); if (!comm->me && ewald_order == ((1<<1) | (1<<6))) error->warning(FLERR,"Using largest cutoff for lj/long/coul/long"); if (!*(++arg)) error->all(FLERR,"Cutoffs missing in pair_style lj/long/coul/long"); if (!((ewald_order^ewald_off) & (1<<1))) error->all(FLERR, "Coulomb cut not supported in pair_style lj/long/coul/long"); cut_lj_global = force->numeric(FLERR,*(arg++)); if (narg == 4 && ((ewald_order & 0x42) == 0x42)) error->all(FLERR,"Only one cutoff allowed when requesting all long"); if (narg == 4) cut_coul = force->numeric(FLERR,*arg); else cut_coul = cut_lj_global; 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; } } /* ---------------------------------------------------------------------- free all arrays ------------------------------------------------------------------------- */ PairLJLongCoulLong::~PairLJLongCoulLong() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut_lj_read); memory->destroy(cut_lj); memory->destroy(cut_ljsq); memory->destroy(epsilon_read); memory->destroy(epsilon); memory->destroy(sigma_read); memory->destroy(sigma); memory->destroy(lj1); memory->destroy(lj2); memory->destroy(lj3); memory->destroy(lj4); memory->destroy(offset); } if (ftable) free_tables(); } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairLJLongCoulLong::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_read,n+1,n+1,"pair:cut_lj_read"); 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_read,n+1,n+1,"pair:epsilon_read"); memory->create(epsilon,n+1,n+1,"pair:epsilon"); memory->create(sigma_read,n+1,n+1,"pair:sigma_read"); 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"); } /* ---------------------------------------------------------------------- extract protected data from object ------------------------------------------------------------------------- */ void *PairLJLongCoulLong::extract(const char *id, int &dim) { const char *ids[] = { "B", "sigma", "epsilon", "ewald_order", "ewald_cut", "ewald_mix", "cut_coul", "cut_LJ", NULL}; void *ptrs[] = { lj4, sigma, epsilon, &ewald_order, &cut_coul, &mix_flag, &cut_coul, &cut_lj_global, NULL}; int i; for (i=0; ids[i]&&strcmp(ids[i], id); ++i); if (i <= 2) dim = 2; else dim = 0; return ptrs[i]; } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairLJLongCoulLong::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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(FLERR,arg[2]); double sigma_one = force->numeric(FLERR,arg[3]); double cut_lj_one = cut_lj_global; if (narg == 5) cut_lj_one = force->numeric(FLERR,arg[4]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { epsilon_read[i][j] = epsilon_one; sigma_read[i][j] = sigma_one; cut_lj_read[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 PairLJLongCoulLong::init_style() { // require an atom style with charge defined if (!atom->q_flag && (ewald_order&(1<<1))) error->all(FLERR, "Invoking coulombic in pair style lj/coul requires atom attribute q"); // request regular or rRESPA neighbor lists if neighrequest_flag != 0 if (force->kspace->neighrequest_flag) { 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,instance_me); else if (respa == 1) { irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respainner = 1; irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 3; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respaouter = 1; } else { irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respainner = 1; irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 2; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respamiddle = 1; irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 3; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respaouter = 1; } } else irequest = neighbor->request(this,instance_me); } 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; // ensure use of KSpace long-range solver, set g_ewald if (force->kspace == NULL) error->all(FLERR,"Pair style requires a KSpace style"); if (force->kspace) g_ewald = force->kspace->g_ewald; if (force->kspace) g_ewald_6 = force->kspace->g_ewald_6; // setup force tables if (ncoultablebits) init_tables(cut_coul,cut_respa); if (ndisptablebits) init_tables_disp(cut_lj_global); } /* ---------------------------------------------------------------------- neighbor callback to inform pair style of neighbor list to use regular or rRESPA ------------------------------------------------------------------------- */ void PairLJLongCoulLong::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 PairLJLongCoulLong::init_one(int i, int j) { if (setflag[i][j] == 0) { epsilon[i][j] = mix_energy(epsilon_read[i][i],epsilon_read[j][j], sigma_read[i][i],sigma_read[j][j]); sigma[i][j] = mix_distance(sigma_read[i][i],sigma_read[j][j]); if (ewald_order&(1<<6)) cut_lj[i][j] = cut_lj_global; else cut_lj[i][j] = mix_distance(cut_lj_read[i][i],cut_lj_read[j][j]); } else { sigma[i][j] = sigma_read[i][j]; epsilon[i][j] = epsilon_read[i][j]; cut_lj[i][j] = cut_lj_read[i][j]; } double cut = MAX(cut_lj[i][j], cut_coul + 2.0*qdist); cutsq[i][j] = cut*cut; 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); // 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"); 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; cutsq[j][i] = cutsq[i][j]; 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]; return cut; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJLongCoulLong::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_read[i][j],sizeof(double),1,fp); fwrite(&sigma_read[i][j],sizeof(double),1,fp); fwrite(&cut_lj_read[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJLongCoulLong::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_read[i][j],sizeof(double),1,fp); fread(&sigma_read[i][j],sizeof(double),1,fp); fread(&cut_lj_read[i][j],sizeof(double),1,fp); } MPI_Bcast(&epsilon_read[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&sigma_read[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_lj_read[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJLongCoulLong::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); fwrite(&ncoultablebits,sizeof(int),1,fp); fwrite(&tabinner,sizeof(double),1,fp); fwrite(&ewald_order,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJLongCoulLong::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); fread(&ncoultablebits,sizeof(int),1,fp); fread(&tabinner,sizeof(double),1,fp); fread(&ewald_order,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); MPI_Bcast(&ncoultablebits,1,MPI_INT,0,world); MPI_Bcast(&tabinner,1,MPI_DOUBLE,0,world); MPI_Bcast(&ewald_order,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void PairLJLongCoulLong::write_data(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) fprintf(fp,"%d %g %g\n",i,epsilon_read[i][i],sigma_read[i][i]); } /* ---------------------------------------------------------------------- proc 0 writes all pairs to data file ------------------------------------------------------------------------- */ void PairLJLongCoulLong::write_data_all(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) fprintf(fp,"%d %d %g %g %g\n",i,j, epsilon_read[i][j],sigma_read[i][j],cut_lj_read[i][j]); } /* ---------------------------------------------------------------------- compute pair interactions ------------------------------------------------------------------------- */ void PairLJLongCoulLong::compute(int eflag, int vflag) { double evdwl,ecoul,fpair; evdwl = ecoul = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; double **x = atom->x, *x0 = x[0]; double **f = atom->f, *f0 = f[0], *fi = f0; 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; int i, j, order1 = ewald_order&(1<<1), order6 = ewald_order&(1<<6); int *ineigh, *ineighn, *jneigh, *jneighn, typei, typej, ni; double qi = 0.0, qri = 0.0; double *cutsqi, *cut_ljsqi, *lj1i, *lj2i, *lj3i, *lj4i, *offseti; double rsq, r2inv, force_coul, force_lj; double g2 = g_ewald_6*g_ewald_6, g6 = g2*g2*g2, g8 = g6*g2; vector xi, d; ineighn = (ineigh = list->ilist)+list->inum; for (; ineighfirstneigh[i])+list->numneigh[i]; for (; jneigh= cutsqi[typej = type[j]]) continue; r2inv = 1.0/rsq; if (order1 && (rsq < cut_coulsq)) { // coulombic if (!ncoultablebits || rsq <= tabinnersq) { // series real space register double r = sqrt(rsq), x = g_ewald*r; register double s = qri*q[j], t = 1.0/(1.0+EWALD_P*x); if (ni == 0) { s *= g_ewald*exp(-x*x); force_coul = (t *= ((((t*A5+A4)*t+A3)*t+A2)*t+A1)*s/x)+EWALD_F*s; if (eflag) ecoul = t; } else { // special case r = s*(1.0-special_coul[ni])/r; s *= g_ewald*exp(-x*x); force_coul = (t *= ((((t*A5+A4)*t+A3)*t+A2)*t+A1)*s/x)+EWALD_F*s-r; if (eflag) ecoul = t-r; } } // table real space else { register union_int_float_t t; t.f = rsq; register const int k = (t.i & ncoulmask)>>ncoulshiftbits; register double f = (rsq-rtable[k])*drtable[k], qiqj = qi*q[j]; if (ni == 0) { force_coul = qiqj*(ftable[k]+f*dftable[k]); if (eflag) ecoul = qiqj*(etable[k]+f*detable[k]); } else { // special case t.f = (1.0-special_coul[ni])*(ctable[k]+f*dctable[k]); force_coul = qiqj*(ftable[k]+f*dftable[k]-t.f); if (eflag) ecoul = qiqj*(etable[k]+f*detable[k]-t.f); } } } else force_coul = ecoul = 0.0; if (rsq < cut_ljsqi[typej]) { // lj if (order6) { // long-range lj if(!ndisptablebits || rsq <= tabinnerdispsq) { // series real space register double rn = r2inv*r2inv*r2inv; register double x2 = g2*rsq, a2 = 1.0/x2; x2 = a2*exp(-x2)*lj4i[typej]; if (ni == 0) { force_lj = (rn*=rn)*lj1i[typej]-g8*(((6.0*a2+6.0)*a2+3.0)*a2+1.0)*x2*rsq; if (eflag) evdwl = rn*lj3i[typej]-g6*((a2+1.0)*a2+0.5)*x2; } else { // special case register double f = special_lj[ni], t = rn*(1.0-f); force_lj = f*(rn *= rn)*lj1i[typej]- g8*(((6.0*a2+6.0)*a2+3.0)*a2+1.0)*x2*rsq+t*lj2i[typej]; if (eflag) evdwl = f*rn*lj3i[typej]-g6*((a2+1.0)*a2+0.5)*x2+t*lj4i[typej]; } } else { // table real space register union_int_float_t disp_t; disp_t.f = rsq; register const int disp_k = (disp_t.i & ndispmask)>>ndispshiftbits; register double f_disp = (rsq-rdisptable[disp_k])*drdisptable[disp_k]; register double rn = r2inv*r2inv*r2inv; if (ni == 0) { force_lj = (rn*=rn)*lj1i[typej]-(fdisptable[disp_k]+f_disp*dfdisptable[disp_k])*lj4i[typej]; if (eflag) evdwl = rn*lj3i[typej]-(edisptable[disp_k]+f_disp*dedisptable[disp_k])*lj4i[typej]; } else { // special case register double f = special_lj[ni], t = rn*(1.0-f); force_lj = f*(rn *= rn)*lj1i[typej]-(fdisptable[disp_k]+f_disp*dfdisptable[disp_k])*lj4i[typej]+t*lj2i[typej]; if (eflag) evdwl = f*rn*lj3i[typej]-(edisptable[disp_k]+f_disp*dedisptable[disp_k])*lj4i[typej]+t*lj4i[typej]; } } } else { // cut lj register double rn = r2inv*r2inv*r2inv; if (ni == 0) { force_lj = rn*(rn*lj1i[typej]-lj2i[typej]); if (eflag) evdwl = rn*(rn*lj3i[typej]-lj4i[typej])-offseti[typej]; } else { // special case register double f = special_lj[ni]; force_lj = f*rn*(rn*lj1i[typej]-lj2i[typej]); if (eflag) evdwl = f * (rn*(rn*lj3i[typej]-lj4i[typej])-offseti[typej]); } } } else force_lj = evdwl = 0.0; fpair = (force_coul+force_lj)*r2inv; if (newton_pair || j < nlocal) { register double *fj = f0+(j+(j<<1)), f; fi[0] += f = d[0]*fpair; fj[0] -= f; fi[1] += f = d[1]*fpair; fj[1] -= f; fi[2] += f = d[2]*fpair; fj[2] -= f; } else { fi[0] += d[0]*fpair; fi[1] += d[1]*fpair; fi[2] += d[2]*fpair; } if (evflag) ev_tally(i,j,nlocal,newton_pair, evdwl,ecoul,fpair,d[0],d[1],d[2]); } } if (vflag_fdotr) virial_fdotr_compute(); } /* ---------------------------------------------------------------------- */ void PairLJLongCoulLong::compute_inner() { double rsq, r2inv, force_coul = 0.0, force_lj, fpair; int *type = atom->type; int nlocal = atom->nlocal; double *x0 = atom->x[0], *f0 = atom->f[0], *fi = f0, *q = atom->q; double *special_coul = force->special_coul; double *special_lj = force->special_lj; int newton_pair = force->newton_pair; double qqrd2e = force->qqrd2e; 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; int *ineigh, *ineighn, *jneigh, *jneighn, typei, typej, ni; int i, j, order1 = (ewald_order|(ewald_off^-1))&(1<<1); double qri, *cut_ljsqi, *lj1i, *lj2i; vector xi, d; ineighn = (ineigh = listinner->ilist)+listinner->inum; for (; ineighfirstneigh[i])+listinner->numneigh[i]; for (; jneigh= cut_out_off_sq) continue; r2inv = 1.0/rsq; if (order1 && (rsq < cut_coulsq)) { // coulombic qri = qqrd2e*q[i]; force_coul = ni == 0 ? qri*q[j]*sqrt(r2inv) : qri*q[j]*sqrt(r2inv)*special_coul[ni]; } if (rsq < cut_ljsqi[typej = type[j]]) { // lennard-jones register double rn = r2inv*r2inv*r2inv; force_lj = ni == 0 ? rn*(rn*lj1i[typej]-lj2i[typej]) : rn*(rn*lj1i[typej]-lj2i[typej])*special_lj[ni]; } else force_lj = 0.0; fpair = (force_coul + force_lj) * r2inv; if (rsq > cut_out_on_sq) { // switching register double rsw = (sqrt(rsq) - cut_out_on)/cut_out_diff; fpair *= 1.0 + rsw*rsw*(2.0*rsw-3.0); } if (newton_pair || j < nlocal) { // force update register double *fj = f0+(j+(j<<1)), f; fi[0] += f = d[0]*fpair; fj[0] -= f; fi[1] += f = d[1]*fpair; fj[1] -= f; fi[2] += f = d[2]*fpair; fj[2] -= f; } else { fi[0] += d[0]*fpair; fi[1] += d[1]*fpair; fi[2] += d[2]*fpair; } } } } /* ---------------------------------------------------------------------- */ void PairLJLongCoulLong::compute_middle() { double rsq, r2inv, force_coul = 0.0, force_lj, fpair; int *type = atom->type; int nlocal = atom->nlocal; double *x0 = atom->x[0], *f0 = atom->f[0], *fi = f0, *q = atom->q; double *special_coul = force->special_coul; double *special_lj = force->special_lj; int newton_pair = force->newton_pair; double qqrd2e = force->qqrd2e; 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; int *ineigh, *ineighn, *jneigh, *jneighn, typei, typej, ni; int i, j, order1 = (ewald_order|(ewald_off^-1))&(1<<1); double qri, *cut_ljsqi, *lj1i, *lj2i; vector xi, d; ineighn = (ineigh = listmiddle->ilist)+listmiddle->inum; for (; ineighfirstneigh[i])+listmiddle->numneigh[i]; for (; jneigh= cut_out_off_sq) continue; if (rsq <= cut_in_off_sq) continue; r2inv = 1.0/rsq; if (order1 && (rsq < cut_coulsq)) // coulombic force_coul = ni == 0 ? qri*q[j]*sqrt(r2inv) : qri*q[j]*sqrt(r2inv)*special_coul[ni]; if (rsq < cut_ljsqi[typej = type[j]]) { // lennard-jones register double rn = r2inv*r2inv*r2inv; force_lj = ni == 0 ? rn*(rn*lj1i[typej]-lj2i[typej]) : rn*(rn*lj1i[typej]-lj2i[typej])*special_lj[ni]; } else force_lj = 0.0; fpair = (force_coul + force_lj) * r2inv; if (rsq < cut_in_on_sq) { // switching register double rsw = (sqrt(rsq) - cut_in_off)/cut_in_diff; fpair *= rsw*rsw*(3.0 - 2.0*rsw); } if (rsq > cut_out_on_sq) { register double rsw = (sqrt(rsq) - cut_out_on)/cut_out_diff; fpair *= 1.0 + rsw*rsw*(2.0*rsw-3.0); } if (newton_pair || j < nlocal) { // force update register double *fj = f0+(j+(j<<1)), f; fi[0] += f = d[0]*fpair; fj[0] -= f; fi[1] += f = d[1]*fpair; fj[1] -= f; fi[2] += f = d[2]*fpair; fj[2] -= f; } else { fi[0] += d[0]*fpair; fi[1] += d[1]*fpair; fi[2] += d[2]*fpair; } } } } /* ---------------------------------------------------------------------- */ void PairLJLongCoulLong::compute_outer(int eflag, int vflag) { double evdwl,ecoul,fvirial,fpair; evdwl = ecoul = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x, *x0 = x[0]; double **f = atom->f, *f0 = f[0], *fi = f0; 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; int i, j, order1 = ewald_order&(1<<1), order6 = ewald_order&(1<<6); int *ineigh, *ineighn, *jneigh, *jneighn, typei, typej, ni, respa_flag; double qi = 0.0, qri = 0.0; double *cutsqi, *cut_ljsqi, *lj1i, *lj2i, *lj3i, *lj4i, *offseti; double rsq, r2inv, force_coul, force_lj; double g2 = g_ewald_6*g_ewald_6, g6 = g2*g2*g2, g8 = g6*g2; double respa_lj = 0.0, respa_coul = 0.0, frespa = 0.0; vector xi, d; 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; ineighn = (ineigh = listouter->ilist)+listouter->inum; for (; ineighfirstneigh[i])+listouter->numneigh[i]; for (; jneigh= cutsqi[typej = type[j]]) continue; r2inv = 1.0/rsq; frespa = 1.0; // check whether and how to compute respa corrections respa_coul = 0; respa_lj = 0; respa_flag = rsq < cut_in_on_sq ? 1 : 0; if (respa_flag && (rsq > cut_in_off_sq)) { register double rsw = (sqrt(rsq)-cut_in_off)/cut_in_diff; frespa = 1-rsw*rsw*(3.0-2.0*rsw); } if (order1 && (rsq < cut_coulsq)) { // coulombic if (!ncoultablebits || rsq <= tabinnersq) { // series real space register double r = sqrt(rsq), s = qri*q[j]; if (respa_flag) // correct for respa respa_coul = ni == 0 ? frespa*s/r : frespa*s/r*special_coul[ni]; register double x = g_ewald*r, t = 1.0/(1.0+EWALD_P*x); if (ni == 0) { s *= g_ewald*exp(-x*x); force_coul = (t *= ((((t*A5+A4)*t+A3)*t+A2)*t+A1)*s/x)+EWALD_F*s-respa_coul; if (eflag) ecoul = t; } else { // correct for special r = s*(1.0-special_coul[ni])/r; s *= g_ewald*exp(-x*x); force_coul = (t *= ((((t*A5+A4)*t+A3)*t+A2)*t+A1)*s/x)+EWALD_F*s-r-respa_coul; if (eflag) ecoul = t-r; } } // table real space else { if (respa_flag) { register double r = sqrt(rsq), s = qri*q[j]; respa_coul = ni == 0 ? frespa*s/r : frespa*s/r*special_coul[ni]; } register union_int_float_t t; t.f = rsq; register const int k = (t.i & ncoulmask) >> ncoulshiftbits; register double f = (rsq-rtable[k])*drtable[k], qiqj = qi*q[j]; if (ni == 0) { force_coul = qiqj*(ftable[k]+f*dftable[k]); if (eflag) ecoul = qiqj*(etable[k]+f*detable[k]); } else { // correct for special t.f = (1.0-special_coul[ni])*(ctable[k]+f*dctable[k]); force_coul = qiqj*(ftable[k]+f*dftable[k]-t.f); if (eflag) { t.f = (1.0-special_coul[ni])*(ptable[k]+f*dptable[k]); ecoul = qiqj*(etable[k]+f*detable[k]-t.f); } } } } else force_coul = respa_coul = ecoul = 0.0; if (rsq < cut_ljsqi[typej]) { // lennard-jones register double rn = r2inv*r2inv*r2inv; if (respa_flag) respa_lj = ni == 0 ? // correct for respa frespa*rn*(rn*lj1i[typej]-lj2i[typej]) : frespa*rn*(rn*lj1i[typej]-lj2i[typej])*special_lj[ni]; if (order6) { // long-range form if (!ndisptablebits || rsq <= tabinnerdispsq) { register double x2 = g2*rsq, a2 = 1.0/x2; x2 = a2*exp(-x2)*lj4i[typej]; if (ni == 0) { force_lj = (rn*=rn)*lj1i[typej]-g8*(((6.0*a2+6.0)*a2+3.0)*a2+1.0)*x2*rsq-respa_lj; if (eflag) evdwl = rn*lj3i[typej]-g6*((a2+1.0)*a2+0.5)*x2; } else { // correct for special register double f = special_lj[ni], t = rn*(1.0-f); force_lj = f*(rn *= rn)*lj1i[typej]- g8*(((6.0*a2+6.0)*a2+3.0)*a2+1.0)*x2*rsq+t*lj2i[typej]-respa_lj; if (eflag) evdwl = f*rn*lj3i[typej]-g6*((a2+1.0)*a2+0.5)*x2+t*lj4i[typej]; } } else { // table real space register union_int_float_t disp_t; disp_t.f = rsq; register const int disp_k = (disp_t.i & ndispmask)>>ndispshiftbits; register double f_disp = (rsq-rdisptable[disp_k])*drdisptable[disp_k]; register double rn = r2inv*r2inv*r2inv; if (ni == 0) { force_lj = (rn*=rn)*lj1i[typej]-(fdisptable[disp_k]+f_disp*dfdisptable[disp_k])*lj4i[typej]-respa_lj; if (eflag) evdwl = rn*lj3i[typej]-(edisptable[disp_k]+f_disp*dedisptable[disp_k])*lj4i[typej]; } else { // special case register double f = special_lj[ni], t = rn*(1.0-f); force_lj = f*(rn *= rn)*lj1i[typej]-(fdisptable[disp_k]+f_disp*dfdisptable[disp_k])*lj4i[typej]+t*lj2i[typej]-respa_lj; if (eflag) evdwl = f*rn*lj3i[typej]-(edisptable[disp_k]+f_disp*dedisptable[disp_k])*lj4i[typej]+t*lj4i[typej]; } } } else { // cut form if (ni == 0) { force_lj = rn*(rn*lj1i[typej]-lj2i[typej])-respa_lj; if (eflag) evdwl = rn*(rn*lj3i[typej]-lj4i[typej])-offseti[typej]; } else { // correct for special register double f = special_lj[ni]; force_lj = f*rn*(rn*lj1i[typej]-lj2i[typej])-respa_lj; if (eflag) evdwl = f*(rn*(rn*lj3i[typej]-lj4i[typej])-offseti[typej]); } } } else force_lj = respa_lj = evdwl = 0.0; fpair = (force_coul+force_lj)*r2inv; if (newton_pair || j < nlocal) { register double *fj = f0+(j+(j<<1)), f; fi[0] += f = d[0]*fpair; fj[0] -= f; fi[1] += f = d[1]*fpair; fj[1] -= f; fi[2] += f = d[2]*fpair; fj[2] -= f; } else { fi[0] += d[0]*fpair; fi[1] += d[1]*fpair; fi[2] += d[2]*fpair; } if (evflag) { fvirial = (force_coul + force_lj + respa_coul + respa_lj)*r2inv; ev_tally(i,j,nlocal,newton_pair, evdwl,ecoul,fvirial,d[0],d[1],d[2]); } } } } /* ---------------------------------------------------------------------- */ double PairLJLongCoulLong::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r2inv, r6inv, force_coul, force_lj; double g2 = g_ewald_6*g_ewald_6, g6 = g2*g2*g2, g8 = g6*g2, *q = atom->q; double eng = 0.0; r2inv = 1.0/rsq; if ((ewald_order&2) && (rsq < cut_coulsq)) { // coulombic if (!ncoultablebits || rsq <= tabinnersq) { // series real space register double r = sqrt(rsq), x = g_ewald*r; register double s = force->qqrd2e*q[i]*q[j], t = 1.0/(1.0+EWALD_P*x); r = s*(1.0-factor_coul)/r; s *= g_ewald*exp(-x*x); force_coul = (t *= ((((t*A5+A4)*t+A3)*t+A2)*t+A1)*s/x)+EWALD_F*s-r; eng += t-r; } else { // table real space register union_int_float_t t; t.f = rsq; register const int k = (t.i & ncoulmask) >> ncoulshiftbits; register double f = (rsq-rtable[k])*drtable[k], qiqj = q[i]*q[j]; t.f = (1.0-factor_coul)*(ctable[k]+f*dctable[k]); force_coul = qiqj*(ftable[k]+f*dftable[k]-t.f); eng += qiqj*(etable[k]+f*detable[k]-t.f); } } else force_coul = 0.0; if (rsq < cut_ljsq[itype][jtype]) { // lennard-jones r6inv = r2inv*r2inv*r2inv; if (ewald_order&64) { // long-range register double x2 = g2*rsq, a2 = 1.0/x2, t = r6inv*(1.0-factor_lj); x2 = a2*exp(-x2)*lj4[itype][jtype]; force_lj = factor_lj*(r6inv *= r6inv)*lj1[itype][jtype]- g8*(((6.0*a2+6.0)*a2+3.0)*a2+a2)*x2*rsq+t*lj2[itype][jtype]; eng += factor_lj*r6inv*lj3[itype][jtype]- g6*((a2+1.0)*a2+0.5)*x2+t*lj4[itype][jtype]; } else { // cut force_lj = factor_lj*r6inv*(lj1[itype][jtype]*r6inv-lj2[itype][jtype]); eng += factor_lj*(r6inv*(r6inv*lj3[itype][jtype]- lj4[itype][jtype])-offset[itype][jtype]); } } else force_lj = 0.0; fforce = (force_coul+force_lj)*r2inv; return eng; } diff --git a/src/MANYBODY/pair_eam.cpp b/src/MANYBODY/pair_eam.cpp index 53fbef60e..880b8f62f 100644 --- a/src/MANYBODY/pair_eam.cpp +++ b/src/MANYBODY/pair_eam.cpp @@ -1,905 +1,905 @@ /* ---------------------------------------------------------------------- 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: Stephen Foiles (SNL), Murray Daw (SNL) ------------------------------------------------------------------------- */ #include #include #include #include #include "pair_eam.h" #include "atom.h" #include "force.h" #include "comm.h" #include "neighbor.h" #include "neigh_list.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define MAXLINE 1024 /* ---------------------------------------------------------------------- */ PairEAM::PairEAM(LAMMPS *lmp) : Pair(lmp) { restartinfo = 0; manybody_flag = 1; nmax = 0; rho = NULL; fp = NULL; map = NULL; type2frho = NULL; nfuncfl = 0; funcfl = NULL; setfl = NULL; fs = NULL; frho = NULL; rhor = NULL; z2r = NULL; scale = NULL; frho_spline = NULL; rhor_spline = NULL; z2r_spline = NULL; // set comm size needed by this Pair comm_forward = 1; comm_reverse = 1; } /* ---------------------------------------------------------------------- check if allocated, since class can be destructed when incomplete ------------------------------------------------------------------------- */ PairEAM::~PairEAM() { if (copymode) return; memory->destroy(rho); memory->destroy(fp); if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); delete [] map; delete [] type2frho; map = NULL; type2frho = NULL; memory->destroy(type2rhor); memory->destroy(type2z2r); memory->destroy(scale); } if (funcfl) { for (int i = 0; i < nfuncfl; i++) { delete [] funcfl[i].file; memory->destroy(funcfl[i].frho); memory->destroy(funcfl[i].rhor); memory->destroy(funcfl[i].zr); } memory->sfree(funcfl); funcfl = NULL; } if (setfl) { for (int i = 0; i < setfl->nelements; i++) delete [] setfl->elements[i]; delete [] setfl->elements; delete [] setfl->mass; memory->destroy(setfl->frho); memory->destroy(setfl->rhor); memory->destroy(setfl->z2r); delete setfl; setfl = NULL; } if (fs) { for (int i = 0; i < fs->nelements; i++) delete [] fs->elements[i]; delete [] fs->elements; delete [] fs->mass; memory->destroy(fs->frho); memory->destroy(fs->rhor); memory->destroy(fs->z2r); delete fs; fs = NULL; } memory->destroy(frho); memory->destroy(rhor); memory->destroy(z2r); memory->destroy(frho_spline); memory->destroy(rhor_spline); memory->destroy(z2r_spline); } /* ---------------------------------------------------------------------- */ void PairEAM::compute(int eflag, int vflag) { int i,j,ii,jj,m,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair; double rsq,r,p,rhoip,rhojp,z2,z2p,recip,phip,psip,phi; double *coeff; int *ilist,*jlist,*numneigh,**firstneigh; evdwl = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = eflag_global = eflag_atom = 0; // grow energy and fp arrays if necessary // need to be atom->nmax in length if (atom->nmax > nmax) { memory->destroy(rho); memory->destroy(fp); nmax = atom->nmax; memory->create(rho,nmax,"pair:rho"); memory->create(fp,nmax,"pair:fp"); } double **x = atom->x; double **f = atom->f; int *type = atom->type; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; int newton_pair = force->newton_pair; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // zero out density if (newton_pair) { for (i = 0; i < nall; i++) rho[i] = 0.0; } else for (i = 0; i < nlocal; i++) rho[i] = 0.0; // rho = density at each atom // 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; if (rsq < cutforcesq) { jtype = type[j]; p = sqrt(rsq)*rdr + 1.0; m = static_cast (p); m = MIN(m,nr-1); p -= m; p = MIN(p,1.0); coeff = rhor_spline[type2rhor[jtype][itype]][m]; rho[i] += ((coeff[3]*p + coeff[4])*p + coeff[5])*p + coeff[6]; if (newton_pair || j < nlocal) { coeff = rhor_spline[type2rhor[itype][jtype]][m]; rho[j] += ((coeff[3]*p + coeff[4])*p + coeff[5])*p + coeff[6]; } } } } // communicate and sum densities if (newton_pair) comm->reverse_comm_pair(this); // fp = derivative of embedding energy at each atom // phi = embedding energy at each atom // if rho > rhomax (e.g. due to close approach of two atoms), // will exceed table, so add linear term to conserve energy for (ii = 0; ii < inum; ii++) { i = ilist[ii]; p = rho[i]*rdrho + 1.0; m = static_cast (p); m = MAX(1,MIN(m,nrho-1)); p -= m; p = MIN(p,1.0); coeff = frho_spline[type2frho[type[i]]][m]; fp[i] = (coeff[0]*p + coeff[1])*p + coeff[2]; if (eflag) { phi = ((coeff[3]*p + coeff[4])*p + coeff[5])*p + coeff[6]; if (rho[i] > rhomax) phi += fp[i] * (rho[i]-rhomax); phi *= scale[type[i]][type[i]]; if (eflag_global) eng_vdwl += phi; if (eflag_atom) eatom[i] += phi; } } // communicate derivative of embedding function comm->forward_comm_pair(this); // compute forces on each atom // 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; if (rsq < cutforcesq) { jtype = type[j]; r = sqrt(rsq); p = r*rdr + 1.0; m = static_cast (p); m = MIN(m,nr-1); p -= m; p = MIN(p,1.0); // rhoip = derivative of (density at atom j due to atom i) // rhojp = derivative of (density at atom i due to atom j) // phi = pair potential energy // phip = phi' // z2 = phi * r // z2p = (phi * r)' = (phi' r) + phi // psip needs both fp[i] and fp[j] terms since r_ij appears in two // terms of embed eng: Fi(sum rho_ij) and Fj(sum rho_ji) // hence embed' = Fi(sum rho_ij) rhojp + Fj(sum rho_ji) rhoip // scale factor can be applied by thermodynamic integration coeff = rhor_spline[type2rhor[itype][jtype]][m]; rhoip = (coeff[0]*p + coeff[1])*p + coeff[2]; coeff = rhor_spline[type2rhor[jtype][itype]][m]; rhojp = (coeff[0]*p + coeff[1])*p + coeff[2]; coeff = z2r_spline[type2z2r[itype][jtype]][m]; z2p = (coeff[0]*p + coeff[1])*p + coeff[2]; z2 = ((coeff[3]*p + coeff[4])*p + coeff[5])*p + coeff[6]; recip = 1.0/r; phi = z2*recip; phip = z2p*recip - phi*recip; psip = fp[i]*rhojp + fp[j]*rhoip + phip; fpair = -scale[itype][jtype]*psip*recip; 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 = scale[itype][jtype]*phi; 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 PairEAM::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"); map = new int[n+1]; for (int i = 1; i <= n; i++) map[i] = -1; type2frho = new int[n+1]; memory->create(type2rhor,n+1,n+1,"pair:type2rhor"); memory->create(type2z2r,n+1,n+1,"pair:type2z2r"); memory->create(scale,n+1,n+1,"pair:scale"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairEAM::settings(int narg, char **arg) { if (narg > 0) error->all(FLERR,"Illegal pair_style command"); } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs read DYNAMO funcfl file ------------------------------------------------------------------------- */ void PairEAM::coeff(int narg, char **arg) { if (!allocated) allocate(); if (narg != 3) error->all(FLERR,"Incorrect args for pair coefficients"); // parse pair of atom types int ilo,ihi,jlo,jhi; - force->bounds(arg[0],atom->ntypes,ilo,ihi); - force->bounds(arg[1],atom->ntypes,jlo,jhi); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); // read funcfl file if hasn't already been read // store filename in Funcfl data struct int ifuncfl; for (ifuncfl = 0; ifuncfl < nfuncfl; ifuncfl++) if (strcmp(arg[2],funcfl[ifuncfl].file) == 0) break; if (ifuncfl == nfuncfl) { nfuncfl++; funcfl = (Funcfl *) memory->srealloc(funcfl,nfuncfl*sizeof(Funcfl),"pair:funcfl"); read_file(arg[2]); int n = strlen(arg[2]) + 1; funcfl[ifuncfl].file = new char[n]; strcpy(funcfl[ifuncfl].file,arg[2]); } // set setflag and map only for i,i type pairs // set mass of atom type if i = j int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { if (i == j) { setflag[i][i] = 1; map[i] = ifuncfl; atom->set_mass(i,funcfl[ifuncfl].mass); count++; } scale[i][j] = 1.0; } } if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairEAM::init_style() { // convert read-in file(s) to arrays and spline them file2array(); array2spline(); neighbor->request(this,instance_me); } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairEAM::init_one(int i, int j) { // single global cutoff = max of cut from all files read in // for funcfl could be multiple files // for setfl or fs, just one file scale[j][i] = scale[i][j]; if (funcfl) { cutmax = 0.0; for (int m = 0; m < nfuncfl; m++) cutmax = MAX(cutmax,funcfl[m].cut); } else if (setfl) cutmax = setfl->cut; else if (fs) cutmax = fs->cut; cutforcesq = cutmax*cutmax; return cutmax; } /* ---------------------------------------------------------------------- read potential values from a DYNAMO single element funcfl file ------------------------------------------------------------------------- */ void PairEAM::read_file(char *filename) { Funcfl *file = &funcfl[nfuncfl-1]; int me = comm->me; FILE *fptr; char line[MAXLINE]; if (me == 0) { fptr = force->open_potential(filename); if (fptr == NULL) { char str[128]; sprintf(str,"Cannot open EAM potential file %s",filename); error->one(FLERR,str); } } int tmp; if (me == 0) { fgets(line,MAXLINE,fptr); fgets(line,MAXLINE,fptr); sscanf(line,"%d %lg",&tmp,&file->mass); fgets(line,MAXLINE,fptr); sscanf(line,"%d %lg %d %lg %lg", &file->nrho,&file->drho,&file->nr,&file->dr,&file->cut); } MPI_Bcast(&file->mass,1,MPI_DOUBLE,0,world); MPI_Bcast(&file->nrho,1,MPI_INT,0,world); MPI_Bcast(&file->drho,1,MPI_DOUBLE,0,world); MPI_Bcast(&file->nr,1,MPI_INT,0,world); MPI_Bcast(&file->dr,1,MPI_DOUBLE,0,world); MPI_Bcast(&file->cut,1,MPI_DOUBLE,0,world); memory->create(file->frho,(file->nrho+1),"pair:frho"); memory->create(file->rhor,(file->nr+1),"pair:rhor"); memory->create(file->zr,(file->nr+1),"pair:zr"); if (me == 0) grab(fptr,file->nrho,&file->frho[1]); MPI_Bcast(&file->frho[1],file->nrho,MPI_DOUBLE,0,world); if (me == 0) grab(fptr,file->nr,&file->zr[1]); MPI_Bcast(&file->zr[1],file->nr,MPI_DOUBLE,0,world); if (me == 0) grab(fptr,file->nr,&file->rhor[1]); MPI_Bcast(&file->rhor[1],file->nr,MPI_DOUBLE,0,world); if (me == 0) fclose(fptr); } /* ---------------------------------------------------------------------- convert read-in funcfl potential(s) to standard array format interpolate all file values to a single grid and cutoff ------------------------------------------------------------------------- */ void PairEAM::file2array() { int i,j,k,m,n; int ntypes = atom->ntypes; double sixth = 1.0/6.0; // determine max function params from all active funcfl files // active means some element is pointing at it via map int active; double rmax; dr = drho = rmax = rhomax = 0.0; for (int i = 0; i < nfuncfl; i++) { active = 0; for (j = 1; j <= ntypes; j++) if (map[j] == i) active = 1; if (active == 0) continue; Funcfl *file = &funcfl[i]; dr = MAX(dr,file->dr); drho = MAX(drho,file->drho); rmax = MAX(rmax,(file->nr-1) * file->dr); rhomax = MAX(rhomax,(file->nrho-1) * file->drho); } // set nr,nrho from cutoff and spacings // 0.5 is for round-off in divide nr = static_cast (rmax/dr + 0.5); nrho = static_cast (rhomax/drho + 0.5); // ------------------------------------------------------------------ // setup frho arrays // ------------------------------------------------------------------ // allocate frho arrays // nfrho = # of funcfl files + 1 for zero array nfrho = nfuncfl + 1; memory->destroy(frho); memory->create(frho,nfrho,nrho+1,"pair:frho"); // interpolate each file's frho to a single grid and cutoff double r,p,cof1,cof2,cof3,cof4; n = 0; for (i = 0; i < nfuncfl; i++) { Funcfl *file = &funcfl[i]; for (m = 1; m <= nrho; m++) { r = (m-1)*drho; p = r/file->drho + 1.0; k = static_cast (p); k = MIN(k,file->nrho-2); k = MAX(k,2); p -= k; p = MIN(p,2.0); cof1 = -sixth*p*(p-1.0)*(p-2.0); cof2 = 0.5*(p*p-1.0)*(p-2.0); cof3 = -0.5*p*(p+1.0)*(p-2.0); cof4 = sixth*p*(p*p-1.0); frho[n][m] = cof1*file->frho[k-1] + cof2*file->frho[k] + cof3*file->frho[k+1] + cof4*file->frho[k+2]; } n++; } // add extra frho of zeroes for non-EAM types to point to (pair hybrid) // this is necessary b/c fp is still computed for non-EAM atoms for (m = 1; m <= nrho; m++) frho[nfrho-1][m] = 0.0; // type2frho[i] = which frho array (0 to nfrho-1) each atom type maps to // if atom type doesn't point to file (non-EAM atom in pair hybrid) // then map it to last frho array of zeroes for (i = 1; i <= ntypes; i++) if (map[i] >= 0) type2frho[i] = map[i]; else type2frho[i] = nfrho-1; // ------------------------------------------------------------------ // setup rhor arrays // ------------------------------------------------------------------ // allocate rhor arrays // nrhor = # of funcfl files nrhor = nfuncfl; memory->destroy(rhor); memory->create(rhor,nrhor,nr+1,"pair:rhor"); // interpolate each file's rhor to a single grid and cutoff n = 0; for (i = 0; i < nfuncfl; i++) { Funcfl *file = &funcfl[i]; for (m = 1; m <= nr; m++) { r = (m-1)*dr; p = r/file->dr + 1.0; k = static_cast (p); k = MIN(k,file->nr-2); k = MAX(k,2); p -= k; p = MIN(p,2.0); cof1 = -sixth*p*(p-1.0)*(p-2.0); cof2 = 0.5*(p*p-1.0)*(p-2.0); cof3 = -0.5*p*(p+1.0)*(p-2.0); cof4 = sixth*p*(p*p-1.0); rhor[n][m] = cof1*file->rhor[k-1] + cof2*file->rhor[k] + cof3*file->rhor[k+1] + cof4*file->rhor[k+2]; } n++; } // type2rhor[i][j] = which rhor array (0 to nrhor-1) each type pair maps to // for funcfl files, I,J mapping only depends on I // OK if map = -1 (non-EAM atom in pair hybrid) b/c type2rhor not used for (i = 1; i <= ntypes; i++) for (j = 1; j <= ntypes; j++) type2rhor[i][j] = map[i]; // ------------------------------------------------------------------ // setup z2r arrays // ------------------------------------------------------------------ // allocate z2r arrays // nz2r = N*(N+1)/2 where N = # of funcfl files nz2r = nfuncfl*(nfuncfl+1)/2; memory->destroy(z2r); memory->create(z2r,nz2r,nr+1,"pair:z2r"); // create a z2r array for each file against other files, only for I >= J // interpolate zri and zrj to a single grid and cutoff double zri,zrj; n = 0; for (i = 0; i < nfuncfl; i++) { Funcfl *ifile = &funcfl[i]; for (j = 0; j <= i; j++) { Funcfl *jfile = &funcfl[j]; for (m = 1; m <= nr; m++) { r = (m-1)*dr; p = r/ifile->dr + 1.0; k = static_cast (p); k = MIN(k,ifile->nr-2); k = MAX(k,2); p -= k; p = MIN(p,2.0); cof1 = -sixth*p*(p-1.0)*(p-2.0); cof2 = 0.5*(p*p-1.0)*(p-2.0); cof3 = -0.5*p*(p+1.0)*(p-2.0); cof4 = sixth*p*(p*p-1.0); zri = cof1*ifile->zr[k-1] + cof2*ifile->zr[k] + cof3*ifile->zr[k+1] + cof4*ifile->zr[k+2]; p = r/jfile->dr + 1.0; k = static_cast (p); k = MIN(k,jfile->nr-2); k = MAX(k,2); p -= k; p = MIN(p,2.0); cof1 = -sixth*p*(p-1.0)*(p-2.0); cof2 = 0.5*(p*p-1.0)*(p-2.0); cof3 = -0.5*p*(p+1.0)*(p-2.0); cof4 = sixth*p*(p*p-1.0); zrj = cof1*jfile->zr[k-1] + cof2*jfile->zr[k] + cof3*jfile->zr[k+1] + cof4*jfile->zr[k+2]; z2r[n][m] = 27.2*0.529 * zri*zrj; } n++; } } // type2z2r[i][j] = which z2r array (0 to nz2r-1) each type pair maps to // set of z2r arrays only fill lower triangular Nelement matrix // value = n = sum over rows of lower-triangular matrix until reach irow,icol // swap indices when irow < icol to stay lower triangular // if map = -1 (non-EAM atom in pair hybrid): // type2z2r is not used by non-opt // but set type2z2r to 0 since accessed by opt int irow,icol; for (i = 1; i <= ntypes; i++) { for (j = 1; j <= ntypes; j++) { irow = map[i]; icol = map[j]; if (irow == -1 || icol == -1) { type2z2r[i][j] = 0; continue; } if (irow < icol) { irow = map[j]; icol = map[i]; } n = 0; for (m = 0; m < irow; m++) n += m + 1; n += icol; type2z2r[i][j] = n; } } } /* ---------------------------------------------------------------------- */ void PairEAM::array2spline() { rdr = 1.0/dr; rdrho = 1.0/drho; memory->destroy(frho_spline); memory->destroy(rhor_spline); memory->destroy(z2r_spline); memory->create(frho_spline,nfrho,nrho+1,7,"pair:frho"); memory->create(rhor_spline,nrhor,nr+1,7,"pair:rhor"); memory->create(z2r_spline,nz2r,nr+1,7,"pair:z2r"); for (int i = 0; i < nfrho; i++) interpolate(nrho,drho,frho[i],frho_spline[i]); for (int i = 0; i < nrhor; i++) interpolate(nr,dr,rhor[i],rhor_spline[i]); for (int i = 0; i < nz2r; i++) interpolate(nr,dr,z2r[i],z2r_spline[i]); } /* ---------------------------------------------------------------------- */ void PairEAM::interpolate(int n, double delta, double *f, double **spline) { for (int m = 1; m <= n; m++) spline[m][6] = f[m]; spline[1][5] = spline[2][6] - spline[1][6]; spline[2][5] = 0.5 * (spline[3][6]-spline[1][6]); spline[n-1][5] = 0.5 * (spline[n][6]-spline[n-2][6]); spline[n][5] = spline[n][6] - spline[n-1][6]; for (int m = 3; m <= n-2; m++) spline[m][5] = ((spline[m-2][6]-spline[m+2][6]) + 8.0*(spline[m+1][6]-spline[m-1][6])) / 12.0; for (int m = 1; m <= n-1; m++) { spline[m][4] = 3.0*(spline[m+1][6]-spline[m][6]) - 2.0*spline[m][5] - spline[m+1][5]; spline[m][3] = spline[m][5] + spline[m+1][5] - 2.0*(spline[m+1][6]-spline[m][6]); } spline[n][4] = 0.0; spline[n][3] = 0.0; for (int m = 1; m <= n; m++) { spline[m][2] = spline[m][5]/delta; spline[m][1] = 2.0*spline[m][4]/delta; spline[m][0] = 3.0*spline[m][3]/delta; } } /* ---------------------------------------------------------------------- grab n values from file fp and put them in list values can be several to a line only called by proc 0 ------------------------------------------------------------------------- */ void PairEAM::grab(FILE *fptr, int n, double *list) { char *ptr; char line[MAXLINE]; int i = 0; while (i < n) { fgets(line,MAXLINE,fptr); ptr = strtok(line," \t\n\r\f"); list[i++] = atof(ptr); while ((ptr = strtok(NULL," \t\n\r\f"))) list[i++] = atof(ptr); } } /* ---------------------------------------------------------------------- */ double PairEAM::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { int m; double r,p,rhoip,rhojp,z2,z2p,recip,phi,phip,psip; double *coeff; r = sqrt(rsq); p = r*rdr + 1.0; m = static_cast (p); m = MIN(m,nr-1); p -= m; p = MIN(p,1.0); coeff = rhor_spline[type2rhor[itype][jtype]][m]; rhoip = (coeff[0]*p + coeff[1])*p + coeff[2]; coeff = rhor_spline[type2rhor[jtype][itype]][m]; rhojp = (coeff[0]*p + coeff[1])*p + coeff[2]; coeff = z2r_spline[type2z2r[itype][jtype]][m]; z2p = (coeff[0]*p + coeff[1])*p + coeff[2]; z2 = ((coeff[3]*p + coeff[4])*p + coeff[5])*p + coeff[6]; recip = 1.0/r; phi = z2*recip; phip = z2p*recip - phi*recip; psip = fp[i]*rhojp + fp[j]*rhoip + phip; fforce = -psip*recip; return phi; } /* ---------------------------------------------------------------------- */ int PairEAM::pack_forward_comm(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; m = 0; for (i = 0; i < n; i++) { j = list[i]; buf[m++] = fp[j]; } return m; } /* ---------------------------------------------------------------------- */ void PairEAM::unpack_forward_comm(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) fp[i] = buf[m++]; } /* ---------------------------------------------------------------------- */ int PairEAM::pack_reverse_comm(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) buf[m++] = rho[i]; return m; } /* ---------------------------------------------------------------------- */ void PairEAM::unpack_reverse_comm(int n, int *list, double *buf) { int i,j,m; m = 0; for (i = 0; i < n; i++) { j = list[i]; rho[j] += buf[m++]; } } /* ---------------------------------------------------------------------- memory usage of local atom-based arrays ------------------------------------------------------------------------- */ double PairEAM::memory_usage() { double bytes = maxeatom * sizeof(double); bytes += maxvatom*6 * sizeof(double); bytes += 2 * nmax * sizeof(double); return bytes; } /* ---------------------------------------------------------------------- swap fp array with one passed in by caller ------------------------------------------------------------------------- */ void PairEAM::swap_eam(double *fp_caller, double **fp_caller_hold) { double *tmp = fp; fp = fp_caller; *fp_caller_hold = tmp; } /* ---------------------------------------------------------------------- */ void *PairEAM::extract(const char *str, int &dim) { dim = 2; if (strcmp(str,"scale") == 0) return (void *) scale; return NULL; } diff --git a/src/MC/pair_dsmc.cpp b/src/MC/pair_dsmc.cpp index 7aa0237a9..344faf87f 100644 --- a/src/MC/pair_dsmc.cpp +++ b/src/MC/pair_dsmc.cpp @@ -1,523 +1,523 @@ /* ---------------------------------------------------------------------- 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: Paul Crozier (SNL) ------------------------------------------------------------------------- */ #include #include #include #include #include "pair_dsmc.h" #include "atom.h" #include "comm.h" #include "force.h" #include "memory.h" #include "error.h" #include "domain.h" #include "update.h" #include "random_mars.h" #include using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ PairDSMC::PairDSMC(LAMMPS *lmp) : Pair(lmp) { single_enable = 0; total_number_of_collisions = 0; max_particles = max_particle_list = 0; next_particle = NULL; random = NULL; } /* ---------------------------------------------------------------------- */ PairDSMC::~PairDSMC() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(sigma); memory->destroy(cut); memory->destroy(V_sigma_max); memory->destroy(particle_list); memory->destroy(first); memory->destroy(number); } delete [] next_particle; delete random; } /* ---------------------------------------------------------------------- */ void PairDSMC::compute(int eflag, int vflag) { double **x = atom->x; double *mass = atom->mass; int *type = atom->type; int nlocal = atom->nlocal; for (int i = 1; i <= atom->ntypes; ++i) for (int j = 0; j < total_ncells; ++j) { first[i][j] = -1; number[i][j] = 0; } if (atom->nmax > max_particles) { delete [] next_particle; max_particles = atom->nmax; next_particle = new int[max_particles]; } // find each particle's cell and sort by type // assume a constant volume and shape simulation domain // skip particle if outside processor domain for (int i = 0; i < nlocal; ++i) { int xcell = static_cast((x[i][0] - domain->boxlo[0])/cellx); int ycell = static_cast((x[i][1] - domain->boxlo[1])/celly); int zcell = static_cast((x[i][2] - domain->boxlo[2])/cellz); if ((xcell < 0) or (xcell > ncellsx-1) or (ycell < 0) or (ycell > ncellsy-1) or (zcell < 0) or (zcell > ncellsz-1)) continue; int icell = xcell + ycell*ncellsx + zcell*ncellsx*ncellsy; itype = type[i]; next_particle[i] = first[itype][icell]; first[itype][icell] = i; number[itype][icell]++; } for (int icell = 0; icell < total_ncells; ++icell) { for (itype = 1; itype <= atom->ntypes; ++itype) { number_of_A = number[itype][icell]; if (number_of_A > max_particle_list) { max_particle_list = number_of_A; memory->grow(particle_list,atom->ntypes+1,max_particle_list, "pair:particle_list"); } int m = first[itype][icell]; for (int k = 0; k < number_of_A; k++) { particle_list[itype][k] = m; m = next_particle[m]; } } for (itype = 1; itype <= atom->ntypes; ++itype) { imass = mass[itype]; number_of_A = number[itype][icell]; for (jtype = itype; jtype <= atom->ntypes; ++jtype) { jmass = mass[jtype]; number_of_B = number[jtype][icell]; reduced_mass = imass*jmass/(imass + jmass); total_mass = imass + jmass; jmass_tmass = jmass/total_mass; imass_tmass = imass/total_mass; // if necessary, recompute V_sigma_max values if (recompute_vsigmamax_stride && (update->ntimestep % recompute_vsigmamax_stride == 0)) recompute_V_sigma_max(icell); // # of collisions to perform for itype-jtype pairs double &Vs_max = V_sigma_max[itype][jtype]; double num_of_collisions_double = number_of_A * number_of_B * weighting * Vs_max * update->dt / vol; if ((itype == jtype) and number_of_B) num_of_collisions_double *= 0.5 * double(number_of_B - 1) / double(number_of_B); int num_of_collisions = convert_double_to_equivalent_int(num_of_collisions_double); if (num_of_collisions > number_of_A) error->warning(FLERR,"Pair dsmc: num_of_collisions > number_of_A",0); if (num_of_collisions > number_of_B) error->warning(FLERR,"Pair dsmc: num_of_collisions > number_of_B",0); // perform collisions on pairs of particles in icell for (int k = 0; k < num_of_collisions; k++) { if ((number_of_A < 1) or (number_of_B < 1)) break; if ((itype == jtype) and (number_of_A < 2)) break; int ith_A = static_cast(random->uniform()*number_of_A); int jth_B = static_cast(random->uniform()*number_of_B); int i = particle_list[itype][ith_A]; int j = particle_list[jtype][jth_B]; if (i == j) { k--; continue; } double probability = V_sigma(i,j)/Vs_max; if (probability > random->uniform()) scatter_random(i,j,icell); } } } } } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairDSMC::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(sigma,n+1,n+1,"pair:sigma"); memory->create(V_sigma_max,n+1,n+1,"pair:V_sigma_max"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairDSMC::settings(int narg, char **arg) { if (narg != 6) error->all(FLERR,"Illegal pair_style command"); cut_global = 0.0; max_cell_size = force->numeric(FLERR,arg[0]); seed = force->inumeric(FLERR,arg[1]); weighting = force->numeric(FLERR,arg[2]); T_ref = force->numeric(FLERR,arg[3]); recompute_vsigmamax_stride = force->inumeric(FLERR,arg[4]); vsigmamax_samples = force->inumeric(FLERR,arg[5]); // initialize Marsaglia RNG with processor-unique seed if (max_cell_size <= 0.0) error->all(FLERR,"Illegal pair_style command"); if (seed <= 0) error->all(FLERR,"Illegal pair_style command"); if (random) delete random; random = new RanMars(lmp,seed + comm->me); kT_ref = force->boltz*T_ref; // 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 PairDSMC::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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double sigma_one = force->numeric(FLERR,arg[2]); double cut_one = cut_global; if (narg == 4) cut_one = force->numeric(FLERR,arg[3]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { 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 PairDSMC::init_style() { ncellsx = ncellsy = ncellsz = 1; while (((domain->boxhi[0] - domain->boxlo[0])/ncellsx) > max_cell_size) ncellsx++; while (((domain->boxhi[1] - domain->boxlo[1])/ncellsy) > max_cell_size) ncellsy++; while (((domain->boxhi[2] - domain->boxlo[2])/ncellsz) > max_cell_size) ncellsz++; cellx = (domain->boxhi[0] - domain->boxlo[0])/ncellsx; celly = (domain->boxhi[1] - domain->boxlo[1])/ncellsy; cellz = (domain->boxhi[2] - domain->boxlo[2])/ncellsz; if (comm->me == 0) { if (screen) fprintf(screen,"DSMC cell size = %g x %g x %g\n", cellx,celly,cellz); if (logfile) fprintf(logfile,"DSMC cell size = %g x %g x %g\n", cellx,celly,cellz); } total_ncells = ncellsx*ncellsy*ncellsz; vol = cellx*celly*cellz; memory->create(particle_list,atom->ntypes+1,0,"pair:particle_list"); memory->create(first,atom->ntypes+1,total_ncells,"pair:first"); memory->create(number,atom->ntypes+1,total_ncells,"pair:number"); for (int i = 1; i <= atom->ntypes; i++) for (int j = 1; j <= atom->ntypes; j++) V_sigma_max[i][j] = 0.0; two_pi = 8.0*atan(1.0); } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairDSMC::init_one(int i, int j) { if (setflag[i][j] == 0) cut[i][j] = 0.0; return cut[i][j]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairDSMC::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(&sigma[i][j],sizeof(double),1,fp); fwrite(&cut[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairDSMC::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(&sigma[i][j],sizeof(double),1,fp); fread(&cut[i][j],sizeof(double),1,fp); } 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 PairDSMC::write_restart_settings(FILE *fp) { fwrite(&cut_global,sizeof(double),1,fp); fwrite(&max_cell_size,sizeof(double),1,fp); fwrite(&seed,sizeof(int),1,fp); fwrite(&offset_flag,sizeof(int),1,fp); fwrite(&mix_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairDSMC::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&cut_global,sizeof(double),1,fp); fread(&max_cell_size,sizeof(double),1,fp); fread(&seed,sizeof(int),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(&max_cell_size,1,MPI_DOUBLE,0,world); MPI_Bcast(&seed,1,MPI_INT,0,world); MPI_Bcast(&offset_flag,1,MPI_INT,0,world); MPI_Bcast(&mix_flag,1,MPI_INT,0,world); // initialize Marsaglia RNG with processor-unique seed // same seed that pair_style command initially specified if (random) delete random; random = new RanMars(lmp,seed + comm->me); } /*------------------------------------------------------------------------- rezero and recompute the V_sigma_max values this timestep for use during the next nrezero timesteps -------------------------------------------------------------------------*/ void PairDSMC::recompute_V_sigma_max(int icell) { int i,j,k; double Vsigma_max = 0; if (number_of_A && number_of_B) { for (k = 0; k < vsigmamax_samples; k++) { i = particle_list[itype] [static_cast(random->uniform()*number_of_A)]; j = particle_list[jtype] [static_cast(random->uniform()*number_of_B)]; if (i == j) continue; Vsigma_max = MAX(Vsigma_max,V_sigma(i,j)); } } V_sigma_max[itype][jtype] = Vsigma_max; } /*------------------------------------------------------------------------- VHS model compute the velocity vector difference between i and j and multiply by their combined collision cross section, sigma, for neutral-neutral collisions using the Variable Hard Sphere model -------------------------------------------------------------------------*/ double PairDSMC::V_sigma(int i, int j) { double relative_velocity_sq,relative_velocity,pair_sigma; double delv[3]; double *vi = atom->v[i]; double *vj = atom->v[j]; subtract3d(vi,vj,delv); relative_velocity_sq = dot3d(delv,delv); relative_velocity = sqrt(relative_velocity_sq); // from Bird eq 4.63, and omega=0.67 // (omega - 0.5) = 0.17 // 1/GAMMA(2.5 - omega) = 1.06418029298371 if (relative_velocity_sq != 0.0) pair_sigma = sigma[itype][jtype]* pow(kT_ref/(0.5*reduced_mass*relative_velocity_sq),0.17) * 1.06418029298371; else pair_sigma = 0.0; return relative_velocity*pair_sigma; } /*------------------------------------------------------------------------- generate new velocities for collided particles -------------------------------------------------------------------------*/ void PairDSMC::scatter_random(int i, int j, int icell) { double mag_delv,cos_phi,cos_squared,r,theta; double delv[3],vcm[3]; double *vi = atom->v[i]; double *vj = atom->v[j]; subtract3d(vi,vj,delv); if (itype == jtype) mag_delv = sqrt(dot3d(delv,delv))*0.5; else mag_delv = sqrt(dot3d(delv,delv)); cos_phi = 1.0 - (2.0*random->uniform()); cos_squared = MIN(1.0,cos_phi*cos_phi); r = sqrt(1.0 - cos_squared); delv[0] = cos_phi*mag_delv; theta = two_pi*random->uniform(); delv[1] = r*mag_delv*cos(theta); delv[2] = r*mag_delv*sin(theta); if (itype == jtype) { vcm[0] = (vi[0]+vj[0])*0.5; vcm[1] = (vi[1]+vj[1])*0.5; vcm[2] = (vi[2]+vj[2])*0.5; vi[0] = vcm[0] + delv[0]; vi[1] = vcm[1] + delv[1]; vi[2] = vcm[2] + delv[2]; vj[0] = vcm[0] - delv[0]; vj[1] = vcm[1] - delv[1]; vj[2] = vcm[2] - delv[2]; } else { vcm[0] = vi[0]*imass_tmass + vj[0]*jmass_tmass; vcm[1] = vi[1]*imass_tmass + vj[1]*jmass_tmass; vcm[2] = vi[2]*imass_tmass + vj[2]*jmass_tmass; vi[0] = vcm[0] + delv[0]*jmass_tmass; vi[1] = vcm[1] + delv[1]*jmass_tmass; vi[2] = vcm[2] + delv[2]*jmass_tmass; vj[0] = vcm[0] - delv[0]*imass_tmass; vj[1] = vcm[1] - delv[1]*imass_tmass; vj[2] = vcm[2] - delv[2]*imass_tmass; } total_number_of_collisions++; } /* ---------------------------------------------------------------------- This method converts the double supplied by the calling function into an int, which is returned. By adding a random number between 0 and 1 to the double before converting it to an int, we ensure that, statistically, we round down with probability identical to the remainder and up the rest of the time. So even though we're using an integer, we're statistically matching the exact expression represented by the double. ------------------------------------------------------------------------- */ int PairDSMC::convert_double_to_equivalent_int(double input_double) { if (input_double > INT_MAX) error->all(FLERR,"Tried to convert a double to int, but input_double > INT_MAX"); int output_int = static_cast(input_double + random->uniform()); return output_int; } diff --git a/src/MISC/compute_ti.cpp b/src/MISC/compute_ti.cpp index 02f160850..eca136c93 100644 --- a/src/MISC/compute_ti.cpp +++ b/src/MISC/compute_ti.cpp @@ -1,230 +1,230 @@ /* ---------------------------------------------------------------------- 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 (University of Notre Dame) ------------------------------------------------------------------------- */ #include #include "atom.h" #include #include "compute_ti.h" #include "update.h" #include "modify.h" #include "domain.h" #include "force.h" #include "pair.h" #include "kspace.h" #include "input.h" #include "variable.h" #include "error.h" using namespace LAMMPS_NS; enum{PAIR,TAIL,KSPACE}; /* ---------------------------------------------------------------------- */ ComputeTI::ComputeTI(LAMMPS *lmp, int narg, char **arg) : Compute(lmp, narg, arg) { if (narg < 4) error->all(FLERR,"Illegal compute ti command"); peflag = 1; peratom_flag = 1; peatomflag = 1; scalar_flag = 1; extscalar = 1; timeflag = 1; // terms come in triplets // changed to quadruplets to include atom type nterms = (narg-3) / 4; if (narg != 4*nterms + 3) error->all(FLERR,"Illegal compute ti command"); which = new int[nterms]; ivar1 = new int[nterms]; ivar2 = new int[nterms]; ilo = new int[nterms]; ihi = new int[nterms]; var1 = new char*[nterms]; var2 = new char*[nterms]; pptr = new Pair*[nterms]; pstyle = new char*[nterms]; for (int m = 0; m < nterms; m++) pstyle[m] = NULL; // parse keywords nterms = 0; int iarg = 3; while (iarg < narg) { if (iarg+4 > narg) error->all(FLERR,"Illegal compute ti command"); if (strcmp(arg[iarg],"kspace") == 0) which[nterms] = KSPACE; else if (strcmp(arg[iarg],"tail") == 0) which[nterms] = TAIL; else which[nterms] = PAIR; int n = strlen(arg[iarg]) + 1; pstyle[nterms] = new char[n]; strcpy(pstyle[nterms],arg[iarg]); - force->bounds(arg[iarg+1],atom->ntypes,ilo[nterms],ihi[nterms]); + force->bounds(FLERR,arg[iarg+1],atom->ntypes,ilo[nterms],ihi[nterms]); iarg += 1; if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) { int n = strlen(&arg[iarg+1][2]) + 1; var1[nterms] = new char[n]; strcpy(var1[nterms],&arg[iarg+1][2]); } else error->all(FLERR,"Illegal compute ti command"); if (strstr(arg[iarg+2],"v_") == arg[iarg+2]) { int n = strlen(&arg[iarg+2][2]) + 1; var2[nterms] = new char[n]; strcpy(var2[nterms],&arg[iarg+2][2]); } else error->all(FLERR,"Illegal compute ti command"); nterms++; iarg += 3; } } /* --------------------------------------------------------------------- */ ComputeTI::~ComputeTI() { for (int m = 0; m < nterms; m++) { delete [] var1[m]; delete [] var2[m]; delete [] pstyle[m]; } delete [] which; delete [] ivar1; delete [] ivar2; delete [] var1; delete [] var2; delete [] ilo; delete [] ihi; delete [] pptr; delete [] pstyle; } /* --------------------------------------------------------------------- */ void ComputeTI::init() { // setup and error checks for (int m = 0; m < nterms; m++) { ivar1[m] = input->variable->find(var1[m]); ivar2[m] = input->variable->find(var2[m]); if (ivar1[m] < 0 || ivar2[m] < 0) error->all(FLERR,"Variable name for compute ti does not exist"); if (!input->variable->equalstyle(ivar1[m]) || !input->variable->equalstyle(ivar2[m])) error->all(FLERR,"Variable for compute ti is invalid style"); if (which[m] == PAIR) { pptr[m] = force->pair_match(pstyle[m],1); if (pptr[m] == NULL) error->all(FLERR,"Compute ti pair style does not exist"); } else if (which[m] == TAIL) { if (force->pair == NULL || force->pair->tail_flag == 0) error->all(FLERR,"Compute ti tail when pair style does not " "compute tail corrections"); } else if (which[m] == KSPACE) { if (force->kspace == NULL) error->all(FLERR,"Compute ti kspace style does not exist"); } } } /* --------------------------------------------------------------------- */ double ComputeTI::compute_scalar() { double eng,engall,value1,value2; invoked_scalar = update->ntimestep; if (update->eflag_global != invoked_scalar) error->all(FLERR,"Energy was not tallied on needed timestep"); const int nlocal = atom->nlocal; const int * const type = atom->type; double dUdl = 0.0; for (int m = 0; m < nterms; m++) { int total_flag = 0; if ((ihi[m]-ilo[m])==atom->ntypes) total_flag = 1; eng = 0.0; value1 = input->variable->compute_equal(ivar1[m]); value2 = input->variable->compute_equal(ivar2[m]); if (value1 == 0.0) continue; if (which[m] == PAIR) { if (total_flag) { eng = pptr[m]->eng_vdwl + pptr[m]->eng_coul; MPI_Allreduce(&eng,&engall,1,MPI_DOUBLE,MPI_SUM,world); } else { int npair = nlocal; double *eatom = pptr[m]->eatom; if (force->newton_pair) npair += atom->nghost; for (int i = 0; i < npair; i++) if ((ilo[m]<=type[i])&(ihi[m]>=type[i])) eng += eatom[i]; MPI_Allreduce(&eng,&engall,1,MPI_DOUBLE,MPI_SUM,world); } dUdl += engall/value1 * value2; } else if (which[m] == TAIL) { double vol = domain->xprd*domain->yprd*domain->zprd; if (total_flag) eng = force->pair->etail / vol; else { eng = 0; for (int it = 1; it <= atom->ntypes; it++) { int jt; if ((it >= ilo[m])&&(it <=ihi[m])) jt = it; else jt = ilo[m]; for (; jt <=ihi[m];jt++) { if ((force->pair->tail_flag)&&(force->pair->setflag[it][jt])) { force->pair->init_one(it,jt); eng += force->pair->etail_ij; } if (it !=jt) eng += force->pair->etail_ij; } } eng /= vol; } dUdl += eng/value1 * value2; } else if (which[m] == KSPACE) { if (total_flag) eng = force->kspace->energy; else { double *eatom = force->kspace->eatom; for(int i = 0; i < nlocal; i++) if ((ilo[m]<=type[i])&(ihi[m]>=type[i])) eng += eatom[i]; MPI_Allreduce(&eng,&engall,1,MPI_DOUBLE,MPI_SUM,world); eng = engall; } dUdl += eng/value1 * value2; } } scalar = dUdl; return scalar; } diff --git a/src/MISC/pair_nm_cut.cpp b/src/MISC/pair_nm_cut.cpp index f0c9806fb..467be1b7b 100644 --- a/src/MISC/pair_nm_cut.cpp +++ b/src/MISC/pair_nm_cut.cpp @@ -1,433 +1,433 @@ /* ---------------------------------------------------------------------- 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: Julien Devemy (ICCF) ------------------------------------------------------------------------- */ #include #include #include #include #include "pair_nm_cut.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; /* ---------------------------------------------------------------------- */ PairNMCut::PairNMCut(LAMMPS *lmp) : Pair(lmp) { writedata = 1; } /* ---------------------------------------------------------------------- */ PairNMCut::~PairNMCut() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut); memory->destroy(e0); memory->destroy(r0); memory->destroy(nn); memory->destroy(mm); memory->destroy(nm); memory->destroy(e0nm); memory->destroy(r0n); memory->destroy(r0m); memory->destroy(offset); } } /* ---------------------------------------------------------------------- */ void PairNMCut::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,factor_lj; double r,forcenm,rminv,rninv; 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; r = sqrt(rsq); rminv = pow(r2inv,mm[itype][jtype]/2.0); rninv = pow(r2inv,nn[itype][jtype]/2.0); forcenm = e0nm[itype][jtype]*nm[itype][jtype] * (r0n[itype][jtype]/pow(r,nn[itype][jtype]) - r0m[itype][jtype]/pow(r,mm[itype][jtype])); fpair = factor_lj*forcenm*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 = e0nm[itype][jtype] * (mm[itype][jtype]*r0n[itype][jtype]*rninv - nn[itype][jtype]*r0m[itype][jtype]*rminv) - 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 PairNMCut::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(e0,n+1,n+1,"pair:e0"); memory->create(r0,n+1,n+1,"pair:r0"); memory->create(nn,n+1,n+1,"pair:nn"); memory->create(mm,n+1,n+1,"pair:mm"); memory->create(nm,n+1,n+1,"pair:nm"); memory->create(e0nm,n+1,n+1,"pair:e0nm"); memory->create(r0n,n+1,n+1,"pair:r0n"); memory->create(r0m,n+1,n+1,"pair:r0m"); memory->create(offset,n+1,n+1,"pair:offset"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairNMCut::settings(int narg, char **arg) { if (narg != 1) error->all(FLERR,"Illegal pair_style command"); cut_global = force->numeric(FLERR,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 PairNMCut::coeff(int narg, char **arg) { if (narg < 6 || narg > 7) 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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double e0_one = force->numeric(FLERR,arg[2]); double r0_one = force->numeric(FLERR,arg[3]); double nn_one = force->numeric(FLERR,arg[4]); double mm_one = force->numeric(FLERR,arg[5]); double cut_one = cut_global; if (narg == 7) cut_one = force->numeric(FLERR,arg[6]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { e0[i][j] = e0_one; r0[i][j] = r0_one; nn[i][j] = nn_one; mm[i][j] = mm_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 PairNMCut::init_one(int i, int j) { if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set"); nm[i][j] = nn[i][j]*mm[i][j]; e0nm[i][j] = e0[i][j]/(nn[i][j]-mm[i][j]); r0n[i][j] = pow(r0[i][j],nn[i][j]); r0m[i][j] = pow(r0[i][j],mm[i][j]); if (offset_flag) { offset[i][j] = e0nm[i][j] * ((mm[i][j]*r0n[i][j] / pow(cut[i][j],nn[i][j])) - (nn[i][j]*r0m[i][j] / pow(cut[i][j],mm[i][j]))); } else offset[i][j] = 0.0; e0[j][i] = e0[i][j]; nn[j][i] = nn[i][j]; mm[j][i] = mm[i][j]; nm[j][i] = nm[i][j]; r0[j][i] = r0[i][j]; e0nm[j][i] = e0nm[i][j]; r0n[j][i] = r0n[i][j]; r0m[j][i] = r0m[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 rr1 = mm[i][j]*(nn[i][j]-1)*pow(r0[i][j],nn[i][j]); double rr2 = nn[i][j]*(mm[i][j]-1)*pow(r0[i][j],mm[i][j]); double p1 = 1-nn[i][j]; double p2 = 1-mm[i][j]; double rrr1 = pow(r0[i][j],nn[i][j])*(1-nn[i][j]); double rrr2 = pow(r0[i][j],mm[i][j])*(1-mm[i][j]); etail_ij = 2.0*MY_PI*all[0]*all[1]*e0nm[i][j] * (rr1*pow(cut[i][j],p1)-rr2*pow(cut[i][j],p2)); ptail_ij = 2.0*MY_PI*all[0]*all[1]*e0nm[i][j] * nn[i][j]*mm[i][j]*(rrr1*pow(cut[i][j],p1)-rrr2*pow(cut[i][j],p2)); } return cut[i][j]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairNMCut::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(&e0[i][j],sizeof(double),1,fp); fwrite(&r0[i][j],sizeof(double),1,fp); fwrite(&nn[i][j],sizeof(double),1,fp); fwrite(&mm[i][j],sizeof(double),1,fp); fwrite(&cut[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairNMCut::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(&e0[i][j],sizeof(double),1,fp); fread(&r0[i][j],sizeof(double),1,fp); fread(&nn[i][j],sizeof(double),1,fp); fread(&mm[i][j],sizeof(double),1,fp); fread(&cut[i][j],sizeof(double),1,fp); } MPI_Bcast(&e0[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&r0[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&nn[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&mm[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairNMCut::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); fwrite(&tail_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairNMCut::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); fread(&tail_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); MPI_Bcast(&tail_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void PairNMCut::write_data(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) fprintf(fp,"%d %g %g %g %g\n",i,e0[i][i],r0[i][i],nn[i][i],mm[i][i]); } /* ---------------------------------------------------------------------- proc 0 writes all pairs to data file ------------------------------------------------------------------------- */ void PairNMCut::write_data_all(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) fprintf(fp,"%d %d %g %g %g %g %g\n",i,j, e0[i][j],r0[i][j],nn[i][j],mm[i][j],cut[i][j]); } /* ---------------------------------------------------------------------- */ double PairNMCut::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r2inv,r,forcenm,phinm; r2inv = 1.0/rsq; r = sqrt(rsq); forcenm = e0nm[itype][jtype]*nm[itype][jtype] * (r0n[itype][jtype]/pow(r,nn[itype][jtype]) - r0m[itype][jtype]/pow(r,mm[itype][jtype])); fforce = factor_lj*forcenm*r2inv; phinm = e0nm[itype][jtype] * (mm[itype][jtype] * r0n[itype][jtype]/pow(r,nn[itype][jtype]) - nn[itype][jtype]*r0m[itype][jtype] /pow(r,mm[itype][jtype])) - offset[itype][jtype]; return factor_lj*phinm; } /* ---------------------------------------------------------------------- */ void *PairNMCut::extract(const char *str, int &dim) { dim = 2; if (strcmp(str,"e0") == 0) return (void *) e0; if (strcmp(str,"r0") == 0) return (void *) r0; if (strcmp(str,"nn") == 0) return (void *) nn; if (strcmp(str,"mm") == 0) return (void *) mm; return NULL; } diff --git a/src/MISC/pair_nm_cut_coul_cut.cpp b/src/MISC/pair_nm_cut_coul_cut.cpp index 61326ee1e..86fa09f17 100644 --- a/src/MISC/pair_nm_cut_coul_cut.cpp +++ b/src/MISC/pair_nm_cut_coul_cut.cpp @@ -1,506 +1,506 @@ /* ---------------------------------------------------------------------- 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: Julien Devemy (ICCF) ------------------------------------------------------------------------- */ #include #include #include #include #include "pair_nm_cut_coul_cut.h" #include "atom.h" #include "comm.h" #include "force.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; /* ---------------------------------------------------------------------- */ PairNMCutCoulCut::PairNMCutCoulCut(LAMMPS *lmp) : Pair(lmp) { writedata = 1; } /* ---------------------------------------------------------------------- */ PairNMCutCoulCut::~PairNMCutCoulCut() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut_lj); memory->destroy(cut_ljsq); memory->destroy(cut_coul); memory->destroy(cut_coulsq); memory->destroy(e0); memory->destroy(r0); memory->destroy(nn); memory->destroy(mm); memory->destroy(nm); memory->destroy(e0nm); memory->destroy(r0n); memory->destroy(r0m); memory->destroy(offset); } } /* ---------------------------------------------------------------------- */ void PairNMCutCoulCut::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,factor_coul,factor_lj; double r,forcecoul,forcenm,rminv,rninv; 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[itype][jtype]) forcecoul = qqrd2e * qtmp*q[j]*sqrt(r2inv); else forcecoul = 0.0; if (rsq < cut_ljsq[itype][jtype]) { r = sqrt(rsq); rminv = pow(r2inv,mm[itype][jtype]/2.0); rninv = pow(r2inv,nn[itype][jtype]/2.0); forcenm = e0nm[itype][jtype]*nm[itype][jtype] * (r0n[itype][jtype]/pow(r,nn[itype][jtype]) - r0m[itype][jtype]/pow(r,mm[itype][jtype])); } else forcenm = 0.0; fpair = (factor_coul*forcecoul + factor_lj*forcenm) * 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[itype][jtype]) ecoul = factor_coul * qqrd2e * qtmp*q[j]*sqrt(r2inv); else ecoul = 0.0; if (rsq < cut_ljsq[itype][jtype]) { evdwl = e0nm[itype][jtype]*(mm[itype][jtype] * r0n[itype][jtype]*rninv - nn[itype][jtype] * r0m[itype][jtype]*rminv) - 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 PairNMCutCoulCut::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(cut_coul,n+1,n+1,"pair:cut_coul"); memory->create(cut_coulsq,n+1,n+1,"pair:cut_coulsq"); memory->create(e0,n+1,n+1,"pair:e0"); memory->create(r0,n+1,n+1,"pair:r0"); memory->create(nn,n+1,n+1,"pair:nn"); memory->create(mm,n+1,n+1,"pair:mm"); memory->create(nm,n+1,n+1,"pair:nm"); memory->create(e0nm,n+1,n+1,"pair:e0nm"); memory->create(r0n,n+1,n+1,"pair:r0n"); memory->create(r0m,n+1,n+1,"pair:r0m"); memory->create(offset,n+1,n+1,"pair:offset"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairNMCutCoulCut::settings(int narg, char **arg) { if (narg < 1 || narg > 2) error->all(FLERR,"Illegal pair_style command"); cut_lj_global = force->numeric(FLERR,arg[0]); if (narg == 1) cut_coul_global = cut_lj_global; else cut_coul_global = force->numeric(FLERR,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; cut_coul[i][j] = cut_coul_global; } } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairNMCutCoulCut::coeff(int narg, char **arg) { if (narg < 6 || 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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double e0_one = force->numeric(FLERR,arg[2]); double r0_one = force->numeric(FLERR,arg[3]); double nn_one = force->numeric(FLERR,arg[4]); double mm_one = force->numeric(FLERR,arg[5]); double cut_lj_one = cut_lj_global; double cut_coul_one = cut_coul_global; if (narg >= 7) cut_coul_one = cut_lj_one = force->numeric(FLERR,arg[4]); if (narg == 8) cut_coul_one = force->numeric(FLERR,arg[5]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { e0[i][j] = e0_one; r0[i][j] = r0_one; nn[i][j] = nn_one; mm[i][j] = mm_one; cut_lj[i][j] = cut_lj_one; cut_coul[i][j] = cut_coul_one; setflag[i][j] = 1; count++; } } if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairNMCutCoulCut::init_style() { if (!atom->q_flag) error->all(FLERR,"Pair style nm/cut/coul/cut requires atom attribute q"); neighbor->request(this,instance_me); } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairNMCutCoulCut::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[i][j]); cut_ljsq[i][j] = cut_lj[i][j] * cut_lj[i][j]; cut_coulsq[i][j] = cut_coul[i][j] * cut_coul[i][j]; nm[i][j] = nn[i][j]*mm[i][j]; e0nm[i][j] = e0[i][j]/(nn[i][j]-mm[i][j]); r0n[i][j] = pow(r0[i][j],nn[i][j]); r0m[i][j] = pow(r0[i][j],mm[i][j]); if (offset_flag) { offset[i][j] = e0nm[i][j] * ((mm[i][j]*r0n[i][j] / pow(cut_lj[i][j],nn[i][j])) - (nn[i][j]*r0m[i][j] / pow(cut_lj[i][j],mm[i][j]))); } else offset[i][j] = 0.0; cut_ljsq[j][i] = cut_ljsq[i][j]; cut_coulsq[j][i] = cut_coulsq[i][j]; e0[j][i] = e0[i][j]; nn[j][i] = nn[i][j]; mm[j][i] = mm[i][j]; nm[j][i] = nm[i][j]; r0[j][i] = r0[i][j]; e0nm[j][i] = e0nm[i][j]; r0n[j][i] = r0n[i][j]; r0m[j][i] = r0m[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 rr1 = mm[i][j]*(nn[i][j]-1)*pow(r0[i][j],nn[i][j]); double rr2 = nn[i][j]*(mm[i][j]-1)*pow(r0[i][j],mm[i][j]); double p1 = 1-nn[i][j]; double p2 = 1-mm[i][j]; double rrr1 = pow(r0[i][j],nn[i][j])*(1-nn[i][j]); double rrr2 = pow(r0[i][j],mm[i][j])*(1-mm[i][j]); etail_ij = 2.0*MY_PI*all[0]*all[1]*e0nm[i][j] * (rr1*pow(cut_lj[i][j],p1)-rr2*pow(cut_lj[i][j],p2)); ptail_ij = 2.0*MY_PI*all[0]*all[1]*e0nm[i][j] * nn[i][j]*mm[i][j]*(rrr1*pow(cut_lj[i][j],p1)-rrr2*pow(cut_lj[i][j],p2)); } return cut; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairNMCutCoulCut::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(&e0[i][j],sizeof(double),1,fp); fwrite(&r0[i][j],sizeof(double),1,fp); fwrite(&nn[i][j],sizeof(double),1,fp); fwrite(&mm[i][j],sizeof(double),1,fp); fwrite(&cut_lj[i][j],sizeof(double),1,fp); fwrite(&cut_coul[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairNMCutCoulCut::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(&e0[i][j],sizeof(double),1,fp); fread(&r0[i][j],sizeof(double),1,fp); fread(&nn[i][j],sizeof(double),1,fp); fread(&mm[i][j],sizeof(double),1,fp); fread(&cut_lj[i][j],sizeof(double),1,fp); fread(&cut_coul[i][j],sizeof(double),1,fp); } MPI_Bcast(&e0[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&r0[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&nn[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&mm[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_lj[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_coul[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairNMCutCoulCut::write_restart_settings(FILE *fp) { fwrite(&cut_lj_global,sizeof(double),1,fp); fwrite(&cut_coul_global,sizeof(double),1,fp); fwrite(&offset_flag,sizeof(int),1,fp); fwrite(&mix_flag,sizeof(int),1,fp); fwrite(&tail_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairNMCutCoulCut::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&cut_lj_global,sizeof(double),1,fp); fread(&cut_coul_global,sizeof(double),1,fp); fread(&offset_flag,sizeof(int),1,fp); fread(&mix_flag,sizeof(int),1,fp); fread(&tail_flag,sizeof(int),1,fp); } MPI_Bcast(&cut_lj_global,1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_coul_global,1,MPI_DOUBLE,0,world); MPI_Bcast(&offset_flag,1,MPI_INT,0,world); MPI_Bcast(&mix_flag,1,MPI_INT,0,world); MPI_Bcast(&tail_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void PairNMCutCoulCut::write_data(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) fprintf(fp,"%d %g %g %g %g\n",i,e0[i][i],r0[i][i],nn[i][i],mm[i][i]); } /* ---------------------------------------------------------------------- proc 0 writes all pairs to data file ------------------------------------------------------------------------- */ void PairNMCutCoulCut::write_data_all(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) fprintf(fp,"%d %d %g %g %g %g %g\n",i,j, e0[i][j],r0[i][j],nn[i][j],mm[i][j],cut_lj[i][j]); } /* ---------------------------------------------------------------------- */ double PairNMCutCoulCut::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r2inv,r,forcecoul,forcenm,phicoul,phinm; r2inv = 1.0/rsq; if (rsq < cut_coulsq[itype][jtype]) forcecoul = force->qqrd2e * atom->q[i]*atom->q[j]*sqrt(r2inv); else forcecoul = 0.0; if (rsq < cut_ljsq[itype][jtype]) { r = sqrt(rsq); forcenm = e0nm[itype][jtype]*nm[itype][jtype] * (r0n[itype][jtype]/pow(r,nn[itype][jtype]) - r0m[itype][jtype]/pow(r,mm[itype][jtype])); } else forcenm = 0.0; fforce = (factor_coul*forcecoul + factor_lj*forcenm) * r2inv; double eng = 0.0; if (rsq < cut_coulsq[itype][jtype]) { phicoul = force->qqrd2e * atom->q[i]*atom->q[j]*sqrt(r2inv); eng += factor_coul*phicoul; } if (rsq < cut_ljsq[itype][jtype]) { phinm = e0nm[itype][jtype] * (mm[itype][jtype]*r0n[itype][jtype]/pow(r,nn[itype][jtype]) - nn[itype][jtype]*r0m[itype][jtype]/pow(r,mm[itype][jtype])) - offset[itype][jtype]; eng += factor_lj*phinm; } return eng; } /* ---------------------------------------------------------------------- */ void *PairNMCutCoulCut::extract(const char *str, int &dim) { dim = 0; if (strcmp(str,"cut_coul") == 0) return (void *) &cut_coul; dim = 2; if (strcmp(str,"e0") == 0) return (void *) e0; if (strcmp(str,"r0") == 0) return (void *) r0; if (strcmp(str,"nn") == 0) return (void *) nn; if (strcmp(str,"mm") == 0) return (void *) mm; return NULL; } diff --git a/src/MISC/pair_nm_cut_coul_long.cpp b/src/MISC/pair_nm_cut_coul_long.cpp index 0cd12ac03..c186d1953 100644 --- a/src/MISC/pair_nm_cut_coul_long.cpp +++ b/src/MISC/pair_nm_cut_coul_long.cpp @@ -1,590 +1,590 @@ /* ---------------------------------------------------------------------- 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: Julien Devemy (ICCF) ------------------------------------------------------------------------- */ #include #include #include #include #include "pair_nm_cut_coul_long.h" #include "atom.h" #include "comm.h" #include "force.h" #include "kspace.h" #include "update.h" #include "integrate.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 /* ---------------------------------------------------------------------- */ PairNMCutCoulLong::PairNMCutCoulLong(LAMMPS *lmp) : Pair(lmp) { ewaldflag = pppmflag = 1; ftable = NULL; qdist = 0.0; } /* ---------------------------------------------------------------------- */ PairNMCutCoulLong::~PairNMCutCoulLong() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut_lj); memory->destroy(cut_ljsq); memory->destroy(e0); memory->destroy(r0); memory->destroy(nn); memory->destroy(mm); memory->destroy(nm); memory->destroy(e0nm); memory->destroy(r0n); memory->destroy(r0m); memory->destroy(offset); } if (ftable) free_tables(); } /* ---------------------------------------------------------------------- */ void PairNMCutCoulLong::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,factor_coul,factor_lj; double forcecoul,forcenm,rminv,rninv; 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]) { r = sqrt(rsq); rminv = pow(r2inv,mm[itype][jtype]/2.0); rninv = pow(r2inv,nn[itype][jtype]/2.0); forcenm = e0nm[itype][jtype]*nm[itype][jtype] * (r0n[itype][jtype]/pow(r,nn[itype][jtype]) - r0m[itype][jtype]/pow(r,mm[itype][jtype])); } else forcenm = 0.0; fpair = (forcecoul + factor_lj*forcenm) * 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 = e0nm[itype][jtype] * (mm[itype][jtype]*r0n[itype][jtype]*rninv - nn[itype][jtype]*r0m[itype][jtype]*rminv) - 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 PairNMCutCoulLong::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(e0,n+1,n+1,"pair:e0"); memory->create(r0,n+1,n+1,"pair:r0"); memory->create(nn,n+1,n+1,"pair:nn"); memory->create(mm,n+1,n+1,"pair:mm"); memory->create(nm,n+1,n+1,"pair:nm"); memory->create(e0nm,n+1,n+1,"pair:e0nm"); memory->create(r0n,n+1,n+1,"pair:r0n"); memory->create(r0m,n+1,n+1,"pair:r0m"); memory->create(offset,n+1,n+1,"pair:offset"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairNMCutCoulLong::settings(int narg, char **arg) { if (narg < 1 || narg > 2) error->all(FLERR,"Illegal pair_style command"); cut_lj_global = force->numeric(FLERR,arg[0]); if (narg == 1) cut_coul = cut_lj_global; else cut_coul = force->numeric(FLERR,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 PairNMCutCoulLong::coeff(int narg, char **arg) { if (narg < 6 || narg > 7) 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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double e0_one = force->numeric(FLERR,arg[2]); double r0_one = force->numeric(FLERR,arg[3]); double nn_one = force->numeric(FLERR,arg[4]); double mm_one = force->numeric(FLERR,arg[5]); double cut_lj_one = cut_lj_global; if (narg == 7) cut_lj_one = force->numeric(FLERR,arg[4]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { e0[i][j] = e0_one; r0[i][j] = r0_one; nn[i][j] = nn_one; mm[i][j] = mm_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 PairNMCutCoulLong::init_style() { if (!atom->q_flag) error->all(FLERR,"Pair style nm/cut/coul/long requires atom attribute q"); neighbor->request(this,instance_me); 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 requires a KSpace style"); g_ewald = force->kspace->g_ewald; // setup force tables if (ncoultablebits) init_tables(cut_coul,NULL); } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairNMCutCoulLong::init_one(int i, int j) { if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set"); // include TIP4P qdist in full cutoff, qdist = 0.0 if not TIP4P double cut = MAX(cut_lj[i][j],cut_coul+2.0*qdist); cut_ljsq[i][j] = cut_lj[i][j] * cut_lj[i][j]; nm[i][j] = nn[i][j]*mm[i][j]; e0nm[i][j] = e0[i][j]/(nn[i][j]-mm[i][j]); r0n[i][j] = pow(r0[i][j],nn[i][j]); r0m[i][j] = pow(r0[i][j],mm[i][j]); if (offset_flag) { offset[i][j] = e0nm[i][j] * ((mm[i][j]*r0n[i][j] / pow(cut_lj[i][j],nn[i][j])) - (nn[i][j]*r0m[i][j] / pow(cut_lj[i][j],mm[i][j]))); } else offset[i][j] = 0.0; cut_ljsq[j][i] = cut_ljsq[i][j]; e0[j][i] = e0[i][j]; nn[j][i] = nn[i][j]; mm[j][i] = mm[i][j]; nm[j][i] = nm[i][j]; r0[j][i] = r0[i][j]; e0nm[j][i] = e0nm[i][j]; r0n[j][i] = r0n[i][j]; r0m[j][i] = r0m[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 rr1 = mm[i][j]*(nn[i][j]-1)*pow(r0[i][j],nn[i][j]); double rr2 = nn[i][j]*(mm[i][j]-1)*pow(r0[i][j],mm[i][j]); double p1 = 1-nn[i][j]; double p2 = 1-mm[i][j]; double rrr1 = pow(r0[i][j],nn[i][j])*(1-nn[i][j]); double rrr2 = pow(r0[i][j],mm[i][j])*(1-mm[i][j]); etail_ij = 2.0*MY_PI*all[0]*all[1]*e0nm[i][j] * (rr1*pow(cut_lj[i][j],p1)-rr2*pow(cut_lj[i][j],p2)); ptail_ij = 2.0*MY_PI*all[0]*all[1]*e0nm[i][j]*nn[i][j]*mm[i][j] * (rrr1*pow(cut_lj[i][j],p1)-rrr2*pow(cut_lj[i][j],p2)); } return cut; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairNMCutCoulLong::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(&e0[i][j],sizeof(double),1,fp); fwrite(&r0[i][j],sizeof(double),1,fp); fwrite(&nn[i][j],sizeof(double),1,fp); fwrite(&mm[i][j],sizeof(double),1,fp); fwrite(&cut_lj[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairNMCutCoulLong::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(&e0[i][j],sizeof(double),1,fp); fread(&r0[i][j],sizeof(double),1,fp); fread(&nn[i][j],sizeof(double),1,fp); fread(&mm[i][j],sizeof(double),1,fp); fread(&cut_lj[i][j],sizeof(double),1,fp); } MPI_Bcast(&e0[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&r0[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&nn[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&mm[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 PairNMCutCoulLong::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); fwrite(&tail_flag,sizeof(int),1,fp); fwrite(&ncoultablebits,sizeof(int),1,fp); fwrite(&tabinner,sizeof(double),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairNMCutCoulLong::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); fread(&tail_flag,sizeof(int),1,fp); fread(&ncoultablebits,sizeof(int),1,fp); fread(&tabinner,sizeof(double),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); MPI_Bcast(&tail_flag,1,MPI_INT,0,world); MPI_Bcast(&ncoultablebits,1,MPI_INT,0,world); MPI_Bcast(&tabinner,1,MPI_DOUBLE,0,world); } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void PairNMCutCoulLong::write_data(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) fprintf(fp,"%d %g %g %g %g\n",i,e0[i][i],r0[i][i],nn[i][i],mm[i][i]); } /* ---------------------------------------------------------------------- proc 0 writes all pairs to data file ------------------------------------------------------------------------- */ void PairNMCutCoulLong::write_data_all(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) fprintf(fp,"%d %d %g %g %g %g %g\n",i,j, e0[i][j],r0[i][j],nn[i][j],mm[i][j],cut_lj[i][j]); } /* ---------------------------------------------------------------------- */ double PairNMCutCoulLong::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,forcenm,phicoul,phinm; 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]) { r = sqrt(rsq); forcenm = e0nm[itype][jtype]*nm[itype][jtype] * (r0n[itype][jtype]/pow(r,nn[itype][jtype]) - r0m[itype][jtype]/pow(r,mm[itype][jtype])); } else forcenm = 0.0; fforce = (forcecoul + factor_lj*forcenm) * 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]) { phinm = e0nm[itype][jtype] * (mm[itype][jtype]*r0n[itype][jtype]/pow(r,nn[itype][jtype]) - nn[itype][jtype]*r0m[itype][jtype]/pow(r,mm[itype][jtype])) - offset[itype][jtype]; eng += factor_lj*phinm; } return eng; } /* ---------------------------------------------------------------------- */ void *PairNMCutCoulLong::extract(const char *str, int &dim) { dim = 0; if (strcmp(str,"cut_coul") == 0) return (void *) &cut_coul; dim = 2; if (strcmp(str,"e0") == 0) return (void *) e0; if (strcmp(str,"r0") == 0) return (void *) r0; if (strcmp(str,"nn") == 0) return (void *) nn; if (strcmp(str,"mm") == 0) return (void *) mm; return NULL; } diff --git a/src/MOLECULE/angle_charmm.cpp b/src/MOLECULE/angle_charmm.cpp index c2d44b26d..c7284add8 100644 --- a/src/MOLECULE/angle_charmm.cpp +++ b/src/MOLECULE/angle_charmm.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. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author: Paul Crozier (SNL) ------------------------------------------------------------------------- */ #include #include #include "angle_charmm.h" #include "atom.h" #include "neighbor.h" #include "domain.h" #include "comm.h" #include "force.h" #include "math_const.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace MathConst; #define SMALL 0.001 /* ---------------------------------------------------------------------- */ AngleCharmm::AngleCharmm(LAMMPS *lmp) : Angle(lmp) {} /* ---------------------------------------------------------------------- */ AngleCharmm::~AngleCharmm() { if (allocated && !copymode) { memory->destroy(setflag); memory->destroy(k); memory->destroy(theta0); memory->destroy(k_ub); memory->destroy(r_ub); } } /* ---------------------------------------------------------------------- */ void AngleCharmm::compute(int eflag, int vflag) { int i1,i2,i3,n,type; double delx1,dely1,delz1,delx2,dely2,delz2; double eangle,f1[3],f3[3]; double dtheta,tk; double rsq1,rsq2,r1,r2,c,s,a,a11,a12,a22; double delxUB,delyUB,delzUB,rsqUB,rUB,dr,rk,forceUB; eangle = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; int **anglelist = neighbor->anglelist; int nanglelist = neighbor->nanglelist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < nanglelist; n++) { i1 = anglelist[n][0]; i2 = anglelist[n][1]; i3 = anglelist[n][2]; type = anglelist[n][3]; // 1st bond delx1 = x[i1][0] - x[i2][0]; dely1 = x[i1][1] - x[i2][1]; delz1 = x[i1][2] - x[i2][2]; rsq1 = delx1*delx1 + dely1*dely1 + delz1*delz1; r1 = sqrt(rsq1); // 2nd bond delx2 = x[i3][0] - x[i2][0]; dely2 = x[i3][1] - x[i2][1]; delz2 = x[i3][2] - x[i2][2]; rsq2 = delx2*delx2 + dely2*dely2 + delz2*delz2; r2 = sqrt(rsq2); // Urey-Bradley bond delxUB = x[i3][0] - x[i1][0]; delyUB = x[i3][1] - x[i1][1]; delzUB = x[i3][2] - x[i1][2]; rsqUB = delxUB*delxUB + delyUB*delyUB + delzUB*delzUB; rUB = sqrt(rsqUB); // Urey-Bradley force & energy dr = rUB - r_ub[type]; rk = k_ub[type] * dr; if (rUB > 0.0) forceUB = -2.0*rk/rUB; else forceUB = 0.0; if (eflag) eangle = rk*dr; // angle (cos and sin) c = delx1*delx2 + dely1*dely2 + delz1*delz2; c /= r1*r2; if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; s = sqrt(1.0 - c*c); if (s < SMALL) s = SMALL; s = 1.0/s; // harmonic force & energy dtheta = acos(c) - theta0[type]; tk = k[type] * dtheta; if (eflag) eangle += tk*dtheta; a = -2.0 * tk * s; a11 = a*c / rsq1; a12 = -a / (r1*r2); a22 = a*c / rsq2; f1[0] = a11*delx1 + a12*delx2 - delxUB*forceUB; f1[1] = a11*dely1 + a12*dely2 - delyUB*forceUB; f1[2] = a11*delz1 + a12*delz2 - delzUB*forceUB; f3[0] = a22*delx2 + a12*delx1 + delxUB*forceUB; f3[1] = a22*dely2 + a12*dely1 + delyUB*forceUB; f3[2] = a22*delz2 + a12*delz1 + delzUB*forceUB; // apply force to each of 3 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += f1[0]; f[i1][1] += f1[1]; f[i1][2] += f1[2]; } if (newton_bond || i2 < nlocal) { f[i2][0] -= f1[0] + f3[0]; f[i2][1] -= f1[1] + f3[1]; f[i2][2] -= f1[2] + f3[2]; } if (newton_bond || i3 < nlocal) { f[i3][0] += f3[0]; f[i3][1] += f3[1]; f[i3][2] += f3[2]; } if (evflag) ev_tally(i1,i2,i3,nlocal,newton_bond,eangle,f1,f3, delx1,dely1,delz1,delx2,dely2,delz2); } } /* ---------------------------------------------------------------------- */ void AngleCharmm::allocate() { allocated = 1; int n = atom->nangletypes; memory->create(k,n+1,"angle:k"); memory->create(theta0,n+1,"angle:theta0"); memory->create(k_ub,n+1,"angle:k_ub"); memory->create(r_ub,n+1,"angle:r_ub"); memory->create(setflag,n+1,"angle:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one type ------------------------------------------------------------------------- */ void AngleCharmm::coeff(int narg, char **arg) { if (narg != 5) error->all(FLERR,"Incorrect args for angle coefficients"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->nangletypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->nangletypes,ilo,ihi); double k_one = force->numeric(FLERR,arg[1]); double theta0_one = force->numeric(FLERR,arg[2]); double k_ub_one = force->numeric(FLERR,arg[3]); double r_ub_one = force->numeric(FLERR,arg[4]); // convert theta0 from degrees to radians int count = 0; for (int i = ilo; i <= ihi; i++) { k[i] = k_one; theta0[i] = theta0_one/180.0 * MY_PI; k_ub[i] = k_ub_one; r_ub[i] = r_ub_one; setflag[i] = 1; count++; } if (count == 0) error->all(FLERR,"Incorrect args for angle coefficients"); } /* ---------------------------------------------------------------------- */ double AngleCharmm::equilibrium_angle(int i) { return theta0[i]; } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void AngleCharmm::write_restart(FILE *fp) { fwrite(&k[1],sizeof(double),atom->nangletypes,fp); fwrite(&theta0[1],sizeof(double),atom->nangletypes,fp); fwrite(&k_ub[1],sizeof(double),atom->nangletypes,fp); fwrite(&r_ub[1],sizeof(double),atom->nangletypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void AngleCharmm::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&k[1],sizeof(double),atom->nangletypes,fp); fread(&theta0[1],sizeof(double),atom->nangletypes,fp); fread(&k_ub[1],sizeof(double),atom->nangletypes,fp); fread(&r_ub[1],sizeof(double),atom->nangletypes,fp); } MPI_Bcast(&k[1],atom->nangletypes,MPI_DOUBLE,0,world); MPI_Bcast(&theta0[1],atom->nangletypes,MPI_DOUBLE,0,world); MPI_Bcast(&k_ub[1],atom->nangletypes,MPI_DOUBLE,0,world); MPI_Bcast(&r_ub[1],atom->nangletypes,MPI_DOUBLE,0,world); for (int i = 1; i <= atom->nangletypes; i++) setflag[i] = 1; } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void AngleCharmm::write_data(FILE *fp) { for (int i = 1; i <= atom->nangletypes; i++) fprintf(fp,"%d %g %g %g %g\n", i,k[i],theta0[i]/MY_PI*180.0,k_ub[i],r_ub[i]); } /* ---------------------------------------------------------------------- */ double AngleCharmm::single(int type, int i1, int i2, int i3) { double **x = atom->x; double delx1 = x[i1][0] - x[i2][0]; double dely1 = x[i1][1] - x[i2][1]; double delz1 = x[i1][2] - x[i2][2]; domain->minimum_image(delx1,dely1,delz1); double r1 = sqrt(delx1*delx1 + dely1*dely1 + delz1*delz1); double delx2 = x[i3][0] - x[i2][0]; double dely2 = x[i3][1] - x[i2][1]; double delz2 = x[i3][2] - x[i2][2]; domain->minimum_image(delx2,dely2,delz2); double r2 = sqrt(delx2*delx2 + dely2*dely2 + delz2*delz2); double delxUB = x[i3][0] - x[i1][0]; double delyUB = x[i3][1] - x[i1][1]; double delzUB = x[i3][2] - x[i1][2]; domain->minimum_image(delxUB,delyUB,delzUB); double rUB = sqrt(delxUB*delxUB + delyUB*delyUB + delzUB*delzUB); double c = delx1*delx2 + dely1*dely2 + delz1*delz2; c /= r1*r2; if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; double dtheta = acos(c) - theta0[type]; double tk = k[type] * dtheta; double dr = rUB - r_ub[type]; double rk = k_ub[type] * dr; return (tk*dtheta + rk*dr); } diff --git a/src/MOLECULE/angle_cosine.cpp b/src/MOLECULE/angle_cosine.cpp index 135d4bbf8..f064a34f2 100644 --- a/src/MOLECULE/angle_cosine.cpp +++ b/src/MOLECULE/angle_cosine.cpp @@ -1,237 +1,237 @@ /* ---------------------------------------------------------------------- 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 #include #include "angle_cosine.h" #include "atom.h" #include "neighbor.h" #include "domain.h" #include "comm.h" #include "force.h" #include "math_const.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace MathConst; #define SMALL 0.001 /* ---------------------------------------------------------------------- */ AngleCosine::AngleCosine(LAMMPS *lmp) : Angle(lmp) {} /* ---------------------------------------------------------------------- */ AngleCosine::~AngleCosine() { if (allocated) { memory->destroy(setflag); memory->destroy(k); } } /* ---------------------------------------------------------------------- */ void AngleCosine::compute(int eflag, int vflag) { int i1,i2,i3,n,type; double delx1,dely1,delz1,delx2,dely2,delz2; double eangle,f1[3],f3[3]; double rsq1,rsq2,r1,r2,c,a,a11,a12,a22; eangle = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; int **anglelist = neighbor->anglelist; int nanglelist = neighbor->nanglelist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < nanglelist; n++) { i1 = anglelist[n][0]; i2 = anglelist[n][1]; i3 = anglelist[n][2]; type = anglelist[n][3]; // 1st bond delx1 = x[i1][0] - x[i2][0]; dely1 = x[i1][1] - x[i2][1]; delz1 = x[i1][2] - x[i2][2]; rsq1 = delx1*delx1 + dely1*dely1 + delz1*delz1; r1 = sqrt(rsq1); // 2nd bond delx2 = x[i3][0] - x[i2][0]; dely2 = x[i3][1] - x[i2][1]; delz2 = x[i3][2] - x[i2][2]; rsq2 = delx2*delx2 + dely2*dely2 + delz2*delz2; r2 = sqrt(rsq2); // c = cosine of angle c = delx1*delx2 + dely1*dely2 + delz1*delz2; c /= r1*r2; if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; // force & energy if (eflag) eangle = k[type]*(1.0+c); a = k[type]; a11 = a*c / rsq1; a12 = -a / (r1*r2); a22 = a*c / rsq2; f1[0] = a11*delx1 + a12*delx2; f1[1] = a11*dely1 + a12*dely2; f1[2] = a11*delz1 + a12*delz2; f3[0] = a22*delx2 + a12*delx1; f3[1] = a22*dely2 + a12*dely1; f3[2] = a22*delz2 + a12*delz1; // apply force to each of 3 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += f1[0]; f[i1][1] += f1[1]; f[i1][2] += f1[2]; } if (newton_bond || i2 < nlocal) { f[i2][0] -= f1[0] + f3[0]; f[i2][1] -= f1[1] + f3[1]; f[i2][2] -= f1[2] + f3[2]; } if (newton_bond || i3 < nlocal) { f[i3][0] += f3[0]; f[i3][1] += f3[1]; f[i3][2] += f3[2]; } if (evflag) ev_tally(i1,i2,i3,nlocal,newton_bond,eangle,f1,f3, delx1,dely1,delz1,delx2,dely2,delz2); } } /* ---------------------------------------------------------------------- */ void AngleCosine::allocate() { allocated = 1; int n = atom->nangletypes; memory->create(k,n+1,"angle:k"); memory->create(setflag,n+1,"angle:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one type ------------------------------------------------------------------------- */ void AngleCosine::coeff(int narg, char **arg) { if (narg != 2) error->all(FLERR,"Incorrect args for angle coefficients"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->nangletypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->nangletypes,ilo,ihi); double k_one = force->numeric(FLERR,arg[1]); int count = 0; for (int i = ilo; i <= ihi; i++) { k[i] = k_one; setflag[i] = 1; count++; } if (count == 0) error->all(FLERR,"Incorrect args for angle coefficients"); } /* ---------------------------------------------------------------------- */ double AngleCosine::equilibrium_angle(int i) { return MY_PI; } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void AngleCosine::write_restart(FILE *fp) { fwrite(&k[1],sizeof(double),atom->nangletypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void AngleCosine::read_restart(FILE *fp) { allocate(); if (comm->me == 0) fread(&k[1],sizeof(double),atom->nangletypes,fp); MPI_Bcast(&k[1],atom->nangletypes,MPI_DOUBLE,0,world); for (int i = 1; i <= atom->nangletypes; i++) setflag[i] = 1; } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void AngleCosine::write_data(FILE *fp) { for (int i = 1; i <= atom->nangletypes; i++) fprintf(fp,"%d %g\n",i,k[i]); } /* ---------------------------------------------------------------------- */ double AngleCosine::single(int type, int i1, int i2, int i3) { double **x = atom->x; double delx1 = x[i1][0] - x[i2][0]; double dely1 = x[i1][1] - x[i2][1]; double delz1 = x[i1][2] - x[i2][2]; domain->minimum_image(delx1,dely1,delz1); double r1 = sqrt(delx1*delx1 + dely1*dely1 + delz1*delz1); double delx2 = x[i3][0] - x[i2][0]; double dely2 = x[i3][1] - x[i2][1]; double delz2 = x[i3][2] - x[i2][2]; domain->minimum_image(delx2,dely2,delz2); double r2 = sqrt(delx2*delx2 + dely2*dely2 + delz2*delz2); double c = delx1*delx2 + dely1*dely2 + delz1*delz2; c /= r1*r2; if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; return k[type]*(1.0+c); } diff --git a/src/MOLECULE/angle_cosine_periodic.cpp b/src/MOLECULE/angle_cosine_periodic.cpp index dbd93b3b7..77fb335b7 100644 --- a/src/MOLECULE/angle_cosine_periodic.cpp +++ b/src/MOLECULE/angle_cosine_periodic.cpp @@ -1,299 +1,299 @@ /* ---------------------------------------------------------------------- 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: Tod A Pascal (Caltech) ------------------------------------------------------------------------- */ #include #include #include "angle_cosine_periodic.h" #include "atom.h" #include "neighbor.h" #include "domain.h" #include "comm.h" #include "force.h" #include "math_const.h" #include "math_special.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace MathConst; using namespace MathSpecial; #define SMALL 0.001 /* ---------------------------------------------------------------------- */ AngleCosinePeriodic::AngleCosinePeriodic(LAMMPS *lmp) : Angle(lmp) {} /* ---------------------------------------------------------------------- */ AngleCosinePeriodic::~AngleCosinePeriodic() { if (allocated) { memory->destroy(setflag); memory->destroy(k); memory->destroy(b); memory->destroy(multiplicity); } } /* ---------------------------------------------------------------------- */ void AngleCosinePeriodic::compute(int eflag, int vflag) { int i,i1,i2,i3,n,m,type,b_factor; double delx1,dely1,delz1,delx2,dely2,delz2; double eangle,f1[3],f3[3]; double rsq1,rsq2,r1,r2,c,a,a11,a12,a22; double tn,tn_1,tn_2,un,un_1,un_2; eangle = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; int **anglelist = neighbor->anglelist; int nanglelist = neighbor->nanglelist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < nanglelist; n++) { i1 = anglelist[n][0]; i2 = anglelist[n][1]; i3 = anglelist[n][2]; type = anglelist[n][3]; // 1st bond delx1 = x[i1][0] - x[i2][0]; dely1 = x[i1][1] - x[i2][1]; delz1 = x[i1][2] - x[i2][2]; rsq1 = delx1*delx1 + dely1*dely1 + delz1*delz1; r1 = sqrt(rsq1); // 2nd bond delx2 = x[i3][0] - x[i2][0]; dely2 = x[i3][1] - x[i2][1]; delz2 = x[i3][2] - x[i2][2]; rsq2 = delx2*delx2 + dely2*dely2 + delz2*delz2; r2 = sqrt(rsq2); // c = cosine of angle c = delx1*delx2 + dely1*dely2 + delz1*delz2; c /= r1*r2; if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; m = multiplicity[type]; b_factor = b[type]; // cos(n*x) = Tn(cos(x)) // Tn(x) = Chebyshev polynomials of the first kind: T_0 = 1, T_1 = x, ... // recurrence relationship: // Tn(x) = 2*x*T[n-1](x) - T[n-2](x) where T[-1](x) = 0 // also, dTn(x)/dx = n*U[n-1](x) // where Un(x) = 2*x*U[n-1](x) - U[n-2](x) and U[-1](x) = 0 // finally need to handle special case for n = 1 tn = 1.0; tn_1 = 1.0; tn_2 = 0.0; un = 1.0; un_1 = 2.0; un_2 = 0.0; // force & energy tn_2 = c; for (i = 1; i <= m; i++) { tn = 2*c*tn_1 - tn_2; tn_2 = tn_1; tn_1 = tn; } for (i = 2; i <= m; i++) { un = 2*c*un_1 - un_2; un_2 = un_1; un_1 = un; } tn = b_factor*powsign(m)*tn; un = b_factor*powsign(m)*m*un; if (eflag) eangle = 2*k[type]*(1.0 - tn); a = -k[type]*un; a11 = a*c / rsq1; a12 = -a / (r1*r2); a22 = a*c / rsq2; f1[0] = a11*delx1 + a12*delx2; f1[1] = a11*dely1 + a12*dely2; f1[2] = a11*delz1 + a12*delz2; f3[0] = a22*delx2 + a12*delx1; f3[1] = a22*dely2 + a12*dely1; f3[2] = a22*delz2 + a12*delz1; // apply force to each of 3 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += f1[0]; f[i1][1] += f1[1]; f[i1][2] += f1[2]; } if (newton_bond || i2 < nlocal) { f[i2][0] -= f1[0] + f3[0]; f[i2][1] -= f1[1] + f3[1]; f[i2][2] -= f1[2] + f3[2]; } if (newton_bond || i3 < nlocal) { f[i3][0] += f3[0]; f[i3][1] += f3[1]; f[i3][2] += f3[2]; } if (evflag) ev_tally(i1,i2,i3,nlocal,newton_bond,eangle,f1,f3, delx1,dely1,delz1,delx2,dely2,delz2); } } /* ---------------------------------------------------------------------- */ void AngleCosinePeriodic::allocate() { allocated = 1; int n = atom->nangletypes; memory->create(k,n+1,"angle:k"); memory->create(multiplicity,n+1,"angle:multiplicity"); memory->create(b,n+1,"angle:b"); memory->create(setflag,n+1,"angle:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one or more types ------------------------------------------------------------------------- */ void AngleCosinePeriodic::coeff(int narg, char **arg) { if (narg != 4) error->all(FLERR,"Incorrect args for angle coefficients"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->nangletypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->nangletypes,ilo,ihi); double c_one = force->numeric(FLERR,arg[1]); int b_one = force->inumeric(FLERR,arg[2]); int n_one = force->inumeric(FLERR,arg[3]); if (n_one <= 0) error->all(FLERR,"Incorrect args for angle coefficients"); int count = 0; for (int i = ilo; i <= ihi; i++) { k[i] = c_one/(n_one*n_one); b[i] = b_one; multiplicity[i] = n_one; setflag[i] = 1; count++; } if (count == 0) error->all(FLERR,"Incorrect args for angle coefficients"); } /* ---------------------------------------------------------------------- */ double AngleCosinePeriodic::equilibrium_angle(int i) { return MY_PI; } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void AngleCosinePeriodic::write_restart(FILE *fp) { fwrite(&k[1],sizeof(double),atom->nangletypes,fp); fwrite(&b[1],sizeof(int),atom->nangletypes,fp); fwrite(&multiplicity[1],sizeof(int),atom->nangletypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void AngleCosinePeriodic::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&k[1],sizeof(double),atom->nangletypes,fp); fread(&b[1],sizeof(int),atom->nangletypes,fp); fread(&multiplicity[1],sizeof(int),atom->nangletypes,fp); } MPI_Bcast(&k[1],atom->nangletypes,MPI_DOUBLE,0,world); MPI_Bcast(&b[1],atom->nangletypes,MPI_INT,0,world); MPI_Bcast(&multiplicity[1],atom->nangletypes,MPI_INT,0,world); for (int i = 1; i <= atom->nangletypes; i++) setflag[i] = 1; } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void AngleCosinePeriodic::write_data(FILE *fp) { for (int i = 1; i <= atom->nangletypes; i++) { int m = multiplicity[i]; fprintf(fp,"%d %g %d %d\n",i,k[i]*m*m,b[i],m); } } /* ---------------------------------------------------------------------- */ double AngleCosinePeriodic::single(int type, int i1, int i2, int i3) { double **x = atom->x; double delx1 = x[i1][0] - x[i2][0]; double dely1 = x[i1][1] - x[i2][1]; double delz1 = x[i1][2] - x[i2][2]; domain->minimum_image(delx1,dely1,delz1); double r1 = sqrt(delx1*delx1 + dely1*dely1 + delz1*delz1); double delx2 = x[i3][0] - x[i2][0]; double dely2 = x[i3][1] - x[i2][1]; double delz2 = x[i3][2] - x[i2][2]; domain->minimum_image(delx2,dely2,delz2); double r2 = sqrt(delx2*delx2 + dely2*dely2 + delz2*delz2); double c = delx1*delx2 + dely1*dely2 + delz1*delz2; c /= r1*r2; if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; c = cos(acos(c)*multiplicity[type]); return k[type]*(1.0-b[type]*powsign(multiplicity[type])*c); } diff --git a/src/MOLECULE/angle_cosine_squared.cpp b/src/MOLECULE/angle_cosine_squared.cpp index 6d073f156..bc38d76dc 100644 --- a/src/MOLECULE/angle_cosine_squared.cpp +++ b/src/MOLECULE/angle_cosine_squared.cpp @@ -1,260 +1,260 @@ /* ---------------------------------------------------------------------- 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: Naveen Michaud-Agrawal (Johns Hopkins U) ------------------------------------------------------------------------- */ #include #include #include "angle_cosine_squared.h" #include "atom.h" #include "neighbor.h" #include "domain.h" #include "comm.h" #include "force.h" #include "math_const.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace MathConst; #define SMALL 0.001 /* ---------------------------------------------------------------------- */ AngleCosineSquared::AngleCosineSquared(LAMMPS *lmp) : Angle(lmp) {} /* ---------------------------------------------------------------------- */ AngleCosineSquared::~AngleCosineSquared() { if (allocated) { memory->destroy(setflag); memory->destroy(k); memory->destroy(theta0); } } /* ---------------------------------------------------------------------- */ void AngleCosineSquared::compute(int eflag, int vflag) { int i1,i2,i3,n,type; double delx1,dely1,delz1,delx2,dely2,delz2; double eangle,f1[3],f3[3]; double dcostheta,tk; double rsq1,rsq2,r1,r2,c,a,a11,a12,a22; eangle = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; int **anglelist = neighbor->anglelist; int nanglelist = neighbor->nanglelist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < nanglelist; n++) { i1 = anglelist[n][0]; i2 = anglelist[n][1]; i3 = anglelist[n][2]; type = anglelist[n][3]; // 1st bond delx1 = x[i1][0] - x[i2][0]; dely1 = x[i1][1] - x[i2][1]; delz1 = x[i1][2] - x[i2][2]; rsq1 = delx1*delx1 + dely1*dely1 + delz1*delz1; r1 = sqrt(rsq1); // 2nd bond delx2 = x[i3][0] - x[i2][0]; dely2 = x[i3][1] - x[i2][1]; delz2 = x[i3][2] - x[i2][2]; rsq2 = delx2*delx2 + dely2*dely2 + delz2*delz2; r2 = sqrt(rsq2); // angle (cos and sin) c = delx1*delx2 + dely1*dely2 + delz1*delz2; c /= r1*r2; if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; // force & energy dcostheta = c - cos(theta0[type]); tk = k[type] * dcostheta; if (eflag) eangle = tk*dcostheta; a = 2.0 * tk; a11 = a*c / rsq1; a12 = -a / (r1*r2); a22 = a*c / rsq2; f1[0] = a11*delx1 + a12*delx2; f1[1] = a11*dely1 + a12*dely2; f1[2] = a11*delz1 + a12*delz2; f3[0] = a22*delx2 + a12*delx1; f3[1] = a22*dely2 + a12*dely1; f3[2] = a22*delz2 + a12*delz1; // apply force to each of 3 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += f1[0]; f[i1][1] += f1[1]; f[i1][2] += f1[2]; } if (newton_bond || i2 < nlocal) { f[i2][0] -= f1[0] + f3[0]; f[i2][1] -= f1[1] + f3[1]; f[i2][2] -= f1[2] + f3[2]; } if (newton_bond || i3 < nlocal) { f[i3][0] += f3[0]; f[i3][1] += f3[1]; f[i3][2] += f3[2]; } if (evflag) ev_tally(i1,i2,i3,nlocal,newton_bond,eangle,f1,f3, delx1,dely1,delz1,delx2,dely2,delz2); } } /* ---------------------------------------------------------------------- */ void AngleCosineSquared::allocate() { allocated = 1; int n = atom->nangletypes; memory->create(k,n+1,"angle:k"); memory->create(theta0,n+1,"angle:theta0"); memory->create(setflag,n+1,"angle:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one or more types ------------------------------------------------------------------------- */ void AngleCosineSquared::coeff(int narg, char **arg) { if (narg != 3) error->all(FLERR,"Incorrect args for angle coefficients"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->nangletypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->nangletypes,ilo,ihi); double k_one = force->numeric(FLERR,arg[1]); double theta0_one = force->numeric(FLERR,arg[2]); // convert theta0 from degrees to radians int count = 0; for (int i = ilo; i <= ihi; i++) { k[i] = k_one; theta0[i] = theta0_one/180.0 * MY_PI; setflag[i] = 1; count++; } if (count == 0) error->all(FLERR,"Incorrect args for angle coefficients"); } /* ---------------------------------------------------------------------- */ double AngleCosineSquared::equilibrium_angle(int i) { return theta0[i]; } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void AngleCosineSquared::write_restart(FILE *fp) { fwrite(&k[1],sizeof(double),atom->nangletypes,fp); fwrite(&theta0[1],sizeof(double),atom->nangletypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void AngleCosineSquared::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&k[1],sizeof(double),atom->nangletypes,fp); fread(&theta0[1],sizeof(double),atom->nangletypes,fp); } MPI_Bcast(&k[1],atom->nangletypes,MPI_DOUBLE,0,world); MPI_Bcast(&theta0[1],atom->nangletypes,MPI_DOUBLE,0,world); for (int i = 1; i <= atom->nangletypes; i++) setflag[i] = 1; } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void AngleCosineSquared::write_data(FILE *fp) { for (int i = 1; i <= atom->nangletypes; i++) fprintf(fp,"%d %g %g\n",i,k[i],theta0[i]/MY_PI*180.0); } /* ---------------------------------------------------------------------- */ double AngleCosineSquared::single(int type, int i1, int i2, int i3) { double **x = atom->x; double delx1 = x[i1][0] - x[i2][0]; double dely1 = x[i1][1] - x[i2][1]; double delz1 = x[i1][2] - x[i2][2]; domain->minimum_image(delx1,dely1,delz1); double r1 = sqrt(delx1*delx1 + dely1*dely1 + delz1*delz1); double delx2 = x[i3][0] - x[i2][0]; double dely2 = x[i3][1] - x[i2][1]; double delz2 = x[i3][2] - x[i2][2]; domain->minimum_image(delx2,dely2,delz2); double r2 = sqrt(delx2*delx2 + dely2*dely2 + delz2*delz2); double c = delx1*delx2 + dely1*dely2 + delz1*delz2; c /= r1*r2; if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; double dcostheta = c - cos(theta0[type]); double tk = k[type] * dcostheta; return tk*dcostheta; } diff --git a/src/MOLECULE/angle_harmonic.cpp b/src/MOLECULE/angle_harmonic.cpp index cffc3182d..7e8b57b04 100644 --- a/src/MOLECULE/angle_harmonic.cpp +++ b/src/MOLECULE/angle_harmonic.cpp @@ -1,260 +1,260 @@ /* ---------------------------------------------------------------------- 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 #include #include "angle_harmonic.h" #include "atom.h" #include "neighbor.h" #include "domain.h" #include "comm.h" #include "force.h" #include "math_const.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace MathConst; #define SMALL 0.001 /* ---------------------------------------------------------------------- */ AngleHarmonic::AngleHarmonic(LAMMPS *lmp) : Angle(lmp) {} /* ---------------------------------------------------------------------- */ AngleHarmonic::~AngleHarmonic() { if (allocated && !copymode) { memory->destroy(setflag); memory->destroy(k); memory->destroy(theta0); } } /* ---------------------------------------------------------------------- */ void AngleHarmonic::compute(int eflag, int vflag) { int i1,i2,i3,n,type; double delx1,dely1,delz1,delx2,dely2,delz2; double eangle,f1[3],f3[3]; double dtheta,tk; double rsq1,rsq2,r1,r2,c,s,a,a11,a12,a22; eangle = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; int **anglelist = neighbor->anglelist; int nanglelist = neighbor->nanglelist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < nanglelist; n++) { i1 = anglelist[n][0]; i2 = anglelist[n][1]; i3 = anglelist[n][2]; type = anglelist[n][3]; // 1st bond delx1 = x[i1][0] - x[i2][0]; dely1 = x[i1][1] - x[i2][1]; delz1 = x[i1][2] - x[i2][2]; rsq1 = delx1*delx1 + dely1*dely1 + delz1*delz1; r1 = sqrt(rsq1); // 2nd bond delx2 = x[i3][0] - x[i2][0]; dely2 = x[i3][1] - x[i2][1]; delz2 = x[i3][2] - x[i2][2]; rsq2 = delx2*delx2 + dely2*dely2 + delz2*delz2; r2 = sqrt(rsq2); // angle (cos and sin) c = delx1*delx2 + dely1*dely2 + delz1*delz2; c /= r1*r2; if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; s = sqrt(1.0 - c*c); if (s < SMALL) s = SMALL; s = 1.0/s; // force & energy dtheta = acos(c) - theta0[type]; tk = k[type] * dtheta; if (eflag) eangle = tk*dtheta; a = -2.0 * tk * s; a11 = a*c / rsq1; a12 = -a / (r1*r2); a22 = a*c / rsq2; f1[0] = a11*delx1 + a12*delx2; f1[1] = a11*dely1 + a12*dely2; f1[2] = a11*delz1 + a12*delz2; f3[0] = a22*delx2 + a12*delx1; f3[1] = a22*dely2 + a12*dely1; f3[2] = a22*delz2 + a12*delz1; // apply force to each of 3 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += f1[0]; f[i1][1] += f1[1]; f[i1][2] += f1[2]; } if (newton_bond || i2 < nlocal) { f[i2][0] -= f1[0] + f3[0]; f[i2][1] -= f1[1] + f3[1]; f[i2][2] -= f1[2] + f3[2]; } if (newton_bond || i3 < nlocal) { f[i3][0] += f3[0]; f[i3][1] += f3[1]; f[i3][2] += f3[2]; } if (evflag) ev_tally(i1,i2,i3,nlocal,newton_bond,eangle,f1,f3, delx1,dely1,delz1,delx2,dely2,delz2); } } /* ---------------------------------------------------------------------- */ void AngleHarmonic::allocate() { allocated = 1; int n = atom->nangletypes; memory->create(k,n+1,"angle:k"); memory->create(theta0,n+1,"angle:theta0"); memory->create(setflag,n+1,"angle:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one or more types ------------------------------------------------------------------------- */ void AngleHarmonic::coeff(int narg, char **arg) { if (narg != 3) error->all(FLERR,"Incorrect args for angle coefficients"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->nangletypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->nangletypes,ilo,ihi); double k_one = force->numeric(FLERR,arg[1]); double theta0_one = force->numeric(FLERR,arg[2]); // convert theta0 from degrees to radians int count = 0; for (int i = ilo; i <= ihi; i++) { k[i] = k_one; theta0[i] = theta0_one/180.0 * MY_PI; setflag[i] = 1; count++; } if (count == 0) error->all(FLERR,"Incorrect args for angle coefficients"); } /* ---------------------------------------------------------------------- */ double AngleHarmonic::equilibrium_angle(int i) { return theta0[i]; } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void AngleHarmonic::write_restart(FILE *fp) { fwrite(&k[1],sizeof(double),atom->nangletypes,fp); fwrite(&theta0[1],sizeof(double),atom->nangletypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void AngleHarmonic::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&k[1],sizeof(double),atom->nangletypes,fp); fread(&theta0[1],sizeof(double),atom->nangletypes,fp); } MPI_Bcast(&k[1],atom->nangletypes,MPI_DOUBLE,0,world); MPI_Bcast(&theta0[1],atom->nangletypes,MPI_DOUBLE,0,world); for (int i = 1; i <= atom->nangletypes; i++) setflag[i] = 1; } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void AngleHarmonic::write_data(FILE *fp) { for (int i = 1; i <= atom->nangletypes; i++) fprintf(fp,"%d %g %g\n",i,k[i],theta0[i]/MY_PI*180.0); } /* ---------------------------------------------------------------------- */ double AngleHarmonic::single(int type, int i1, int i2, int i3) { double **x = atom->x; double delx1 = x[i1][0] - x[i2][0]; double dely1 = x[i1][1] - x[i2][1]; double delz1 = x[i1][2] - x[i2][2]; domain->minimum_image(delx1,dely1,delz1); double r1 = sqrt(delx1*delx1 + dely1*dely1 + delz1*delz1); double delx2 = x[i3][0] - x[i2][0]; double dely2 = x[i3][1] - x[i2][1]; double delz2 = x[i3][2] - x[i2][2]; domain->minimum_image(delx2,dely2,delz2); double r2 = sqrt(delx2*delx2 + dely2*dely2 + delz2*delz2); double c = delx1*delx2 + dely1*dely2 + delz1*delz2; c /= r1*r2; if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; double dtheta = acos(c) - theta0[type]; double tk = k[type] * dtheta; return tk*dtheta; } diff --git a/src/MOLECULE/angle_table.cpp b/src/MOLECULE/angle_table.cpp index 9dd992572..4d9007adb 100644 --- a/src/MOLECULE/angle_table.cpp +++ b/src/MOLECULE/angle_table.cpp @@ -1,662 +1,662 @@ /* ---------------------------------------------------------------------- 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: Chuanfu Luo (luochuanfu@gmail.com) ------------------------------------------------------------------------- */ #include #include #include #include "angle_table.h" #include "atom.h" #include "neighbor.h" #include "domain.h" #include "comm.h" #include "force.h" #include "math_const.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace MathConst; enum{LINEAR,SPLINE}; #define MAXLINE 1024 #define SMALL 0.001 #define TINY 1.E-10 /* ---------------------------------------------------------------------- */ AngleTable::AngleTable(LAMMPS *lmp) : Angle(lmp) { writedata = 0; ntables = 0; tables = NULL; } /* ---------------------------------------------------------------------- */ AngleTable::~AngleTable() { for (int m = 0; m < ntables; m++) free_table(&tables[m]); memory->sfree(tables); if (allocated) { memory->destroy(setflag); memory->destroy(theta0); memory->destroy(tabindex); } } /* ---------------------------------------------------------------------- */ void AngleTable::compute(int eflag, int vflag) { int i1,i2,i3,n,type; double eangle,f1[3],f3[3]; double delx1,dely1,delz1,delx2,dely2,delz2; double rsq1,rsq2,r1,r2,c,s,a,a11,a12,a22; double theta,u,mdu; //mdu: minus du, -du/dx=f eangle = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; int **anglelist = neighbor->anglelist; int nanglelist = neighbor->nanglelist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < nanglelist; n++) { i1 = anglelist[n][0]; i2 = anglelist[n][1]; i3 = anglelist[n][2]; type = anglelist[n][3]; // 1st bond delx1 = x[i1][0] - x[i2][0]; dely1 = x[i1][1] - x[i2][1]; delz1 = x[i1][2] - x[i2][2]; rsq1 = delx1*delx1 + dely1*dely1 + delz1*delz1; r1 = sqrt(rsq1); // 2nd bond delx2 = x[i3][0] - x[i2][0]; dely2 = x[i3][1] - x[i2][1]; delz2 = x[i3][2] - x[i2][2]; rsq2 = delx2*delx2 + dely2*dely2 + delz2*delz2; r2 = sqrt(rsq2); // angle (cos and sin) c = delx1*delx2 + dely1*dely2 + delz1*delz2; c /= r1*r2; if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; s = sqrt(1.0 - c*c); if (s < SMALL) s = SMALL; s = 1.0/s; // tabulated force & energy theta = acos(c); uf_lookup(type,theta,u,mdu); if (eflag) eangle = u; a = mdu * s; a11 = a*c / rsq1; a12 = -a / (r1*r2); a22 = a*c / rsq2; f1[0] = a11*delx1 + a12*delx2; f1[1] = a11*dely1 + a12*dely2; f1[2] = a11*delz1 + a12*delz2; f3[0] = a22*delx2 + a12*delx1; f3[1] = a22*dely2 + a12*dely1; f3[2] = a22*delz2 + a12*delz1; // apply force to each of 3 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += f1[0]; f[i1][1] += f1[1]; f[i1][2] += f1[2]; } if (newton_bond || i2 < nlocal) { f[i2][0] -= f1[0] + f3[0]; f[i2][1] -= f1[1] + f3[1]; f[i2][2] -= f1[2] + f3[2]; } if (newton_bond || i3 < nlocal) { f[i3][0] += f3[0]; f[i3][1] += f3[1]; f[i3][2] += f3[2]; } if (evflag) ev_tally(i1,i2,i3,nlocal,newton_bond,eangle,f1,f3, delx1,dely1,delz1,delx2,dely2,delz2); } } /* ---------------------------------------------------------------------- */ void AngleTable::allocate() { allocated = 1; int n = atom->nangletypes; memory->create(theta0,n+1,"angle:theta0"); memory->create(tabindex,n+1,"angle:tabindex"); memory->create(setflag,n+1,"angle:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void AngleTable::settings(int narg, char **arg) { if (narg != 2) error->all(FLERR,"Illegal angle_style command"); if (strcmp(arg[0],"linear") == 0) tabstyle = LINEAR; else if (strcmp(arg[0],"spline") == 0) tabstyle = SPLINE; else error->all(FLERR,"Unknown table style in angle style table"); tablength = force->inumeric(FLERR,arg[1]); if (tablength < 2) error->all(FLERR,"Illegal number of angle 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(tabindex); } allocated = 0; ntables = 0; tables = NULL; } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void AngleTable::coeff(int narg, char **arg) { if (narg != 3) error->all(FLERR,"Illegal angle_coeff command"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->nangletypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->nangletypes,ilo,ihi); int me; MPI_Comm_rank(world,&me); tables = (Table *) memory->srealloc(tables,(ntables+1)*sizeof(Table),"angle:tables"); Table *tb = &tables[ntables]; null_table(tb); if (me == 0) read_table(tb,arg[1],arg[2]); bcast_table(tb); // error check on table parameters if (tb->ninput <= 1) error->one(FLERR,"Invalid angle table length"); double alo,ahi; alo = tb->afile[0]; ahi = tb->afile[tb->ninput-1]; if (fabs(alo-0.0) > TINY || fabs(ahi-180.0) > TINY) error->all(FLERR,"Angle table must range from 0 to 180 degrees"); // convert theta from degrees to radians for (int i = 0; i < tb->ninput; i++){ tb->afile[i] *= MY_PI/180.0; tb->ffile[i] *= 180.0/MY_PI; } // spline read-in and compute a,e,f vectors within table spline_table(tb); compute_table(tb); // store ptr to table in tabindex int count = 0; for (int i = ilo; i <= ihi; i++) { tabindex[i] = ntables; setflag[i] = 1; theta0[i] = tb->theta0; count++; } ntables++; if (count == 0) error->all(FLERR,"Illegal angle_coeff command"); } /* ---------------------------------------------------------------------- return an equilbrium angle length should not be used, since don't know minimum of tabulated function ------------------------------------------------------------------------- */ double AngleTable::equilibrium_angle(int i) { return theta0[i]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void AngleTable::write_restart(FILE *fp) { fwrite(&tabstyle,sizeof(int),1,fp); fwrite(&tablength,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void AngleTable::read_restart(FILE *fp) { if (comm->me == 0) { fread(&tabstyle,sizeof(int),1,fp); fread(&tablength,sizeof(int),1,fp); } MPI_Bcast(&tabstyle,1,MPI_INT,0,world); MPI_Bcast(&tablength,1,MPI_INT,0,world); allocate(); } /* ---------------------------------------------------------------------- */ double AngleTable::single(int type, int i1, int i2, int i3) { double **x = atom->x; double delx1 = x[i1][0] - x[i2][0]; double dely1 = x[i1][1] - x[i2][1]; double delz1 = x[i1][2] - x[i2][2]; domain->minimum_image(delx1,dely1,delz1); double r1 = sqrt(delx1*delx1 + dely1*dely1 + delz1*delz1); double delx2 = x[i3][0] - x[i2][0]; double dely2 = x[i3][1] - x[i2][1]; double delz2 = x[i3][2] - x[i2][2]; domain->minimum_image(delx2,dely2,delz2); double r2 = sqrt(delx2*delx2 + dely2*dely2 + delz2*delz2); double c = delx1*delx2 + dely1*dely2 + delz1*delz2; c /= r1*r2; if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; double theta = acos(c); double u=0.0; u_lookup(type,theta,u); return u; } /* ---------------------------------------------------------------------- */ void AngleTable::null_table(Table *tb) { tb->afile = tb->efile = tb->ffile = NULL; tb->e2file = tb->f2file = NULL; tb->ang = tb->e = tb->de = NULL; tb->f = tb->df = tb->e2 = tb->f2 = NULL; } /* ---------------------------------------------------------------------- */ void AngleTable::free_table(Table *tb) { memory->destroy(tb->afile); memory->destroy(tb->efile); memory->destroy(tb->ffile); memory->destroy(tb->e2file); memory->destroy(tb->f2file); memory->destroy(tb->ang); memory->destroy(tb->e); memory->destroy(tb->de); memory->destroy(tb->f); memory->destroy(tb->df); memory->destroy(tb->e2); memory->destroy(tb->f2); } /* ---------------------------------------------------------------------- read table file, only called by proc 0 ------------------------------------------------------------------------- */ void AngleTable::read_table(Table *tb, char *file, char *keyword) { char line[MAXLINE]; // open file FILE *fp = force->open_potential(file); 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") == strlen(line)) continue; // blank line if (line[0] == '#') continue; // comment char *word = strtok(line," \t\n\r"); if (strcmp(word,keyword) == 0) 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->afile,tb->ninput,"angle:afile"); memory->create(tb->efile,tb->ninput,"angle:efile"); memory->create(tb->ffile,tb->ninput,"angle:ffile"); // read a,e,f table values from file int itmp; fgets(line,MAXLINE,fp); for (int i = 0; i < tb->ninput; i++) { fgets(line,MAXLINE,fp); sscanf(line,"%d %lg %lg %lg", &itmp,&tb->afile[i],&tb->efile[i],&tb->ffile[i]); } fclose(fp); } /* ---------------------------------------------------------------------- build spline representation of e,f over entire range of read-in table this function sets these values in e2file,f2file ------------------------------------------------------------------------- */ void AngleTable::spline_table(Table *tb) { memory->create(tb->e2file,tb->ninput,"angle:e2file"); memory->create(tb->f2file,tb->ninput,"angle:f2file"); double ep0 = - tb->ffile[0]; double epn = - tb->ffile[tb->ninput-1]; spline(tb->afile,tb->efile,tb->ninput,ep0,epn,tb->e2file); if (tb->fpflag == 0) { tb->fplo = (tb->ffile[1] - tb->ffile[0]) / (tb->afile[1] - tb->afile[0]); tb->fphi = (tb->ffile[tb->ninput-1] - tb->ffile[tb->ninput-2]) / (tb->afile[tb->ninput-1] - tb->afile[tb->ninput-2]); } double fp0 = tb->fplo; double fpn = tb->fphi; spline(tb->afile,tb->ffile,tb->ninput,fp0,fpn,tb->f2file); } /* ---------------------------------------------------------------------- compute a,e,f vectors from splined values ------------------------------------------------------------------------- */ void AngleTable::compute_table(Table *tb) { // delta = table spacing in angle for N-1 bins int tlm1 = tablength-1; tb->delta = MY_PI / tlm1; tb->invdelta = 1.0/tb->delta; tb->deltasq6 = tb->delta*tb->delta / 6.0; // N-1 evenly spaced bins in angle from 0 to PI // ang,e,f = value at lower edge of bin // de,df values = delta values of e,f // ang,e,f are N in length so de,df arrays can compute difference memory->create(tb->ang,tablength,"angle:ang"); memory->create(tb->e,tablength,"angle:e"); memory->create(tb->de,tlm1,"angle:de"); memory->create(tb->f,tablength,"angle:f"); memory->create(tb->df,tlm1,"angle:df"); memory->create(tb->e2,tablength,"angle:e2"); memory->create(tb->f2,tablength,"angle:f2"); double a; for (int i = 0; i < tablength; i++) { a = i*tb->delta; tb->ang[i] = a; tb->e[i] = splint(tb->afile,tb->efile,tb->e2file,tb->ninput,a); tb->f[i] = splint(tb->afile,tb->ffile,tb->f2file,tb->ninput,a); } 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]; } double ep0 = - tb->f[0]; double epn = - tb->f[tlm1]; spline(tb->ang,tb->e,tablength,ep0,epn,tb->e2); spline(tb->ang,tb->f,tablength,tb->fplo,tb->fphi,tb->f2); } /* ---------------------------------------------------------------------- extract attributes from parameter line in table section format of line: N value FP fplo fphi EQ theta0 N is required, other params are optional ------------------------------------------------------------------------- */ void AngleTable::param_extract(Table *tb, char *line) { tb->ninput = 0; tb->fpflag = 0; tb->theta0 = 180.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,"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); tb->fplo *= (180.0/MY_PI)*(180.0/MY_PI); tb->fphi *= (180.0/MY_PI)*(180.0/MY_PI); } else if (strcmp(word,"EQ") == 0) { word = strtok(NULL," \t\n\r\f"); tb->theta0 = atof(word); } else { error->one(FLERR,"Invalid keyword in angle table parameters"); } word = strtok(NULL," \t\n\r\f"); } if (tb->ninput == 0) error->one(FLERR,"Angle table parameters did not set N"); } /* ---------------------------------------------------------------------- broadcast read-in table info from proc 0 to other procs this function communicates these values in Table: ninput,afile,efile,ffile,fpflag,fplo,fphi,theta0 ------------------------------------------------------------------------- */ void AngleTable::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->afile,tb->ninput,"angle:afile"); memory->create(tb->efile,tb->ninput,"angle:efile"); memory->create(tb->ffile,tb->ninput,"angle:ffile"); } MPI_Bcast(tb->afile,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->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); } MPI_Bcast(&tb->theta0,1,MPI_DOUBLE,0,world); } /* ---------------------------------------------------------------------- spline and splint routines modified from Numerical Recipes ------------------------------------------------------------------------- */ void AngleTable::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 AngleTable::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; } /* ---------------------------------------------------------------------- calculate potential u and force f at angle x ------------------------------------------------------------------------- */ void AngleTable::uf_lookup(int type, double x, double &u, double &f) { int itable; double fraction,a,b; Table *tb = &tables[tabindex[type]]; if (tabstyle == LINEAR) { itable = static_cast ( x * tb->invdelta); fraction = (x - tb->ang[itable]) * tb->invdelta; u = tb->e[itable] + fraction*tb->de[itable]; f = tb->f[itable] + fraction*tb->df[itable]; } else if (tabstyle == SPLINE) { itable = static_cast ( x * tb->invdelta); fraction = (x - tb->ang[itable]) * tb->invdelta; b = (x - tb->ang[itable]) * tb->invdelta; a = 1.0 - b; u = 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; f = 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; } } /* ---------------------------------------------------------------------- calculate potential u at angle x ------------------------------------------------------------------------- */ void AngleTable::u_lookup(int type, double x, double &u) { int itable; double fraction,a,b; Table *tb = &tables[tabindex[type]]; if (tabstyle == LINEAR) { itable = static_cast ( x * tb->invdelta); fraction = (x - tb->ang[itable]) * tb->invdelta; u = tb->e[itable] + fraction*tb->de[itable]; } else if (tabstyle == SPLINE) { itable = static_cast ( x * tb->invdelta); fraction = (x - tb->ang[itable]) * tb->invdelta; b = (x - tb->ang[itable]) * tb->invdelta; a = 1.0 - b; u = 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; } } diff --git a/src/MOLECULE/bond_fene.cpp b/src/MOLECULE/bond_fene.cpp index 66c5c0817..5d58f2683 100644 --- a/src/MOLECULE/bond_fene.cpp +++ b/src/MOLECULE/bond_fene.cpp @@ -1,275 +1,275 @@ /* ---------------------------------------------------------------------- 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 #include #include "bond_fene.h" #include "atom.h" #include "neighbor.h" #include "domain.h" #include "comm.h" #include "update.h" #include "force.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ BondFENE::BondFENE(LAMMPS *lmp) : Bond(lmp) { TWO_1_3 = pow(2.0,(1.0/3.0)); } /* ---------------------------------------------------------------------- */ BondFENE::~BondFENE() { if (allocated && !copymode) { memory->destroy(setflag); memory->destroy(k); memory->destroy(r0); memory->destroy(epsilon); memory->destroy(sigma); } } /* ---------------------------------------------------------------------- */ void BondFENE::compute(int eflag, int vflag) { int i1,i2,n,type; double delx,dely,delz,ebond,fbond; double rsq,r0sq,rlogarg,sr2,sr6; ebond = sr6 = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; int **bondlist = neighbor->bondlist; int nbondlist = neighbor->nbondlist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < nbondlist; n++) { i1 = bondlist[n][0]; i2 = bondlist[n][1]; type = bondlist[n][2]; delx = x[i1][0] - x[i2][0]; dely = x[i1][1] - x[i2][1]; delz = x[i1][2] - x[i2][2]; // force from log term rsq = delx*delx + dely*dely + delz*delz; r0sq = r0[type] * r0[type]; rlogarg = 1.0 - rsq/r0sq; // if r -> r0, then rlogarg < 0.0 which is an error // issue a warning and reset rlogarg = epsilon // if r > 2*r0 something serious is wrong, abort if (rlogarg < 0.1) { char str[128]; sprintf(str,"FENE bond too long: " BIGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " %g", update->ntimestep,atom->tag[i1],atom->tag[i2],sqrt(rsq)); error->warning(FLERR,str,0); if (rlogarg <= -3.0) error->one(FLERR,"Bad FENE bond"); rlogarg = 0.1; } fbond = -k[type]/rlogarg; // force from LJ term if (rsq < TWO_1_3*sigma[type]*sigma[type]) { sr2 = sigma[type]*sigma[type]/rsq; sr6 = sr2*sr2*sr2; fbond += 48.0*epsilon[type]*sr6*(sr6-0.5)/rsq; } // energy if (eflag) { ebond = -0.5 * k[type]*r0sq*log(rlogarg); if (rsq < TWO_1_3*sigma[type]*sigma[type]) ebond += 4.0*epsilon[type]*sr6*(sr6-1.0) + epsilon[type]; } // apply force to each of 2 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += delx*fbond; f[i1][1] += dely*fbond; f[i1][2] += delz*fbond; } if (newton_bond || i2 < nlocal) { f[i2][0] -= delx*fbond; f[i2][1] -= dely*fbond; f[i2][2] -= delz*fbond; } if (evflag) ev_tally(i1,i2,nlocal,newton_bond,ebond,fbond,delx,dely,delz); } } /* ---------------------------------------------------------------------- */ void BondFENE::allocate() { allocated = 1; int n = atom->nbondtypes; memory->create(k,n+1,"bond:k"); memory->create(r0,n+1,"bond:r0"); memory->create(epsilon,n+1,"bond:epsilon"); memory->create(sigma,n+1,"bond:sigma"); memory->create(setflag,n+1,"bond:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one type ------------------------------------------------------------------------- */ void BondFENE::coeff(int narg, char **arg) { if (narg != 5) error->all(FLERR,"Incorrect args for bond coefficients"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->nbondtypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->nbondtypes,ilo,ihi); double k_one = force->numeric(FLERR,arg[1]); double r0_one = force->numeric(FLERR,arg[2]); double epsilon_one = force->numeric(FLERR,arg[3]); double sigma_one = force->numeric(FLERR,arg[4]); int count = 0; for (int i = ilo; i <= ihi; i++) { k[i] = k_one; r0[i] = r0_one; epsilon[i] = epsilon_one; sigma[i] = sigma_one; setflag[i] = 1; count++; } if (count == 0) error->all(FLERR,"Incorrect args for bond coefficients"); } /* ---------------------------------------------------------------------- check if special_bond settings are valid ------------------------------------------------------------------------- */ void BondFENE::init_style() { // special bonds should be 0 1 1 if (force->special_lj[1] != 0.0 || force->special_lj[2] != 1.0 || force->special_lj[3] != 1.0) { if (comm->me == 0) error->warning(FLERR,"Use special bonds = 0,1,1 with bond style fene"); } } /* ---------------------------------------------------------------------- */ double BondFENE::equilibrium_distance(int i) { return 0.97*sigma[i]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void BondFENE::write_restart(FILE *fp) { fwrite(&k[1],sizeof(double),atom->nbondtypes,fp); fwrite(&r0[1],sizeof(double),atom->nbondtypes,fp); fwrite(&epsilon[1],sizeof(double),atom->nbondtypes,fp); fwrite(&sigma[1],sizeof(double),atom->nbondtypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void BondFENE::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&k[1],sizeof(double),atom->nbondtypes,fp); fread(&r0[1],sizeof(double),atom->nbondtypes,fp); fread(&epsilon[1],sizeof(double),atom->nbondtypes,fp); fread(&sigma[1],sizeof(double),atom->nbondtypes,fp); } MPI_Bcast(&k[1],atom->nbondtypes,MPI_DOUBLE,0,world); MPI_Bcast(&r0[1],atom->nbondtypes,MPI_DOUBLE,0,world); MPI_Bcast(&epsilon[1],atom->nbondtypes,MPI_DOUBLE,0,world); MPI_Bcast(&sigma[1],atom->nbondtypes,MPI_DOUBLE,0,world); for (int i = 1; i <= atom->nbondtypes; i++) setflag[i] = 1; } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void BondFENE::write_data(FILE *fp) { for (int i = 1; i <= atom->nbondtypes; i++) fprintf(fp,"%d %g %g %g %g\n",i,k[i],r0[i],epsilon[i],sigma[i]); } /* ---------------------------------------------------------------------- */ double BondFENE::single(int type, double rsq, int i, int j, double &fforce) { double r0sq = r0[type] * r0[type]; double rlogarg = 1.0 - rsq/r0sq; // if r -> r0, then rlogarg < 0.0 which is an error // issue a warning and reset rlogarg = epsilon // if r > 2*r0 something serious is wrong, abort if (rlogarg < 0.1) { char str[128]; sprintf(str,"FENE bond too long: " BIGINT_FORMAT " %g", update->ntimestep,sqrt(rsq)); error->warning(FLERR,str,0); if (rlogarg <= -3.0) error->one(FLERR,"Bad FENE bond"); rlogarg = 0.1; } double eng = -0.5 * k[type]*r0sq*log(rlogarg); fforce = -k[type]/rlogarg; if (rsq < TWO_1_3*sigma[type]*sigma[type]) { double sr2,sr6; sr2 = sigma[type]*sigma[type]/rsq; sr6 = sr2*sr2*sr2; eng += 4.0*epsilon[type]*sr6*(sr6-1.0) + epsilon[type]; fforce += 48.0*epsilon[type]*sr6*(sr6-0.5)/rsq; } return eng; } diff --git a/src/MOLECULE/bond_fene_expand.cpp b/src/MOLECULE/bond_fene_expand.cpp index f65632cc3..033f8d650 100644 --- a/src/MOLECULE/bond_fene_expand.cpp +++ b/src/MOLECULE/bond_fene_expand.cpp @@ -1,289 +1,289 @@ /* ---------------------------------------------------------------------- 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 #include #include "bond_fene_expand.h" #include "atom.h" #include "neighbor.h" #include "domain.h" #include "comm.h" #include "update.h" #include "force.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ BondFENEExpand::BondFENEExpand(LAMMPS *lmp) : Bond(lmp) { TWO_1_3 = pow(2.0,(1.0/3.0)); } /* ---------------------------------------------------------------------- */ BondFENEExpand::~BondFENEExpand() { if (allocated) { memory->destroy(setflag); memory->destroy(k); memory->destroy(r0); memory->destroy(epsilon); memory->destroy(sigma); memory->destroy(shift); } } /* ---------------------------------------------------------------------- */ void BondFENEExpand::compute(int eflag, int vflag) { int i1,i2,n,type; double delx,dely,delz,ebond,fbond; double rsq,r0sq,rlogarg,sr2,sr6; double r,rshift,rshiftsq; ebond = sr6 = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; int **bondlist = neighbor->bondlist; int nbondlist = neighbor->nbondlist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < nbondlist; n++) { i1 = bondlist[n][0]; i2 = bondlist[n][1]; type = bondlist[n][2]; delx = x[i1][0] - x[i2][0]; dely = x[i1][1] - x[i2][1]; delz = x[i1][2] - x[i2][2]; // force from log term rsq = delx*delx + dely*dely + delz*delz; r = sqrt(rsq); rshift = r - shift[type]; rshiftsq = rshift*rshift; r0sq = r0[type] * r0[type]; rlogarg = 1.0 - rshiftsq/r0sq; // if r -> r0, then rlogarg < 0.0 which is an error // issue a warning and reset rlogarg = epsilon // if r > 2*r0 something serious is wrong, abort if (rlogarg < 0.1) { char str[128]; sprintf(str,"FENE bond too long: " BIGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " %g", update->ntimestep,atom->tag[i1],atom->tag[i2],sqrt(rsq)); error->warning(FLERR,str,0); if (rlogarg <= -3.0) error->one(FLERR,"Bad FENE bond"); rlogarg = 0.1; } fbond = -k[type]*rshift/rlogarg/r; // force from LJ term if (rshiftsq < TWO_1_3*sigma[type]*sigma[type]) { sr2 = sigma[type]*sigma[type]/rshiftsq; sr6 = sr2*sr2*sr2; fbond += 48.0*epsilon[type]*sr6*(sr6-0.5)/rshift/r; } // energy if (eflag) { ebond = -0.5 * k[type]*r0sq*log(rlogarg); if (rshiftsq < TWO_1_3*sigma[type]*sigma[type]) ebond += 4.0*epsilon[type]*sr6*(sr6-1.0) + epsilon[type]; } // apply force to each of 2 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += delx*fbond; f[i1][1] += dely*fbond; f[i1][2] += delz*fbond; } if (newton_bond || i2 < nlocal) { f[i2][0] -= delx*fbond; f[i2][1] -= dely*fbond; f[i2][2] -= delz*fbond; } if (evflag) ev_tally(i1,i2,nlocal,newton_bond,ebond,fbond,delx,dely,delz); } } /* ---------------------------------------------------------------------- */ void BondFENEExpand::allocate() { allocated = 1; int n = atom->nbondtypes; memory->create(k,n+1,"bond:k"); memory->create(r0,n+1,"bond:r0"); memory->create(epsilon,n+1,"bond:epsilon"); memory->create(sigma,n+1,"bond:sigma"); memory->create(shift,n+1,"bond:shift"); memory->create(setflag,n+1,"bond:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one type ------------------------------------------------------------------------- */ void BondFENEExpand::coeff(int narg, char **arg) { if (narg != 6) error->all(FLERR,"Incorrect args for bond coefficients"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->nbondtypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->nbondtypes,ilo,ihi); double k_one = force->numeric(FLERR,arg[1]); double r0_one = force->numeric(FLERR,arg[2]); double epsilon_one = force->numeric(FLERR,arg[3]); double sigma_one = force->numeric(FLERR,arg[4]); double shift_one = force->numeric(FLERR,arg[5]); int count = 0; for (int i = ilo; i <= ihi; i++) { k[i] = k_one; r0[i] = r0_one; epsilon[i] = epsilon_one; sigma[i] = sigma_one; shift[i] = shift_one; setflag[i] = 1; count++; } if (count == 0) error->all(FLERR,"Incorrect args for bond coefficients"); } /* ---------------------------------------------------------------------- check if special_bond settings are valid ------------------------------------------------------------------------- */ void BondFENEExpand::init_style() { // special bonds should be 0 1 1 if (force->special_lj[1] != 0.0 || force->special_lj[2] != 1.0 || force->special_lj[3] != 1.0) { if (comm->me == 0) error->warning(FLERR,"Use special bonds = 0,1,1 with bond style fene/expand"); } } /* ---------------------------------------------------------------------- */ double BondFENEExpand::equilibrium_distance(int i) { return 0.97*sigma[i] + shift[i]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void BondFENEExpand::write_restart(FILE *fp) { fwrite(&k[1],sizeof(double),atom->nbondtypes,fp); fwrite(&r0[1],sizeof(double),atom->nbondtypes,fp); fwrite(&epsilon[1],sizeof(double),atom->nbondtypes,fp); fwrite(&sigma[1],sizeof(double),atom->nbondtypes,fp); fwrite(&shift[1],sizeof(double),atom->nbondtypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void BondFENEExpand::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&k[1],sizeof(double),atom->nbondtypes,fp); fread(&r0[1],sizeof(double),atom->nbondtypes,fp); fread(&epsilon[1],sizeof(double),atom->nbondtypes,fp); fread(&sigma[1],sizeof(double),atom->nbondtypes,fp); fread(&shift[1],sizeof(double),atom->nbondtypes,fp); } MPI_Bcast(&k[1],atom->nbondtypes,MPI_DOUBLE,0,world); MPI_Bcast(&r0[1],atom->nbondtypes,MPI_DOUBLE,0,world); MPI_Bcast(&epsilon[1],atom->nbondtypes,MPI_DOUBLE,0,world); MPI_Bcast(&sigma[1],atom->nbondtypes,MPI_DOUBLE,0,world); MPI_Bcast(&shift[1],atom->nbondtypes,MPI_DOUBLE,0,world); for (int i = 1; i <= atom->nbondtypes; i++) setflag[i] = 1; } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void BondFENEExpand::write_data(FILE *fp) { for (int i = 1; i <= atom->nbondtypes; i++) fprintf(fp,"%d %g %g %g %g %g\n",i,k[i],r0[i],epsilon[i],sigma[i],shift[i]); } /* ---------------------------------------------------------------------- */ double BondFENEExpand::single(int type, double rsq, int i, int j, double &fforce) { double r = sqrt(rsq); double rshift = r - shift[type]; double rshiftsq = rshift*rshift; double r0sq = r0[type] * r0[type]; double rlogarg = 1.0 - rshiftsq/r0sq; // if r -> r0, then rlogarg < 0.0 which is an error // issue a warning and reset rlogarg = epsilon // if r > 2*r0 something serious is wrong, abort if (rlogarg < 0.1) { char str[128]; sprintf(str,"FENE bond too long: " BIGINT_FORMAT " %g", update->ntimestep,sqrt(rsq)); error->warning(FLERR,str,0); if (rlogarg <= -3.0) error->one(FLERR,"Bad FENE bond"); rlogarg = 0.1; } double eng = -0.5 * k[type]*r0sq*log(rlogarg); fforce = -k[type]*rshift/rlogarg/r; if (rshiftsq < TWO_1_3*sigma[type]*sigma[type]) { double sr2,sr6; sr2 = sigma[type]*sigma[type]/rshiftsq; sr6 = sr2*sr2*sr2; eng += 4.0*epsilon[type]*sr6*(sr6-1.0) + epsilon[type]; fforce += 48.0*epsilon[type]*sr6*(sr6-0.5)/rshift/r; } return eng; } diff --git a/src/MOLECULE/bond_harmonic.cpp b/src/MOLECULE/bond_harmonic.cpp index 8c5663bf7..f164a51de 100644 --- a/src/MOLECULE/bond_harmonic.cpp +++ b/src/MOLECULE/bond_harmonic.cpp @@ -1,198 +1,198 @@ /* ---------------------------------------------------------------------- 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 #include #include "bond_harmonic.h" #include "atom.h" #include "neighbor.h" #include "domain.h" #include "comm.h" #include "force.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ BondHarmonic::BondHarmonic(LAMMPS *lmp) : Bond(lmp) {} /* ---------------------------------------------------------------------- */ BondHarmonic::~BondHarmonic() { if (allocated && !copymode) { memory->destroy(setflag); memory->destroy(k); memory->destroy(r0); } } /* ---------------------------------------------------------------------- */ void BondHarmonic::compute(int eflag, int vflag) { int i1,i2,n,type; double delx,dely,delz,ebond,fbond; double rsq,r,dr,rk; ebond = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; int **bondlist = neighbor->bondlist; int nbondlist = neighbor->nbondlist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < nbondlist; n++) { i1 = bondlist[n][0]; i2 = bondlist[n][1]; type = bondlist[n][2]; delx = x[i1][0] - x[i2][0]; dely = x[i1][1] - x[i2][1]; delz = x[i1][2] - x[i2][2]; rsq = delx*delx + dely*dely + delz*delz; r = sqrt(rsq); dr = r - r0[type]; rk = k[type] * dr; // force & energy if (r > 0.0) fbond = -2.0*rk/r; else fbond = 0.0; if (eflag) ebond = rk*dr; // apply force to each of 2 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += delx*fbond; f[i1][1] += dely*fbond; f[i1][2] += delz*fbond; } if (newton_bond || i2 < nlocal) { f[i2][0] -= delx*fbond; f[i2][1] -= dely*fbond; f[i2][2] -= delz*fbond; } if (evflag) ev_tally(i1,i2,nlocal,newton_bond,ebond,fbond,delx,dely,delz); } } /* ---------------------------------------------------------------------- */ void BondHarmonic::allocate() { allocated = 1; int n = atom->nbondtypes; memory->create(k,n+1,"bond:k"); memory->create(r0,n+1,"bond:r0"); memory->create(setflag,n+1,"bond:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one or more types ------------------------------------------------------------------------- */ void BondHarmonic::coeff(int narg, char **arg) { if (narg != 3) error->all(FLERR,"Incorrect args for bond coefficients"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->nbondtypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->nbondtypes,ilo,ihi); double k_one = force->numeric(FLERR,arg[1]); double r0_one = force->numeric(FLERR,arg[2]); int count = 0; for (int i = ilo; i <= ihi; i++) { k[i] = k_one; r0[i] = r0_one; setflag[i] = 1; count++; } if (count == 0) error->all(FLERR,"Incorrect args for bond coefficients"); } /* ---------------------------------------------------------------------- return an equilbrium bond length ------------------------------------------------------------------------- */ double BondHarmonic::equilibrium_distance(int i) { return r0[i]; } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void BondHarmonic::write_restart(FILE *fp) { fwrite(&k[1],sizeof(double),atom->nbondtypes,fp); fwrite(&r0[1],sizeof(double),atom->nbondtypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void BondHarmonic::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&k[1],sizeof(double),atom->nbondtypes,fp); fread(&r0[1],sizeof(double),atom->nbondtypes,fp); } MPI_Bcast(&k[1],atom->nbondtypes,MPI_DOUBLE,0,world); MPI_Bcast(&r0[1],atom->nbondtypes,MPI_DOUBLE,0,world); for (int i = 1; i <= atom->nbondtypes; i++) setflag[i] = 1; } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void BondHarmonic::write_data(FILE *fp) { for (int i = 1; i <= atom->nbondtypes; i++) fprintf(fp,"%d %g %g\n",i,k[i],r0[i]); } /* ---------------------------------------------------------------------- */ double BondHarmonic::single(int type, double rsq, int i, int j, double &fforce) { double r = sqrt(rsq); double dr = r - r0[type]; double rk = k[type] * dr; fforce = 0; if (r > 0.0) fforce = -2.0*rk/r; return rk*dr; } diff --git a/src/MOLECULE/bond_morse.cpp b/src/MOLECULE/bond_morse.cpp index da2717899..3204a0ca6 100644 --- a/src/MOLECULE/bond_morse.cpp +++ b/src/MOLECULE/bond_morse.cpp @@ -1,208 +1,208 @@ /* ---------------------------------------------------------------------- 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: Jeff Greathouse (SNL) ------------------------------------------------------------------------- */ #include #include #include "bond_morse.h" #include "atom.h" #include "neighbor.h" #include "domain.h" #include "comm.h" #include "force.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ BondMorse::BondMorse(LAMMPS *lmp) : Bond(lmp) {} /* ---------------------------------------------------------------------- */ BondMorse::~BondMorse() { if (allocated) { memory->destroy(setflag); memory->destroy(d0); memory->destroy(alpha); memory->destroy(r0); } } /* ---------------------------------------------------------------------- */ void BondMorse::compute(int eflag, int vflag) { int i1,i2,n,type; double delx,dely,delz,ebond,fbond; double rsq,r,dr,ralpha; ebond = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; int **bondlist = neighbor->bondlist; int nbondlist = neighbor->nbondlist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < nbondlist; n++) { i1 = bondlist[n][0]; i2 = bondlist[n][1]; type = bondlist[n][2]; delx = x[i1][0] - x[i2][0]; dely = x[i1][1] - x[i2][1]; delz = x[i1][2] - x[i2][2]; rsq = delx*delx + dely*dely + delz*delz; r = sqrt(rsq); dr = r - r0[type]; ralpha = exp(-alpha[type]*dr); // force & energy if (r > 0.0) fbond = -2.0*d0[type]*alpha[type]*(1-ralpha)*ralpha/r; else fbond = 0.0; if (eflag) ebond = d0[type]*(1-ralpha)*(1-ralpha); // apply force to each of 2 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += delx*fbond; f[i1][1] += dely*fbond; f[i1][2] += delz*fbond; } if (newton_bond || i2 < nlocal) { f[i2][0] -= delx*fbond; f[i2][1] -= dely*fbond; f[i2][2] -= delz*fbond; } if (evflag) ev_tally(i1,i2,nlocal,newton_bond,ebond,fbond,delx,dely,delz); } } /* ---------------------------------------------------------------------- */ void BondMorse::allocate() { allocated = 1; int n = atom->nbondtypes; memory->create(d0,n+1,"bond:d0"); memory->create(alpha,n+1,"bond:alpha"); memory->create(r0,n+1,"bond:r0"); memory->create(setflag,n+1,"bond:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one type ------------------------------------------------------------------------- */ void BondMorse::coeff(int narg, char **arg) { if (narg != 4) error->all(FLERR,"Incorrect args for bond coefficients"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->nbondtypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->nbondtypes,ilo,ihi); double d0_one = force->numeric(FLERR,arg[1]); double alpha_one = force->numeric(FLERR,arg[2]); double r0_one = force->numeric(FLERR,arg[3]); int count = 0; for (int i = ilo; i <= ihi; i++) { d0[i] = d0_one; alpha[i] = alpha_one; r0[i] = r0_one; setflag[i] = 1; count++; } if (count == 0) error->all(FLERR,"Incorrect args for bond coefficients"); } /* ---------------------------------------------------------------------- return an equilbrium bond length ------------------------------------------------------------------------- */ double BondMorse::equilibrium_distance(int i) { return r0[i]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void BondMorse::write_restart(FILE *fp) { fwrite(&d0[1],sizeof(double),atom->nbondtypes,fp); fwrite(&alpha[1],sizeof(double),atom->nbondtypes,fp); fwrite(&r0[1],sizeof(double),atom->nbondtypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void BondMorse::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&d0[1],sizeof(double),atom->nbondtypes,fp); fread(&alpha[1],sizeof(double),atom->nbondtypes,fp); fread(&r0[1],sizeof(double),atom->nbondtypes,fp); } MPI_Bcast(&d0[1],atom->nbondtypes,MPI_DOUBLE,0,world); MPI_Bcast(&alpha[1],atom->nbondtypes,MPI_DOUBLE,0,world); MPI_Bcast(&r0[1],atom->nbondtypes,MPI_DOUBLE,0,world); for (int i = 1; i <= atom->nbondtypes; i++) setflag[i] = 1; } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void BondMorse::write_data(FILE *fp) { for (int i = 1; i <= atom->nbondtypes; i++) fprintf(fp,"%d %g %g %g\n",i,d0[i],alpha[i],r0[i]); } /* ---------------------------------------------------------------------- */ double BondMorse::single(int type, double rsq, int i, int j, double &fforce) { double r = sqrt(rsq); double dr = r - r0[type]; double ralpha = exp(-alpha[type]*dr); fforce = 0; if (r > 0.0) fforce = -2.0*d0[type]*alpha[type]*(1-ralpha)*ralpha/r; return d0[type]*(1-ralpha)*(1-ralpha); } diff --git a/src/MOLECULE/bond_nonlinear.cpp b/src/MOLECULE/bond_nonlinear.cpp index 9da2993c5..edd9dcd4e 100644 --- a/src/MOLECULE/bond_nonlinear.cpp +++ b/src/MOLECULE/bond_nonlinear.cpp @@ -1,205 +1,205 @@ /* ---------------------------------------------------------------------- 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 #include #include "bond_nonlinear.h" #include "atom.h" #include "neighbor.h" #include "domain.h" #include "comm.h" #include "force.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ BondNonlinear::BondNonlinear(LAMMPS *lmp) : Bond(lmp) {} /* ---------------------------------------------------------------------- */ BondNonlinear::~BondNonlinear() { if (allocated) { memory->destroy(setflag); memory->destroy(epsilon); memory->destroy(r0); memory->destroy(lamda); } } /* ---------------------------------------------------------------------- */ void BondNonlinear::compute(int eflag, int vflag) { int i1,i2,n,type; double delx,dely,delz,ebond,fbond; double rsq,r,dr,drsq,lamdasq,denom,denomsq; ebond = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; int **bondlist = neighbor->bondlist; int nbondlist = neighbor->nbondlist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < nbondlist; n++) { i1 = bondlist[n][0]; i2 = bondlist[n][1]; type = bondlist[n][2]; delx = x[i1][0] - x[i2][0]; dely = x[i1][1] - x[i2][1]; delz = x[i1][2] - x[i2][2]; rsq = delx*delx + dely*dely + delz*delz; r = sqrt(rsq); dr = r - r0[type]; drsq = dr*dr; lamdasq = lamda[type]*lamda[type]; denom = lamdasq - drsq; denomsq = denom*denom; // force & energy fbond = -epsilon[type]/r * 2.0*dr*lamdasq/denomsq; if (eflag) ebond = epsilon[type] * drsq / denom; // apply force to each of 2 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += delx*fbond; f[i1][1] += dely*fbond; f[i1][2] += delz*fbond; } if (newton_bond || i2 < nlocal) { f[i2][0] -= delx*fbond; f[i2][1] -= dely*fbond; f[i2][2] -= delz*fbond; } if (evflag) ev_tally(i1,i2,nlocal,newton_bond,ebond,fbond,delx,dely,delz); } } /* ---------------------------------------------------------------------- */ void BondNonlinear::allocate() { allocated = 1; int n = atom->nbondtypes; memory->create(epsilon,n+1,"bond:epsilon"); memory->create(r0,n+1,"bond:r0"); memory->create(lamda,n+1,"bond:lamda"); memory->create(setflag,n+1,"bond:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one type ------------------------------------------------------------------------- */ void BondNonlinear::coeff(int narg, char **arg) { if (narg != 4) error->all(FLERR,"Incorrect args for bond coefficients"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->nbondtypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->nbondtypes,ilo,ihi); double epsilon_one = force->numeric(FLERR,arg[1]); double r0_one = force->numeric(FLERR,arg[2]); double lamda_one = force->numeric(FLERR,arg[3]); int count = 0; for (int i = ilo; i <= ihi; i++) { epsilon[i] = epsilon_one; r0[i] = r0_one; lamda[i] = lamda_one; setflag[i] = 1; count++; } if (count == 0) error->all(FLERR,"Incorrect args for bond coefficients"); } /* ---------------------------------------------------------------------- */ double BondNonlinear::equilibrium_distance(int i) { return r0[i]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void BondNonlinear::write_restart(FILE *fp) { fwrite(&epsilon[1],sizeof(double),atom->nbondtypes,fp); fwrite(&r0[1],sizeof(double),atom->nbondtypes,fp); fwrite(&lamda[1],sizeof(double),atom->nbondtypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void BondNonlinear::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&epsilon[1],sizeof(double),atom->nbondtypes,fp); fread(&r0[1],sizeof(double),atom->nbondtypes,fp); fread(&lamda[1],sizeof(double),atom->nbondtypes,fp); } MPI_Bcast(&epsilon[1],atom->nbondtypes,MPI_DOUBLE,0,world); MPI_Bcast(&r0[1],atom->nbondtypes,MPI_DOUBLE,0,world); MPI_Bcast(&lamda[1],atom->nbondtypes,MPI_DOUBLE,0,world); for (int i = 1; i <= atom->nbondtypes; i++) setflag[i] = 1; } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void BondNonlinear::write_data(FILE *fp) { for (int i = 1; i <= atom->nbondtypes; i++) fprintf(fp,"%d %g %g %g\n",i,epsilon[i],r0[i],lamda[i]); } /* ---------------------------------------------------------------------- */ double BondNonlinear::single(int type, double rsq, int i, int j, double &fforce) { double r = sqrt(rsq); double dr = r - r0[type]; double drsq = dr*dr; double lamdasq = lamda[type]*lamda[type]; double denom = lamdasq - drsq; double denomsq = denom*denom; fforce = -epsilon[type]/r * 2.0*dr*lamdasq/denomsq; return epsilon[type] * drsq / denom; } diff --git a/src/MOLECULE/bond_quartic.cpp b/src/MOLECULE/bond_quartic.cpp index c92048b2c..2a3e395a7 100644 --- a/src/MOLECULE/bond_quartic.cpp +++ b/src/MOLECULE/bond_quartic.cpp @@ -1,348 +1,348 @@ /* ---------------------------------------------------------------------- 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: Chris Lorenz and Mark Stevens (SNL) ------------------------------------------------------------------------- */ #include #include #include "bond_quartic.h" #include "atom.h" #include "neighbor.h" #include "domain.h" #include "comm.h" #include "update.h" #include "force.h" #include "pair.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ BondQuartic::BondQuartic(LAMMPS *lmp) : Bond(lmp) { TWO_1_3 = pow(2.0,(1.0/3.0)); } /* ---------------------------------------------------------------------- */ BondQuartic::~BondQuartic() { if (allocated) { memory->destroy(setflag); memory->destroy(k); memory->destroy(b1); memory->destroy(b2); memory->destroy(rc); memory->destroy(u0); } } /* ---------------------------------------------------------------------- */ void BondQuartic::compute(int eflag, int vflag) { int i1,i2,n,m,type,itype,jtype; double delx,dely,delz,ebond,fbond,evdwl,fpair; double r,rsq,dr,r2,ra,rb,sr2,sr6; ebond = evdwl = sr6 = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; // insure pair->ev_tally() will use 1-4 virial contribution if (vflag_global == 2) force->pair->vflag_either = force->pair->vflag_global = 1; double **cutsq = force->pair->cutsq; double **x = atom->x; double **f = atom->f; int **bondlist = neighbor->bondlist; int nbondlist = neighbor->nbondlist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < nbondlist; n++) { // skip bond if already broken if (bondlist[n][2] <= 0) continue; i1 = bondlist[n][0]; i2 = bondlist[n][1]; type = bondlist[n][2]; delx = x[i1][0] - x[i2][0]; dely = x[i1][1] - x[i2][1]; delz = x[i1][2] - x[i2][2]; rsq = delx*delx + dely*dely + delz*delz; // if bond breaks, set type to 0 // both in temporary bondlist and permanent bond_type // if this proc owns both atoms, // negate bond_type twice if other atom stores it // if other proc owns 2nd atom, other proc will also break bond if (rsq > rc[type]*rc[type]) { bondlist[n][2] = 0; for (m = 0; m < atom->num_bond[i1]; m++) if (atom->bond_atom[i1][m] == atom->tag[i2]) atom->bond_type[i1][m] = 0; if (i2 < atom->nlocal) for (m = 0; m < atom->num_bond[i2]; m++) if (atom->bond_atom[i2][m] == atom->tag[i1]) atom->bond_type[i2][m] = 0; continue; } // quartic bond // 1st portion is from quartic term // 2nd portion is from LJ term cut at 2^(1/6) with eps = sigma = 1.0 r = sqrt(rsq); dr = r - rc[type]; r2 = dr*dr; ra = dr - b1[type]; rb = dr - b2[type]; fbond = -k[type]/r * (r2*(ra+rb) + 2.0*dr*ra*rb); if (rsq < TWO_1_3) { sr2 = 1.0/rsq; sr6 = sr2*sr2*sr2; fbond += 48.0*sr6*(sr6-0.5)/rsq; } if (eflag) { ebond = k[type]*r2*ra*rb + u0[type]; if (rsq < TWO_1_3) ebond += 4.0*sr6*(sr6-1.0) + 1.0; } // apply force to each of 2 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += delx*fbond; f[i1][1] += dely*fbond; f[i1][2] += delz*fbond; } if (newton_bond || i2 < nlocal) { f[i2][0] -= delx*fbond; f[i2][1] -= dely*fbond; f[i2][2] -= delz*fbond; } if (evflag) ev_tally(i1,i2,nlocal,newton_bond,ebond,fbond,delx,dely,delz); // subtract out pairwise contribution from 2 atoms via pair->single() // required since special_bond = 1,1,1 // tally energy/virial in pair, using newton_bond as newton flag itype = atom->type[i1]; jtype = atom->type[i2]; if (rsq < cutsq[itype][jtype]) { evdwl = -force->pair->single(i1,i2,itype,jtype,rsq,1.0,1.0,fpair); fpair = -fpair; if (newton_bond || i1 < nlocal) { f[i1][0] += delx*fpair; f[i1][1] += dely*fpair; f[i1][2] += delz*fpair; } if (newton_bond || i2 < nlocal) { f[i2][0] -= delx*fpair; f[i2][1] -= dely*fpair; f[i2][2] -= delz*fpair; } if (evflag) force->pair->ev_tally(i1,i2,nlocal,newton_bond, evdwl,0.0,fpair,delx,dely,delz); } } } /* ---------------------------------------------------------------------- */ void BondQuartic::allocate() { allocated = 1; int n = atom->nbondtypes; memory->create(k,n+1,"bond:k"); memory->create(b1,n+1,"bond:b1"); memory->create(b2,n+1,"bond:b2"); memory->create(rc,n+1,"bond:rc"); memory->create(u0,n+1,"bond:u0"); memory->create(setflag,n+1,"bond:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one or more types ------------------------------------------------------------------------- */ void BondQuartic::coeff(int narg, char **arg) { if (narg != 6) error->all(FLERR,"Incorrect args for bond coefficients"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->nbondtypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->nbondtypes,ilo,ihi); double k_one = force->numeric(FLERR,arg[1]); double b1_one = force->numeric(FLERR,arg[2]); double b2_one = force->numeric(FLERR,arg[3]); double rc_one = force->numeric(FLERR,arg[4]); double u0_one = force->numeric(FLERR,arg[5]); int count = 0; for (int i = ilo; i <= ihi; i++) { k[i] = k_one; b1[i] = b1_one; b2[i] = b2_one; rc[i] = rc_one; u0[i] = u0_one; setflag[i] = 1; count++; } if (count == 0) error->all(FLERR,"Incorrect args for bond coefficients"); } /* ---------------------------------------------------------------------- check if pair defined and special_bond settings are valid ------------------------------------------------------------------------- */ void BondQuartic::init_style() { if (force->pair == NULL || force->pair->single_enable == 0) error->all(FLERR,"Pair style does not support bond_style quartic"); if (force->angle || force->dihedral || force->improper) error->all(FLERR, "Bond style quartic cannot be used with 3,4-body interactions"); if (atom->molecular == 2) error->all(FLERR, "Bond style quartic cannot be used with atom style template"); // special bonds must be 1 1 1 if (force->special_lj[1] != 1.0 || force->special_lj[2] != 1.0 || force->special_lj[3] != 1.0) error->all(FLERR,"Bond style quartic requires special_bonds = 1,1,1"); } /* ---------------------------------------------------------------------- return an equilbrium bond length ------------------------------------------------------------------------- */ double BondQuartic::equilibrium_distance(int i) { return 0.97; } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void BondQuartic::write_restart(FILE *fp) { fwrite(&k[1],sizeof(double),atom->nbondtypes,fp); fwrite(&b1[1],sizeof(double),atom->nbondtypes,fp); fwrite(&b2[1],sizeof(double),atom->nbondtypes,fp); fwrite(&rc[1],sizeof(double),atom->nbondtypes,fp); fwrite(&u0[1],sizeof(double),atom->nbondtypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void BondQuartic::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&k[1],sizeof(double),atom->nbondtypes,fp); fread(&b1[1],sizeof(double),atom->nbondtypes,fp); fread(&b2[1],sizeof(double),atom->nbondtypes,fp); fread(&rc[1],sizeof(double),atom->nbondtypes,fp); fread(&u0[1],sizeof(double),atom->nbondtypes,fp); } MPI_Bcast(&k[1],atom->nbondtypes,MPI_DOUBLE,0,world); MPI_Bcast(&b1[1],atom->nbondtypes,MPI_DOUBLE,0,world); MPI_Bcast(&b2[1],atom->nbondtypes,MPI_DOUBLE,0,world); MPI_Bcast(&rc[1],atom->nbondtypes,MPI_DOUBLE,0,world); MPI_Bcast(&u0[1],atom->nbondtypes,MPI_DOUBLE,0,world); for (int i = 1; i <= atom->nbondtypes; i++) setflag[i] = 1; } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void BondQuartic::write_data(FILE *fp) { for (int i = 1; i <= atom->nbondtypes; i++) fprintf(fp,"%d %g %g %g %g %g\n",i,k[i],b1[i],b2[i],rc[i],u0[i]); } /* ---------------------------------------------------------------------- */ double BondQuartic::single(int type, double rsq, int i, int j, double &fforce) { double r,dr,r2,ra,rb,sr2,sr6; if (type <= 0) return 0.0; double eng = 0.0; // subtract out pairwise contribution from 2 atoms via pair->single() // required since special_bond = 1,1,1 int itype = atom->type[i]; int jtype = atom->type[j]; if (rsq < force->pair->cutsq[itype][jtype]) { double tmp; eng = -force->pair->single(i,j,itype,jtype,rsq,1.0,1.0,tmp); } // quartic bond // 1st portion is from quartic term // 2nd portion is from LJ term cut at 2^(1/6) with eps = sigma = 1.0 r = sqrt(rsq); dr = r - rc[type]; r2 = dr*dr; ra = dr - b1[type]; rb = dr - b2[type]; eng += k[type]*r2*ra*rb + u0[type]; fforce = -k[type]/r * (r2*(ra+rb) + 2.0*dr*ra*rb); if (rsq < TWO_1_3) { sr2 = 1.0/rsq; sr6 = sr2*sr2*sr2; eng += 4.0*sr6*(sr6-1.0) + 1.0; fforce += 48.0*sr6*(sr6-0.5)/rsq; } return eng; } diff --git a/src/MOLECULE/bond_table.cpp b/src/MOLECULE/bond_table.cpp index 858bc83a3..38cbe7e40 100644 --- a/src/MOLECULE/bond_table.cpp +++ b/src/MOLECULE/bond_table.cpp @@ -1,657 +1,657 @@ /* ---------------------------------------------------------------------- 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: Chuanfu Luo (luochuanfu@gmail.com) ------------------------------------------------------------------------- */ #include #include #include #include "bond_table.h" #include "atom.h" #include "neighbor.h" #include "domain.h" #include "comm.h" #include "force.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; enum{NONE,LINEAR,SPLINE}; #define MAXLINE 1024 #define BIGNUM 1.0e300 /* ---------------------------------------------------------------------- */ BondTable::BondTable(LAMMPS *lmp) : Bond(lmp) { writedata = 0; ntables = 0; tables = NULL; } /* ---------------------------------------------------------------------- */ BondTable::~BondTable() { for (int m = 0; m < ntables; m++) free_table(&tables[m]); memory->sfree(tables); if (allocated) { memory->destroy(setflag); memory->destroy(r0); memory->destroy(tabindex); } } /* ---------------------------------------------------------------------- */ void BondTable::compute(int eflag, int vflag) { int i1,i2,n,type; double delx,dely,delz,ebond,fbond; double rsq,r; double u,mdu; ebond = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; int **bondlist = neighbor->bondlist; int nbondlist = neighbor->nbondlist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < nbondlist; n++) { i1 = bondlist[n][0]; i2 = bondlist[n][1]; type = bondlist[n][2]; delx = x[i1][0] - x[i2][0]; dely = x[i1][1] - x[i2][1]; delz = x[i1][2] - x[i2][2]; rsq = delx*delx + dely*dely + delz*delz; r = sqrt(rsq); // force & energy uf_lookup(type,r,u,mdu); fbond = mdu/r; ebond = u; // apply force to each of 2 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += delx*fbond; f[i1][1] += dely*fbond; f[i1][2] += delz*fbond; } if (newton_bond || i2 < nlocal) { f[i2][0] -= delx*fbond; f[i2][1] -= dely*fbond; f[i2][2] -= delz*fbond; } if (evflag) ev_tally(i1,i2,nlocal,newton_bond,ebond,fbond,delx,dely,delz); } } /* ---------------------------------------------------------------------- */ void BondTable::allocate() { allocated = 1; int n = atom->nbondtypes; memory->create(tabindex,n+1,"bond:tabindex"); memory->create(r0,n+1,"bond:r0"); memory->create(setflag,n+1,"bond:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void BondTable::settings(int narg, char **arg) { if (narg != 2) error->all(FLERR,"Illegal bond_style command"); tabstyle = NONE; if (strcmp(arg[0],"linear") == 0) tabstyle = LINEAR; else if (strcmp(arg[0],"spline") == 0) tabstyle = SPLINE; else error->all(FLERR,"Unknown table style in bond style table"); tablength = force->inumeric(FLERR,arg[1]); if (tablength < 2) error->all(FLERR,"Illegal number of bond 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(tabindex); } allocated = 0; ntables = 0; tables = NULL; } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void BondTable::coeff(int narg, char **arg) { if (narg != 3) error->all(FLERR,"Illegal bond_coeff command"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->nbondtypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->nbondtypes,ilo,ihi); int me; MPI_Comm_rank(world,&me); tables = (Table *) memory->srealloc(tables,(ntables+1)*sizeof(Table),"bond:tables"); Table *tb = &tables[ntables]; null_table(tb); if (me == 0) read_table(tb,arg[1],arg[2]); bcast_table(tb); // error check on table parameters if (tb->ninput <= 1) error->one(FLERR,"Invalid bond table length"); tb->lo = tb->rfile[0]; tb->hi = tb->rfile[tb->ninput-1]; if (tb->lo >= tb->hi) error->all(FLERR,"Bond table values are not increasing"); // spline read-in and compute r,e,f vectors within table spline_table(tb); compute_table(tb); // store ptr to table in tabindex int count = 0; for (int i = ilo; i <= ihi; i++) { tabindex[i] = ntables; r0[i] = tb->r0; setflag[i] = 1; count++; } ntables++; if (count == 0) error->all(FLERR,"Illegal bond_coeff command"); } /* ---------------------------------------------------------------------- return an equilbrium bond length should not be used, since don't know minimum of tabulated function ------------------------------------------------------------------------- */ double BondTable::equilibrium_distance(int i) { return r0[i]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void BondTable::write_restart(FILE *fp) { fwrite(&tabstyle,sizeof(int),1,fp); fwrite(&tablength,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void BondTable::read_restart(FILE *fp) { if (comm->me == 0) { fread(&tabstyle,sizeof(int),1,fp); fread(&tablength,sizeof(int),1,fp); } MPI_Bcast(&tabstyle,1,MPI_INT,0,world); MPI_Bcast(&tablength,1,MPI_INT,0,world); allocate(); } /* ---------------------------------------------------------------------- */ double BondTable::single(int type, double rsq, int i, int j, double &fforce) { double r = sqrt(rsq); double u; double mdu; uf_lookup(type,r,u,mdu); fforce = mdu/r; return u; } /* ---------------------------------------------------------------------- */ void BondTable::null_table(Table *tb) { tb->rfile = tb->efile = tb->ffile = NULL; tb->e2file = tb->f2file = NULL; tb->r = tb->e = tb->de = NULL; tb->f = tb->df = tb->e2 = tb->f2 = NULL; } /* ---------------------------------------------------------------------- */ void BondTable::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->r); memory->destroy(tb->e); memory->destroy(tb->de); memory->destroy(tb->f); memory->destroy(tb->df); memory->destroy(tb->e2); memory->destroy(tb->f2); } /* ---------------------------------------------------------------------- read table file, only called by proc 0 ------------------------------------------------------------------------- */ void BondTable::read_table(Table *tb, char *file, char *keyword) { char line[MAXLINE]; double emin = BIGNUM; // open file FILE *fp = force->open_potential(file); 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 char *word = strtok(line," \t\n\r"); if (strcmp(word,keyword) == 0) 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,"bond:rfile"); memory->create(tb->efile,tb->ninput,"bond:efile"); memory->create(tb->ffile,tb->ninput,"bond:ffile"); // read r,e,f table values from file int itmp; int cerror = 0; int r0idx = -1; fgets(line,MAXLINE,fp); for (int i = 0; i < tb->ninput; i++) { if (NULL == fgets(line,MAXLINE,fp)) error->one(FLERR,"Premature end of file in bond table"); if (4 != sscanf(line,"%d %lg %lg %lg", &itmp,&tb->rfile[i],&tb->efile[i],&tb->ffile[i])) ++cerror; if (tb->efile[i] < emin) { emin = tb->efile[i]; r0idx = i; } } fclose(fp); // infer r0 from minimum of potential, if not given explicitly if ((tb->r0 == 0.0) && (r0idx >= 0)) tb->r0 = tb->rfile[r0idx]; // warn if force != dE/dr at any point that is not an inflection point // check via secant approximation to dE/dr // skip two end points since do not have surrounding secants // inflection point is where curvature changes sign double r,e,f,rprev,rnext,eprev,enext,fleft,fright; int ferror = 0; for (int i = 1; i < tb->ninput-1; i++) { r = tb->rfile[i]; rprev = tb->rfile[i-1]; rnext = tb->rfile[i+1]; e = tb->efile[i]; eprev = tb->efile[i-1]; enext = tb->efile[i+1]; f = tb->ffile[i]; fleft = - (e-eprev) / (r-rprev); fright = - (enext-e) / (rnext-r); if (f < fleft && f < fright) ferror++; if (f > fleft && f > fright) ferror++; //printf("Values %d: %g %g %g\n",i,r,e,f); //printf(" secant %d %d %g: %g %g %g\n",i,ferror,r,fleft,fright,f); } if (ferror) { char str[128]; sprintf(str,"%d of %d force values in table are inconsistent with -dE/dr.\n" " Should only be flagged at inflection points",ferror,tb->ninput); error->warning(FLERR,str); } // warn if data was read incompletely, e.g. columns were missing if (cerror) { char str[128]; sprintf(str,"%d of %d lines in table were incomplete or could not be" " parsed completely",cerror,tb->ninput); error->warning(FLERR,str); } } /* ---------------------------------------------------------------------- build spline representation of e,f over entire range of read-in table this function sets these values in e2file,f2file ------------------------------------------------------------------------- */ void BondTable::spline_table(Table *tb) { memory->create(tb->e2file,tb->ninput,"bond:e2file"); memory->create(tb->f2file,tb->ninput,"bond: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); } /* ---------------------------------------------------------------------- compute r,e,f vectors from splined values ------------------------------------------------------------------------- */ void BondTable::compute_table(Table *tb) { // delta = table spacing for N-1 bins int tlm1 = tablength-1; tb->delta = (tb->hi - tb->lo)/ tlm1; tb->invdelta = 1.0/tb->delta; tb->deltasq6 = tb->delta*tb->delta / 6.0; // N-1 evenly spaced bins in r from min to max // r,e,f = value at lower edge of bin // de,df values = delta values of e,f // r,e,f are N in length so de,df arrays can compute difference memory->create(tb->r,tablength,"bond:r"); memory->create(tb->e,tablength,"bond:e"); memory->create(tb->de,tlm1,"bond:de"); memory->create(tb->f,tablength,"bond:f"); memory->create(tb->df,tlm1,"bond:df"); memory->create(tb->e2,tablength,"bond:e2"); memory->create(tb->f2,tablength,"bond:f2"); double a; for (int i = 0; i < tablength; i++) { a = tb->lo + i*tb->delta; tb->r[i] = a; tb->e[i] = splint(tb->rfile,tb->efile,tb->e2file,tb->ninput,a); tb->f[i] = splint(tb->rfile,tb->ffile,tb->f2file,tb->ninput,a); } 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]; } double ep0 = - tb->f[0]; double epn = - tb->f[tlm1]; spline(tb->r,tb->e,tablength,ep0,epn,tb->e2); spline(tb->r,tb->f,tablength,tb->fplo,tb->fphi,tb->f2); } /* ---------------------------------------------------------------------- extract attributes from parameter line in table section format of line: N value FP fplo fphi EQ r0 N is required, other params are optional ------------------------------------------------------------------------- */ void BondTable::param_extract(Table *tb, char *line) { tb->ninput = 0; tb->fpflag = 0; tb->r0 = 0.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,"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 if (strcmp(word,"EQ") == 0) { word = strtok(NULL," \t\n\r\f"); tb->r0 = atof(word); } else { error->one(FLERR,"Invalid keyword in bond table parameters"); } word = strtok(NULL," \t\n\r\f"); } if (tb->ninput == 0) error->one(FLERR,"Bond table parameters did not set N"); } /* ---------------------------------------------------------------------- broadcast read-in table info from proc 0 to other procs this function communicates these values in Table: ninput,rfile,efile,ffile,fpflag,fplo,fphi,r0 ------------------------------------------------------------------------- */ void BondTable::bcast_table(Table *tb) { MPI_Bcast(&tb->ninput,1,MPI_INT,0,world); MPI_Bcast(&tb->r0,1,MPI_INT,0,world); int me; MPI_Comm_rank(world,&me); if (me > 0) { memory->create(tb->rfile,tb->ninput,"angle:rfile"); memory->create(tb->efile,tb->ninput,"angle:efile"); memory->create(tb->ffile,tb->ninput,"angle: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->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); } MPI_Bcast(&tb->r0,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- spline and splint routines modified from Numerical Recipes ------------------------------------------------------------------------- */ void BondTable::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 BondTable::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; } /* ---------------------------------------------------------------------- calculate potential u and force f at distance x insure x is between bond min/max, exit with error if not ------------------------------------------------------------------------- */ void BondTable::uf_lookup(int type, double x, double &u, double &f) { int itable; double fraction,a,b; char estr[128]; Table *tb = &tables[tabindex[type]]; if (x < tb->lo) { sprintf(estr,"Bond length < table inner cutoff: " "type %d length %g",type,x); error->one(FLERR,estr); } if (x > tb->hi) { sprintf(estr,"Bond length > table outer cutoff: " "type %d length %g",type,x); error->one(FLERR,estr); } if (tabstyle == LINEAR) { itable = static_cast ((x - tb->lo) * tb->invdelta); fraction = (x - tb->r[itable]) * tb->invdelta; u = tb->e[itable] + fraction*tb->de[itable]; f = tb->f[itable] + fraction*tb->df[itable]; } else if (tabstyle == SPLINE) { itable = static_cast ((x - tb->lo) * tb->invdelta); fraction = (x - tb->r[itable]) * tb->invdelta; b = (x - tb->r[itable]) * tb->invdelta; a = 1.0 - b; u = 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; f = 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; } } /* ---------------------------------------------------------------------- calculate potential u at distance x insure x is between bond min/max ------------------------------------------------------------------------- */ void BondTable::u_lookup(int type, double x, double &u) { int itable; double fraction,a,b; Table *tb = &tables[tabindex[type]]; x = MAX(x,tb->lo); x = MIN(x,tb->hi); if (tabstyle == LINEAR) { itable = static_cast ((x - tb->lo) * tb->invdelta); fraction = (x - tb->r[itable]) * tb->invdelta; u = tb->e[itable] + fraction*tb->de[itable]; } else if (tabstyle == SPLINE) { itable = static_cast ((x - tb->lo) * tb->invdelta); fraction = (x - tb->r[itable]) * tb->invdelta; b = (x - tb->r[itable]) * tb->invdelta; a = 1.0 - b; u = 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; } } diff --git a/src/MOLECULE/dihedral_charmm.cpp b/src/MOLECULE/dihedral_charmm.cpp index 8b6909f1a..b9d1c440d 100644 --- a/src/MOLECULE/dihedral_charmm.cpp +++ b/src/MOLECULE/dihedral_charmm.cpp @@ -1,439 +1,439 @@ /* ---------------------------------------------------------------------- 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 #include #include #include "dihedral_charmm.h" #include "atom.h" #include "comm.h" #include "neighbor.h" #include "domain.h" #include "force.h" #include "pair.h" #include "update.h" #include "math_const.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace MathConst; #define TOLERANCE 0.05 /* ---------------------------------------------------------------------- */ DihedralCharmm::DihedralCharmm(LAMMPS *lmp) : Dihedral(lmp) { weightflag = 0; writedata = 1; } /* ---------------------------------------------------------------------- */ DihedralCharmm::~DihedralCharmm() { if (allocated && !copymode) { memory->destroy(setflag); memory->destroy(k); memory->destroy(multiplicity); memory->destroy(shift); memory->destroy(cos_shift); memory->destroy(sin_shift); memory->destroy(weight); } } /* ---------------------------------------------------------------------- */ void DihedralCharmm::compute(int eflag, int vflag) { int i1,i2,i3,i4,i,m,n,type; double vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z,vb2xm,vb2ym,vb2zm; double edihedral,f1[3],f2[3],f3[3],f4[3]; double ax,ay,az,bx,by,bz,rasq,rbsq,rgsq,rg,rginv,ra2inv,rb2inv,rabinv; double df,df1,ddf1,fg,hg,fga,hgb,gaa,gbb; double dtfx,dtfy,dtfz,dtgx,dtgy,dtgz,dthx,dthy,dthz; double c,s,p,sx2,sy2,sz2; int itype,jtype; double delx,dely,delz,rsq,r2inv,r6inv; double forcecoul,forcelj,fpair,ecoul,evdwl; edihedral = evdwl = ecoul = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; // insure pair->ev_tally() will use 1-4 virial contribution if (weightflag && vflag_global == 2) force->pair->vflag_either = force->pair->vflag_global = 1; double **x = atom->x; double **f = atom->f; double *q = atom->q; int *atomtype = atom->type; int **dihedrallist = neighbor->dihedrallist; int ndihedrallist = neighbor->ndihedrallist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; double qqrd2e = force->qqrd2e; for (n = 0; n < ndihedrallist; n++) { i1 = dihedrallist[n][0]; i2 = dihedrallist[n][1]; i3 = dihedrallist[n][2]; i4 = dihedrallist[n][3]; type = dihedrallist[n][4]; // 1st bond vb1x = x[i1][0] - x[i2][0]; vb1y = x[i1][1] - x[i2][1]; vb1z = x[i1][2] - x[i2][2]; // 2nd bond vb2x = x[i3][0] - x[i2][0]; vb2y = x[i3][1] - x[i2][1]; vb2z = x[i3][2] - x[i2][2]; vb2xm = -vb2x; vb2ym = -vb2y; vb2zm = -vb2z; // 3rd bond vb3x = x[i4][0] - x[i3][0]; vb3y = x[i4][1] - x[i3][1]; vb3z = x[i4][2] - x[i3][2]; ax = vb1y*vb2zm - vb1z*vb2ym; ay = vb1z*vb2xm - vb1x*vb2zm; az = vb1x*vb2ym - vb1y*vb2xm; bx = vb3y*vb2zm - vb3z*vb2ym; by = vb3z*vb2xm - vb3x*vb2zm; bz = vb3x*vb2ym - vb3y*vb2xm; rasq = ax*ax + ay*ay + az*az; rbsq = bx*bx + by*by + bz*bz; rgsq = vb2xm*vb2xm + vb2ym*vb2ym + vb2zm*vb2zm; rg = sqrt(rgsq); rginv = ra2inv = rb2inv = 0.0; if (rg > 0) rginv = 1.0/rg; if (rasq > 0) ra2inv = 1.0/rasq; if (rbsq > 0) rb2inv = 1.0/rbsq; rabinv = sqrt(ra2inv*rb2inv); c = (ax*bx + ay*by + az*bz)*rabinv; s = rg*rabinv*(ax*vb3x + ay*vb3y + az*vb3z); // error check if (c > 1.0 + TOLERANCE || c < (-1.0 - TOLERANCE)) { int me; MPI_Comm_rank(world,&me); if (screen) { char str[128]; sprintf(str,"Dihedral problem: %d " BIGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT, me,update->ntimestep, atom->tag[i1],atom->tag[i2],atom->tag[i3],atom->tag[i4]); error->warning(FLERR,str,0); fprintf(screen," 1st atom: %d %g %g %g\n", me,x[i1][0],x[i1][1],x[i1][2]); fprintf(screen," 2nd atom: %d %g %g %g\n", me,x[i2][0],x[i2][1],x[i2][2]); fprintf(screen," 3rd atom: %d %g %g %g\n", me,x[i3][0],x[i3][1],x[i3][2]); fprintf(screen," 4th atom: %d %g %g %g\n", me,x[i4][0],x[i4][1],x[i4][2]); } } if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; m = multiplicity[type]; p = 1.0; ddf1 = df1 = 0.0; for (i = 0; i < m; i++) { ddf1 = p*c - df1*s; df1 = p*s + df1*c; p = ddf1; } p = p*cos_shift[type] + df1*sin_shift[type]; df1 = df1*cos_shift[type] - ddf1*sin_shift[type]; df1 *= -m; p += 1.0; if (m == 0) { p = 1.0 + cos_shift[type]; df1 = 0.0; } if (eflag) edihedral = k[type] * p; fg = vb1x*vb2xm + vb1y*vb2ym + vb1z*vb2zm; hg = vb3x*vb2xm + vb3y*vb2ym + vb3z*vb2zm; fga = fg*ra2inv*rginv; hgb = hg*rb2inv*rginv; gaa = -ra2inv*rg; gbb = rb2inv*rg; dtfx = gaa*ax; dtfy = gaa*ay; dtfz = gaa*az; dtgx = fga*ax - hgb*bx; dtgy = fga*ay - hgb*by; dtgz = fga*az - hgb*bz; dthx = gbb*bx; dthy = gbb*by; dthz = gbb*bz; df = -k[type] * df1; sx2 = df*dtgx; sy2 = df*dtgy; sz2 = df*dtgz; f1[0] = df*dtfx; f1[1] = df*dtfy; f1[2] = df*dtfz; f2[0] = sx2 - f1[0]; f2[1] = sy2 - f1[1]; f2[2] = sz2 - f1[2]; f4[0] = df*dthx; f4[1] = df*dthy; f4[2] = df*dthz; f3[0] = -sx2 - f4[0]; f3[1] = -sy2 - f4[1]; f3[2] = -sz2 - f4[2]; // apply force to each of 4 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += f1[0]; f[i1][1] += f1[1]; f[i1][2] += f1[2]; } if (newton_bond || i2 < nlocal) { f[i2][0] += f2[0]; f[i2][1] += f2[1]; f[i2][2] += f2[2]; } if (newton_bond || i3 < nlocal) { f[i3][0] += f3[0]; f[i3][1] += f3[1]; f[i3][2] += f3[2]; } if (newton_bond || i4 < nlocal) { f[i4][0] += f4[0]; f[i4][1] += f4[1]; f[i4][2] += f4[2]; } if (evflag) ev_tally(i1,i2,i3,i4,nlocal,newton_bond,edihedral,f1,f3,f4, vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z); // 1-4 LJ and Coulomb interactions // tally energy/virial in pair, using newton_bond as newton flag if (weight[type] > 0.0) { itype = atomtype[i1]; jtype = atomtype[i4]; delx = x[i1][0] - x[i4][0]; dely = x[i1][1] - x[i4][1]; delz = x[i1][2] - x[i4][2]; rsq = delx*delx + dely*dely + delz*delz; r2inv = 1.0/rsq; r6inv = r2inv*r2inv*r2inv; if (implicit) forcecoul = qqrd2e * q[i1]*q[i4]*r2inv; else forcecoul = qqrd2e * q[i1]*q[i4]*sqrt(r2inv); forcelj = r6inv * (lj14_1[itype][jtype]*r6inv - lj14_2[itype][jtype]); fpair = weight[type] * (forcelj+forcecoul)*r2inv; if (eflag) { ecoul = weight[type] * forcecoul; evdwl = r6inv * (lj14_3[itype][jtype]*r6inv - lj14_4[itype][jtype]); evdwl *= weight[type]; } if (newton_bond || i1 < nlocal) { f[i1][0] += delx*fpair; f[i1][1] += dely*fpair; f[i1][2] += delz*fpair; } if (newton_bond || i4 < nlocal) { f[i4][0] -= delx*fpair; f[i4][1] -= dely*fpair; f[i4][2] -= delz*fpair; } if (evflag) force->pair->ev_tally(i1,i4,nlocal,newton_bond, evdwl,ecoul,fpair,delx,dely,delz); } } } /* ---------------------------------------------------------------------- */ void DihedralCharmm::allocate() { allocated = 1; int n = atom->ndihedraltypes; memory->create(k,n+1,"dihedral:k"); memory->create(multiplicity,n+1,"dihedral:k"); memory->create(shift,n+1,"dihedral:shift"); memory->create(cos_shift,n+1,"dihedral:cos_shift"); memory->create(sin_shift,n+1,"dihedral:sin_shift"); memory->create(weight,n+1,"dihedral:weight"); memory->create(setflag,n+1,"dihedral:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one type ------------------------------------------------------------------------- */ void DihedralCharmm::coeff(int narg, char **arg) { if (narg != 5) error->all(FLERR,"Incorrect args for dihedral coefficients"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->ndihedraltypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->ndihedraltypes,ilo,ihi); // require integer values of shift for backwards compatibility // arbitrary phase angle shift could be allowed, but would break // backwards compatibility and is probably not needed double k_one = force->numeric(FLERR,arg[1]); int multiplicity_one = force->inumeric(FLERR,arg[2]); int shift_one = force->inumeric(FLERR,arg[3]); double weight_one = force->numeric(FLERR,arg[4]); if (multiplicity_one < 0) error->all(FLERR,"Incorrect multiplicity arg for dihedral coefficients"); if (weight_one < 0.0 || weight_one > 1.0) error->all(FLERR,"Incorrect weight arg for dihedral coefficients"); if (weight_one > 0.0) weightflag=1; int count = 0; for (int i = ilo; i <= ihi; i++) { k[i] = k_one; shift[i] = shift_one; cos_shift[i] = cos(MY_PI*shift_one/180.0); sin_shift[i] = sin(MY_PI*shift_one/180.0); multiplicity[i] = multiplicity_one; weight[i] = weight_one; setflag[i] = 1; count++; } if (count == 0) error->all(FLERR,"Incorrect args for dihedral coefficients"); } /* ---------------------------------------------------------------------- error check and initialize all values needed for force computation ------------------------------------------------------------------------- */ void DihedralCharmm::init_style() { // insure use of CHARMM pair_style if any weight factors are non-zero // set local ptrs to LJ 14 arrays setup by Pair if (weightflag) { int itmp; if (force->pair == NULL) error->all(FLERR,"Dihedral charmm is incompatible with Pair style"); lj14_1 = (double **) force->pair->extract("lj14_1",itmp); lj14_2 = (double **) force->pair->extract("lj14_2",itmp); lj14_3 = (double **) force->pair->extract("lj14_3",itmp); lj14_4 = (double **) force->pair->extract("lj14_4",itmp); int *ptr = (int *) force->pair->extract("implicit",itmp); if (!lj14_1 || !lj14_2 || !lj14_3 || !lj14_4 || !ptr) error->all(FLERR,"Dihedral charmm is incompatible with Pair style"); implicit = *ptr; } } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void DihedralCharmm::write_restart(FILE *fp) { fwrite(&k[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&multiplicity[1],sizeof(int),atom->ndihedraltypes,fp); fwrite(&shift[1],sizeof(int),atom->ndihedraltypes,fp); fwrite(&weight[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&weightflag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void DihedralCharmm::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&k[1],sizeof(double),atom->ndihedraltypes,fp); fread(&multiplicity[1],sizeof(int),atom->ndihedraltypes,fp); fread(&shift[1],sizeof(int),atom->ndihedraltypes,fp); fread(&weight[1],sizeof(double),atom->ndihedraltypes,fp); fread(&weightflag,sizeof(int),1,fp); } MPI_Bcast(&k[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&multiplicity[1],atom->ndihedraltypes,MPI_INT,0,world); MPI_Bcast(&shift[1],atom->ndihedraltypes,MPI_INT,0,world); MPI_Bcast(&weight[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&weightflag,1,MPI_INT,0,world); for (int i = 1; i <= atom->ndihedraltypes; i++) { setflag[i] = 1; cos_shift[i] = cos(MY_PI*shift[i]/180.0); sin_shift[i] = sin(MY_PI*shift[i]/180.0); } } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void DihedralCharmm::write_data(FILE *fp) { for (int i = 1; i <= atom->ndihedraltypes; i++) fprintf(fp,"%d %g %d %d %g\n",i,k[i],multiplicity[i],shift[i],weight[i]); } diff --git a/src/MOLECULE/dihedral_harmonic.cpp b/src/MOLECULE/dihedral_harmonic.cpp index f9ea31ac7..82c5fe315 100644 --- a/src/MOLECULE/dihedral_harmonic.cpp +++ b/src/MOLECULE/dihedral_harmonic.cpp @@ -1,362 +1,362 @@ /* ---------------------------------------------------------------------- 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 #include #include #include "dihedral_harmonic.h" #include "atom.h" #include "comm.h" #include "neighbor.h" #include "domain.h" #include "force.h" #include "update.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define TOLERANCE 0.05 #define SMALL 0.001 /* ---------------------------------------------------------------------- */ DihedralHarmonic::DihedralHarmonic(LAMMPS *lmp) : Dihedral(lmp) { writedata = 1; } /* ---------------------------------------------------------------------- */ DihedralHarmonic::~DihedralHarmonic() { if (allocated) { memory->destroy(setflag); memory->destroy(k); memory->destroy(sign); memory->destroy(multiplicity); memory->destroy(cos_shift); memory->destroy(sin_shift); } } /* ---------------------------------------------------------------------- */ void DihedralHarmonic::compute(int eflag, int vflag) { int i1,i2,i3,i4,i,m,n,type; double vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z,vb2xm,vb2ym,vb2zm; double edihedral,f1[3],f2[3],f3[3],f4[3]; double ax,ay,az,bx,by,bz,rasq,rbsq,rgsq,rg,rginv,ra2inv,rb2inv,rabinv; double df,df1,ddf1,fg,hg,fga,hgb,gaa,gbb; double dtfx,dtfy,dtfz,dtgx,dtgy,dtgz,dthx,dthy,dthz; double c,s,p,sx2,sy2,sz2; edihedral = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; int **dihedrallist = neighbor->dihedrallist; int ndihedrallist = neighbor->ndihedrallist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < ndihedrallist; n++) { i1 = dihedrallist[n][0]; i2 = dihedrallist[n][1]; i3 = dihedrallist[n][2]; i4 = dihedrallist[n][3]; type = dihedrallist[n][4]; // 1st bond vb1x = x[i1][0] - x[i2][0]; vb1y = x[i1][1] - x[i2][1]; vb1z = x[i1][2] - x[i2][2]; // 2nd bond vb2x = x[i3][0] - x[i2][0]; vb2y = x[i3][1] - x[i2][1]; vb2z = x[i3][2] - x[i2][2]; vb2xm = -vb2x; vb2ym = -vb2y; vb2zm = -vb2z; // 3rd bond vb3x = x[i4][0] - x[i3][0]; vb3y = x[i4][1] - x[i3][1]; vb3z = x[i4][2] - x[i3][2]; // c,s calculation ax = vb1y*vb2zm - vb1z*vb2ym; ay = vb1z*vb2xm - vb1x*vb2zm; az = vb1x*vb2ym - vb1y*vb2xm; bx = vb3y*vb2zm - vb3z*vb2ym; by = vb3z*vb2xm - vb3x*vb2zm; bz = vb3x*vb2ym - vb3y*vb2xm; rasq = ax*ax + ay*ay + az*az; rbsq = bx*bx + by*by + bz*bz; rgsq = vb2xm*vb2xm + vb2ym*vb2ym + vb2zm*vb2zm; rg = sqrt(rgsq); rginv = ra2inv = rb2inv = 0.0; if (rg > 0) rginv = 1.0/rg; if (rasq > 0) ra2inv = 1.0/rasq; if (rbsq > 0) rb2inv = 1.0/rbsq; rabinv = sqrt(ra2inv*rb2inv); c = (ax*bx + ay*by + az*bz)*rabinv; s = rg*rabinv*(ax*vb3x + ay*vb3y + az*vb3z); // error check if (c > 1.0 + TOLERANCE || c < (-1.0 - TOLERANCE)) { int me; MPI_Comm_rank(world,&me); if (screen) { char str[128]; sprintf(str,"Dihedral problem: %d " BIGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT, me,update->ntimestep, atom->tag[i1],atom->tag[i2],atom->tag[i3],atom->tag[i4]); error->warning(FLERR,str,0); fprintf(screen," 1st atom: %d %g %g %g\n", me,x[i1][0],x[i1][1],x[i1][2]); fprintf(screen," 2nd atom: %d %g %g %g\n", me,x[i2][0],x[i2][1],x[i2][2]); fprintf(screen," 3rd atom: %d %g %g %g\n", me,x[i3][0],x[i3][1],x[i3][2]); fprintf(screen," 4th atom: %d %g %g %g\n", me,x[i4][0],x[i4][1],x[i4][2]); } } if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; m = multiplicity[type]; p = 1.0; ddf1 = df1 = 0.0; for (i = 0; i < m; i++) { ddf1 = p*c - df1*s; df1 = p*s + df1*c; p = ddf1; } p = p*cos_shift[type] + df1*sin_shift[type]; df1 = df1*cos_shift[type] - ddf1*sin_shift[type]; df1 *= -m; p += 1.0; if (m == 0) { p = 1.0 + cos_shift[type]; df1 = 0.0; } if (eflag) edihedral = k[type] * p; fg = vb1x*vb2xm + vb1y*vb2ym + vb1z*vb2zm; hg = vb3x*vb2xm + vb3y*vb2ym + vb3z*vb2zm; fga = fg*ra2inv*rginv; hgb = hg*rb2inv*rginv; gaa = -ra2inv*rg; gbb = rb2inv*rg; dtfx = gaa*ax; dtfy = gaa*ay; dtfz = gaa*az; dtgx = fga*ax - hgb*bx; dtgy = fga*ay - hgb*by; dtgz = fga*az - hgb*bz; dthx = gbb*bx; dthy = gbb*by; dthz = gbb*bz; df = -k[type] * df1; sx2 = df*dtgx; sy2 = df*dtgy; sz2 = df*dtgz; f1[0] = df*dtfx; f1[1] = df*dtfy; f1[2] = df*dtfz; f2[0] = sx2 - f1[0]; f2[1] = sy2 - f1[1]; f2[2] = sz2 - f1[2]; f4[0] = df*dthx; f4[1] = df*dthy; f4[2] = df*dthz; f3[0] = -sx2 - f4[0]; f3[1] = -sy2 - f4[1]; f3[2] = -sz2 - f4[2]; // apply force to each of 4 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += f1[0]; f[i1][1] += f1[1]; f[i1][2] += f1[2]; } if (newton_bond || i2 < nlocal) { f[i2][0] += f2[0]; f[i2][1] += f2[1]; f[i2][2] += f2[2]; } if (newton_bond || i3 < nlocal) { f[i3][0] += f3[0]; f[i3][1] += f3[1]; f[i3][2] += f3[2]; } if (newton_bond || i4 < nlocal) { f[i4][0] += f4[0]; f[i4][1] += f4[1]; f[i4][2] += f4[2]; } if (evflag) ev_tally(i1,i2,i3,i4,nlocal,newton_bond,edihedral,f1,f3,f4, vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z); } } /* ---------------------------------------------------------------------- */ void DihedralHarmonic::allocate() { allocated = 1; int n = atom->ndihedraltypes; memory->create(k,n+1,"dihedral:k"); memory->create(sign,n+1,"dihedral:sign"); memory->create(multiplicity,n+1,"dihedral:multiplicity"); memory->create(cos_shift,n+1,"dihedral:cos_shift"); memory->create(sin_shift,n+1,"dihedral:sin_shift"); memory->create(setflag,n+1,"dihedral:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one type ------------------------------------------------------------------------- */ void DihedralHarmonic::coeff(int narg, char **arg) { if (narg != 4) error->all(FLERR,"Incorrect args for dihedral coefficients"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->ndihedraltypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->ndihedraltypes,ilo,ihi); double k_one = force->numeric(FLERR,arg[1]); int sign_one = force->inumeric(FLERR,arg[2]); int multiplicity_one = force->inumeric(FLERR,arg[3]); // require sign = +/- 1 for backwards compatibility // arbitrary phase angle shift could be allowed, but would break // backwards compatibility and is probably not needed if (sign_one != -1 && sign_one != 1) error->all(FLERR,"Incorrect sign arg for dihedral coefficients"); if (multiplicity_one < 0) error->all(FLERR,"Incorrect multiplicity arg for dihedral coefficients"); int count = 0; for (int i = ilo; i <= ihi; i++) { k[i] = k_one; sign[i] = sign_one; if (sign[i] == 1) { cos_shift[i] = 1; sin_shift[i] = 0; } else { cos_shift[i] = -1; sin_shift[i] = 0; } multiplicity[i] = multiplicity_one; setflag[i] = 1; count++; } if (count == 0) error->all(FLERR,"Incorrect args for dihedral coefficients"); } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void DihedralHarmonic::write_restart(FILE *fp) { fwrite(&k[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&sign[1],sizeof(int),atom->ndihedraltypes,fp); fwrite(&multiplicity[1],sizeof(int),atom->ndihedraltypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void DihedralHarmonic::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&k[1],sizeof(double),atom->ndihedraltypes,fp); fread(&sign[1],sizeof(int),atom->ndihedraltypes,fp); fread(&multiplicity[1],sizeof(int),atom->ndihedraltypes,fp); } MPI_Bcast(&k[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&sign[1],atom->ndihedraltypes,MPI_INT,0,world); MPI_Bcast(&multiplicity[1],atom->ndihedraltypes,MPI_INT,0,world); for (int i = 1; i <= atom->ndihedraltypes; i++) { setflag[i] = 1; if (sign[i] == 1) { cos_shift[i] = 1; sin_shift[i] = 0; } else { cos_shift[i] = -1; sin_shift[i] = 0; } } } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void DihedralHarmonic::write_data(FILE *fp) { for (int i = 1; i <= atom->ndihedraltypes; i++) fprintf(fp,"%d %g %d %d\n",i,k[i],sign[i],multiplicity[i]); } diff --git a/src/MOLECULE/dihedral_helix.cpp b/src/MOLECULE/dihedral_helix.cpp index b0565e29f..43794bd6a 100644 --- a/src/MOLECULE/dihedral_helix.cpp +++ b/src/MOLECULE/dihedral_helix.cpp @@ -1,334 +1,334 @@ /* ---------------------------------------------------------------------- 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: Naveen Michaud-Agrawal (Johns Hopkins U) and Mark Stevens (Sandia) ------------------------------------------------------------------------- */ #include #include #include #include "dihedral_helix.h" #include "atom.h" #include "neighbor.h" #include "domain.h" #include "comm.h" #include "force.h" #include "update.h" #include "math_const.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace MathConst; #define TOLERANCE 0.05 #define SMALL 0.001 #define SMALLER 0.00001 /* ---------------------------------------------------------------------- */ DihedralHelix::DihedralHelix(LAMMPS *lmp) : Dihedral(lmp) {} /* ---------------------------------------------------------------------- */ DihedralHelix::~DihedralHelix() { if (allocated) { memory->destroy(setflag); memory->destroy(aphi); memory->destroy(bphi); memory->destroy(cphi); } } /* ---------------------------------------------------------------------- */ void DihedralHelix::compute(int eflag, int vflag) { int i1,i2,i3,i4,n,type; double vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z,vb2xm,vb2ym,vb2zm; double edihedral,f1[3],f2[3],f3[3],f4[3]; double sb1,sb2,sb3,rb1,rb3,c0,b1mag2,b1mag,b2mag2; double b2mag,b3mag2,b3mag,ctmp,r12c1,c1mag,r12c2; double c2mag,sc1,sc2,s1,s12,c,p,pd,a,a11,a22; double a33,a12,a13,a23,sx2,sy2,sz2; double s2,cx,cy,cz,cmag,dx,phi,si,siinv,sin2; edihedral = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; int **dihedrallist = neighbor->dihedrallist; int ndihedrallist = neighbor->ndihedrallist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < ndihedrallist; n++) { i1 = dihedrallist[n][0]; i2 = dihedrallist[n][1]; i3 = dihedrallist[n][2]; i4 = dihedrallist[n][3]; type = dihedrallist[n][4]; // 1st bond vb1x = x[i1][0] - x[i2][0]; vb1y = x[i1][1] - x[i2][1]; vb1z = x[i1][2] - x[i2][2]; // 2nd bond vb2x = x[i3][0] - x[i2][0]; vb2y = x[i3][1] - x[i2][1]; vb2z = x[i3][2] - x[i2][2]; vb2xm = -vb2x; vb2ym = -vb2y; vb2zm = -vb2z; // 3rd bond vb3x = x[i4][0] - x[i3][0]; vb3y = x[i4][1] - x[i3][1]; vb3z = x[i4][2] - x[i3][2]; // c0 calculation sb1 = 1.0 / (vb1x*vb1x + vb1y*vb1y + vb1z*vb1z); sb2 = 1.0 / (vb2x*vb2x + vb2y*vb2y + vb2z*vb2z); sb3 = 1.0 / (vb3x*vb3x + vb3y*vb3y + vb3z*vb3z); rb1 = sqrt(sb1); rb3 = sqrt(sb3); c0 = (vb1x*vb3x + vb1y*vb3y + vb1z*vb3z) * rb1*rb3; // 1st and 2nd angle b1mag2 = vb1x*vb1x + vb1y*vb1y + vb1z*vb1z; b1mag = sqrt(b1mag2); b2mag2 = vb2x*vb2x + vb2y*vb2y + vb2z*vb2z; b2mag = sqrt(b2mag2); b3mag2 = vb3x*vb3x + vb3y*vb3y + vb3z*vb3z; b3mag = sqrt(b3mag2); ctmp = vb1x*vb2x + vb1y*vb2y + vb1z*vb2z; r12c1 = 1.0 / (b1mag*b2mag); c1mag = ctmp * r12c1; ctmp = vb2xm*vb3x + vb2ym*vb3y + vb2zm*vb3z; r12c2 = 1.0 / (b2mag*b3mag); c2mag = ctmp * r12c2; // cos and sin of 2 angles and final c sin2 = MAX(1.0 - c1mag*c1mag,0.0); sc1 = sqrt(sin2); if (sc1 < SMALL) sc1 = SMALL; sc1 = 1.0/sc1; sin2 = MAX(1.0 - c2mag*c2mag,0.0); sc2 = sqrt(sin2); if (sc2 < SMALL) sc2 = SMALL; sc2 = 1.0/sc2; s1 = sc1 * sc1; s2 = sc2 * sc2; s12 = sc1 * sc2; c = (c0 + c1mag*c2mag) * s12; cx = vb1y*vb2z - vb1z*vb2y; cy = vb1z*vb2x - vb1x*vb2z; cz = vb1x*vb2y - vb1y*vb2x; cmag = sqrt(cx*cx + cy*cy + cz*cz); dx = (cx*vb3x + cy*vb3y + cz*vb3z)/cmag/b3mag; // error check if (c > 1.0 + TOLERANCE || c < (-1.0 - TOLERANCE)) { int me; MPI_Comm_rank(world,&me); if (screen) { char str[128]; sprintf(str,"Dihedral problem: %d " BIGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT, me,update->ntimestep, atom->tag[i1],atom->tag[i2],atom->tag[i3],atom->tag[i4]); error->warning(FLERR,str,0); fprintf(screen," 1st atom: %d %g %g %g\n", me,x[i1][0],x[i1][1],x[i1][2]); fprintf(screen," 2nd atom: %d %g %g %g\n", me,x[i2][0],x[i2][1],x[i2][2]); fprintf(screen," 3rd atom: %d %g %g %g\n", me,x[i3][0],x[i3][1],x[i3][2]); fprintf(screen," 4th atom: %d %g %g %g\n", me,x[i4][0],x[i4][1],x[i4][2]); } } if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; phi = acos(c); if (dx > 0.0) phi *= -1.0; si = sin(phi); if (fabs(si) < SMALLER) si = SMALLER; siinv = 1.0/si; p = aphi[type]*(1.0 - c) + bphi[type]*(1.0 + cos(3.0*phi)) + cphi[type]*(1.0 + cos(phi + MY_PI4)); pd = -aphi[type] + 3.0*bphi[type]*sin(3.0*phi)*siinv + cphi[type]*sin(phi + MY_PI4)*siinv; if (eflag) edihedral = p; a = pd; c = c * a; s12 = s12 * a; a11 = c*sb1*s1; a22 = -sb2 * (2.0*c0*s12 - c*(s1+s2)); a33 = c*sb3*s2; a12 = -r12c1 * (c1mag*c*s1 + c2mag*s12); a13 = -rb1*rb3*s12; a23 = r12c2 * (c2mag*c*s2 + c1mag*s12); sx2 = a12*vb1x + a22*vb2x + a23*vb3x; sy2 = a12*vb1y + a22*vb2y + a23*vb3y; sz2 = a12*vb1z + a22*vb2z + a23*vb3z; f1[0] = a11*vb1x + a12*vb2x + a13*vb3x; f1[1] = a11*vb1y + a12*vb2y + a13*vb3y; f1[2] = a11*vb1z + a12*vb2z + a13*vb3z; f2[0] = -sx2 - f1[0]; f2[1] = -sy2 - f1[1]; f2[2] = -sz2 - f1[2]; f4[0] = a13*vb1x + a23*vb2x + a33*vb3x; f4[1] = a13*vb1y + a23*vb2y + a33*vb3y; f4[2] = a13*vb1z + a23*vb2z + a33*vb3z; f3[0] = sx2 - f4[0]; f3[1] = sy2 - f4[1]; f3[2] = sz2 - f4[2]; // apply force to each of 4 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += f1[0]; f[i1][1] += f1[1]; f[i1][2] += f1[2]; } if (newton_bond || i2 < nlocal) { f[i2][0] += f2[0]; f[i2][1] += f2[1]; f[i2][2] += f2[2]; } if (newton_bond || i3 < nlocal) { f[i3][0] += f3[0]; f[i3][1] += f3[1]; f[i3][2] += f3[2]; } if (newton_bond || i4 < nlocal) { f[i4][0] += f4[0]; f[i4][1] += f4[1]; f[i4][2] += f4[2]; } if (evflag) ev_tally(i1,i2,i3,i4,nlocal,newton_bond,edihedral,f1,f3,f4, vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z); } } /* ---------------------------------------------------------------------- */ void DihedralHelix::allocate() { allocated = 1; int n = atom->ndihedraltypes; memory->create(aphi,n+1,"dihedral:aphi"); memory->create(bphi,n+1,"dihedral:bphi"); memory->create(cphi,n+1,"dihedral:cphi"); memory->create(setflag,n+1,"dihedral:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs from one line in input script ------------------------------------------------------------------------- */ void DihedralHelix::coeff(int narg, char **arg) { if (narg != 4) error->all(FLERR,"Incorrect args for dihedral coefficients"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->ndihedraltypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->ndihedraltypes,ilo,ihi); double aphi_one = force->numeric(FLERR,arg[1]); double bphi_one = force->numeric(FLERR,arg[2]); double cphi_one = force->numeric(FLERR,arg[3]); int count = 0; for (int i = ilo; i <= ihi; i++) { aphi[i] = aphi_one; bphi[i] = bphi_one; cphi[i] = cphi_one; setflag[i] = 1; count++; } if (count == 0) error->all(FLERR,"Incorrect args for dihedral coefficients"); } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void DihedralHelix::write_restart(FILE *fp) { fwrite(&aphi[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&bphi[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&cphi[1],sizeof(double),atom->ndihedraltypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void DihedralHelix::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&aphi[1],sizeof(double),atom->ndihedraltypes,fp); fread(&bphi[1],sizeof(double),atom->ndihedraltypes,fp); fread(&cphi[1],sizeof(double),atom->ndihedraltypes,fp); } MPI_Bcast(&aphi[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&bphi[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&cphi[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); for (int i = 1; i <= atom->ndihedraltypes; i++) setflag[i] = 1; } diff --git a/src/MOLECULE/dihedral_multi_harmonic.cpp b/src/MOLECULE/dihedral_multi_harmonic.cpp index 0842595fb..3a4be46fc 100644 --- a/src/MOLECULE/dihedral_multi_harmonic.cpp +++ b/src/MOLECULE/dihedral_multi_harmonic.cpp @@ -1,333 +1,333 @@ /* ---------------------------------------------------------------------- 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: Mathias Puetz (SNL) and friends ------------------------------------------------------------------------- */ #include #include #include "dihedral_multi_harmonic.h" #include "atom.h" #include "neighbor.h" #include "domain.h" #include "comm.h" #include "force.h" #include "update.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define TOLERANCE 0.05 #define SMALL 0.001 /* ---------------------------------------------------------------------- */ DihedralMultiHarmonic::DihedralMultiHarmonic(LAMMPS *lmp) : Dihedral(lmp) {} /* ---------------------------------------------------------------------- */ DihedralMultiHarmonic::~DihedralMultiHarmonic() { if (allocated) { memory->destroy(setflag); memory->destroy(a1); memory->destroy(a2); memory->destroy(a3); memory->destroy(a4); memory->destroy(a5); } } /* ---------------------------------------------------------------------- */ void DihedralMultiHarmonic::compute(int eflag, int vflag) { int i1,i2,i3,i4,n,type; double vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z,vb2xm,vb2ym,vb2zm; double edihedral,f1[3],f2[3],f3[3],f4[3]; double sb1,sb2,sb3,rb1,rb3,c0,b1mag2,b1mag,b2mag2; double b2mag,b3mag2,b3mag,ctmp,r12c1,c1mag,r12c2; double c2mag,sc1,sc2,s1,s12,c,p,pd,a,a11,a22; double a33,a12,a13,a23,sx2,sy2,sz2; double s2,sin2; edihedral = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; int **dihedrallist = neighbor->dihedrallist; int ndihedrallist = neighbor->ndihedrallist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < ndihedrallist; n++) { i1 = dihedrallist[n][0]; i2 = dihedrallist[n][1]; i3 = dihedrallist[n][2]; i4 = dihedrallist[n][3]; type = dihedrallist[n][4]; // 1st bond vb1x = x[i1][0] - x[i2][0]; vb1y = x[i1][1] - x[i2][1]; vb1z = x[i1][2] - x[i2][2]; // 2nd bond vb2x = x[i3][0] - x[i2][0]; vb2y = x[i3][1] - x[i2][1]; vb2z = x[i3][2] - x[i2][2]; vb2xm = -vb2x; vb2ym = -vb2y; vb2zm = -vb2z; // 3rd bond vb3x = x[i4][0] - x[i3][0]; vb3y = x[i4][1] - x[i3][1]; vb3z = x[i4][2] - x[i3][2]; // c0 calculation sb1 = 1.0 / (vb1x*vb1x + vb1y*vb1y + vb1z*vb1z); sb2 = 1.0 / (vb2x*vb2x + vb2y*vb2y + vb2z*vb2z); sb3 = 1.0 / (vb3x*vb3x + vb3y*vb3y + vb3z*vb3z); rb1 = sqrt(sb1); rb3 = sqrt(sb3); c0 = (vb1x*vb3x + vb1y*vb3y + vb1z*vb3z) * rb1*rb3; // 1st and 2nd angle b1mag2 = vb1x*vb1x + vb1y*vb1y + vb1z*vb1z; b1mag = sqrt(b1mag2); b2mag2 = vb2x*vb2x + vb2y*vb2y + vb2z*vb2z; b2mag = sqrt(b2mag2); b3mag2 = vb3x*vb3x + vb3y*vb3y + vb3z*vb3z; b3mag = sqrt(b3mag2); ctmp = vb1x*vb2x + vb1y*vb2y + vb1z*vb2z; r12c1 = 1.0 / (b1mag*b2mag); c1mag = ctmp * r12c1; ctmp = vb2xm*vb3x + vb2ym*vb3y + vb2zm*vb3z; r12c2 = 1.0 / (b2mag*b3mag); c2mag = ctmp * r12c2; // cos and sin of 2 angles and final c sin2 = MAX(1.0 - c1mag*c1mag,0.0); sc1 = sqrt(sin2); if (sc1 < SMALL) sc1 = SMALL; sc1 = 1.0/sc1; sin2 = MAX(1.0 - c2mag*c2mag,0.0); sc2 = sqrt(sin2); if (sc2 < SMALL) sc2 = SMALL; sc2 = 1.0/sc2; s1 = sc1 * sc1; s2 = sc2 * sc2; s12 = sc1 * sc2; c = (c0 + c1mag*c2mag) * s12; // error check if (c > 1.0 + TOLERANCE || c < (-1.0 - TOLERANCE)) { int me; MPI_Comm_rank(world,&me); if (screen) { char str[128]; sprintf(str,"Dihedral problem: %d " BIGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT, me,update->ntimestep, atom->tag[i1],atom->tag[i2],atom->tag[i3],atom->tag[i4]); error->warning(FLERR,str,0); fprintf(screen," 1st atom: %d %g %g %g\n", me,x[i1][0],x[i1][1],x[i1][2]); fprintf(screen," 2nd atom: %d %g %g %g\n", me,x[i2][0],x[i2][1],x[i2][2]); fprintf(screen," 3rd atom: %d %g %g %g\n", me,x[i3][0],x[i3][1],x[i3][2]); fprintf(screen," 4th atom: %d %g %g %g\n", me,x[i4][0],x[i4][1],x[i4][2]); } } if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; // force & energy // p = sum (i=1,5) a_i * c**(i-1) // pd = dp/dc p = a1[type] + c*(a2[type] + c*(a3[type] + c*(a4[type] + c*a5[type]))); pd = a2[type] + c*(2.0*a3[type] + c*(3.0*a4[type] + c*4.0*a5[type])); if (eflag) edihedral = p; a = pd; c = c * a; s12 = s12 * a; a11 = c*sb1*s1; a22 = -sb2 * (2.0*c0*s12 - c*(s1+s2)); a33 = c*sb3*s2; a12 = -r12c1*(c1mag*c*s1 + c2mag*s12); a13 = -rb1*rb3*s12; a23 = r12c2*(c2mag*c*s2 + c1mag*s12); sx2 = a12*vb1x + a22*vb2x + a23*vb3x; sy2 = a12*vb1y + a22*vb2y + a23*vb3y; sz2 = a12*vb1z + a22*vb2z + a23*vb3z; f1[0] = a11*vb1x + a12*vb2x + a13*vb3x; f1[1] = a11*vb1y + a12*vb2y + a13*vb3y; f1[2] = a11*vb1z + a12*vb2z + a13*vb3z; f2[0] = -sx2 - f1[0]; f2[1] = -sy2 - f1[1]; f2[2] = -sz2 - f1[2]; f4[0] = a13*vb1x + a23*vb2x + a33*vb3x; f4[1] = a13*vb1y + a23*vb2y + a33*vb3y; f4[2] = a13*vb1z + a23*vb2z + a33*vb3z; f3[0] = sx2 - f4[0]; f3[1] = sy2 - f4[1]; f3[2] = sz2 - f4[2]; // apply force to each of 4 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += f1[0]; f[i1][1] += f1[1]; f[i1][2] += f1[2]; } if (newton_bond || i2 < nlocal) { f[i2][0] += f2[0]; f[i2][1] += f2[1]; f[i2][2] += f2[2]; } if (newton_bond || i3 < nlocal) { f[i3][0] += f3[0]; f[i3][1] += f3[1]; f[i3][2] += f3[2]; } if (newton_bond || i4 < nlocal) { f[i4][0] += f4[0]; f[i4][1] += f4[1]; f[i4][2] += f4[2]; } if (evflag) ev_tally(i1,i2,i3,i4,nlocal,newton_bond,edihedral,f1,f3,f4, vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z); } } /* ---------------------------------------------------------------------- */ void DihedralMultiHarmonic::allocate() { allocated = 1; int n = atom->ndihedraltypes; memory->create(a1,n+1,"dihedral:a1"); memory->create(a2,n+1,"dihedral:a2"); memory->create(a3,n+1,"dihedral:a3"); memory->create(a4,n+1,"dihedral:a4"); memory->create(a5,n+1,"dihedral:a5"); memory->create(setflag,n+1,"dihedral:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one type ------------------------------------------------------------------------- */ void DihedralMultiHarmonic::coeff(int narg, char **arg) { if (narg != 6) error->all(FLERR,"Incorrect args for dihedral coefficients"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->ndihedraltypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->ndihedraltypes,ilo,ihi); double a1_one = force->numeric(FLERR,arg[1]); double a2_one = force->numeric(FLERR,arg[2]); double a3_one = force->numeric(FLERR,arg[3]); double a4_one = force->numeric(FLERR,arg[4]); double a5_one = force->numeric(FLERR,arg[5]); int count = 0; for (int i = ilo; i <= ihi; i++) { a1[i] = a1_one; a2[i] = a2_one; a3[i] = a3_one; a4[i] = a4_one; a5[i] = a5_one; setflag[i] = 1; count++; } if (count == 0) error->all(FLERR,"Incorrect args for dihedral coefficients"); } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void DihedralMultiHarmonic::write_restart(FILE *fp) { fwrite(&a1[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&a2[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&a3[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&a4[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&a5[1],sizeof(double),atom->ndihedraltypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void DihedralMultiHarmonic::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&a1[1],sizeof(double),atom->ndihedraltypes,fp); fread(&a2[1],sizeof(double),atom->ndihedraltypes,fp); fread(&a3[1],sizeof(double),atom->ndihedraltypes,fp); fread(&a4[1],sizeof(double),atom->ndihedraltypes,fp); fread(&a5[1],sizeof(double),atom->ndihedraltypes,fp); } MPI_Bcast(&a1[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&a2[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&a3[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&a4[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&a5[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); for (int i = 1; i <= atom->ndihedraltypes; i++) setflag[i] = 1; } diff --git a/src/MOLECULE/dihedral_opls.cpp b/src/MOLECULE/dihedral_opls.cpp index 609fac74b..c3a7ee6aa 100644 --- a/src/MOLECULE/dihedral_opls.cpp +++ b/src/MOLECULE/dihedral_opls.cpp @@ -1,357 +1,357 @@ /* ---------------------------------------------------------------------- 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: Mark Stevens (SNL) ------------------------------------------------------------------------- */ #include #include #include "dihedral_opls.h" #include "atom.h" #include "comm.h" #include "neighbor.h" #include "domain.h" #include "force.h" #include "update.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define TOLERANCE 0.05 #define SMALL 0.001 #define SMALLER 0.00001 /* ---------------------------------------------------------------------- */ DihedralOPLS::DihedralOPLS(LAMMPS *lmp) : Dihedral(lmp) { writedata = 1; } /* ---------------------------------------------------------------------- */ DihedralOPLS::~DihedralOPLS() { if (allocated && !copymode) { memory->destroy(setflag); memory->destroy(k1); memory->destroy(k2); memory->destroy(k3); memory->destroy(k4); } } /* ---------------------------------------------------------------------- */ void DihedralOPLS::compute(int eflag, int vflag) { int i1,i2,i3,i4,n,type; double vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z,vb2xm,vb2ym,vb2zm; double edihedral,f1[3],f2[3],f3[3],f4[3]; double sb1,sb2,sb3,rb1,rb3,c0,b1mag2,b1mag,b2mag2; double b2mag,b3mag2,b3mag,ctmp,r12c1,c1mag,r12c2; double c2mag,sc1,sc2,s1,s12,c,p,pd,a,a11,a22; double a33,a12,a13,a23,sx2,sy2,sz2; double s2,cx,cy,cz,cmag,dx,phi,si,siinv,sin2; edihedral = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; int **dihedrallist = neighbor->dihedrallist; int ndihedrallist = neighbor->ndihedrallist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < ndihedrallist; n++) { i1 = dihedrallist[n][0]; i2 = dihedrallist[n][1]; i3 = dihedrallist[n][2]; i4 = dihedrallist[n][3]; type = dihedrallist[n][4]; // 1st bond vb1x = x[i1][0] - x[i2][0]; vb1y = x[i1][1] - x[i2][1]; vb1z = x[i1][2] - x[i2][2]; // 2nd bond vb2x = x[i3][0] - x[i2][0]; vb2y = x[i3][1] - x[i2][1]; vb2z = x[i3][2] - x[i2][2]; vb2xm = -vb2x; vb2ym = -vb2y; vb2zm = -vb2z; // 3rd bond vb3x = x[i4][0] - x[i3][0]; vb3y = x[i4][1] - x[i3][1]; vb3z = x[i4][2] - x[i3][2]; // c0 calculation sb1 = 1.0 / (vb1x*vb1x + vb1y*vb1y + vb1z*vb1z); sb2 = 1.0 / (vb2x*vb2x + vb2y*vb2y + vb2z*vb2z); sb3 = 1.0 / (vb3x*vb3x + vb3y*vb3y + vb3z*vb3z); rb1 = sqrt(sb1); rb3 = sqrt(sb3); c0 = (vb1x*vb3x + vb1y*vb3y + vb1z*vb3z) * rb1*rb3; // 1st and 2nd angle b1mag2 = vb1x*vb1x + vb1y*vb1y + vb1z*vb1z; b1mag = sqrt(b1mag2); b2mag2 = vb2x*vb2x + vb2y*vb2y + vb2z*vb2z; b2mag = sqrt(b2mag2); b3mag2 = vb3x*vb3x + vb3y*vb3y + vb3z*vb3z; b3mag = sqrt(b3mag2); ctmp = vb1x*vb2x + vb1y*vb2y + vb1z*vb2z; r12c1 = 1.0 / (b1mag*b2mag); c1mag = ctmp * r12c1; ctmp = vb2xm*vb3x + vb2ym*vb3y + vb2zm*vb3z; r12c2 = 1.0 / (b2mag*b3mag); c2mag = ctmp * r12c2; // cos and sin of 2 angles and final c sin2 = MAX(1.0 - c1mag*c1mag,0.0); sc1 = sqrt(sin2); if (sc1 < SMALL) sc1 = SMALL; sc1 = 1.0/sc1; sin2 = MAX(1.0 - c2mag*c2mag,0.0); sc2 = sqrt(sin2); if (sc2 < SMALL) sc2 = SMALL; sc2 = 1.0/sc2; s1 = sc1 * sc1; s2 = sc2 * sc2; s12 = sc1 * sc2; c = (c0 + c1mag*c2mag) * s12; cx = vb1y*vb2z - vb1z*vb2y; cy = vb1z*vb2x - vb1x*vb2z; cz = vb1x*vb2y - vb1y*vb2x; cmag = sqrt(cx*cx + cy*cy + cz*cz); dx = (cx*vb3x + cy*vb3y + cz*vb3z)/cmag/b3mag; // error check if (c > 1.0 + TOLERANCE || c < (-1.0 - TOLERANCE)) { int me; MPI_Comm_rank(world,&me); if (screen) { char str[128]; sprintf(str,"Dihedral problem: %d " BIGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT, me,update->ntimestep, atom->tag[i1],atom->tag[i2],atom->tag[i3],atom->tag[i4]); error->warning(FLERR,str,0); fprintf(screen," 1st atom: %d %g %g %g\n", me,x[i1][0],x[i1][1],x[i1][2]); fprintf(screen," 2nd atom: %d %g %g %g\n", me,x[i2][0],x[i2][1],x[i2][2]); fprintf(screen," 3rd atom: %d %g %g %g\n", me,x[i3][0],x[i3][1],x[i3][2]); fprintf(screen," 4th atom: %d %g %g %g\n", me,x[i4][0],x[i4][1],x[i4][2]); } } if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; // force & energy // p = sum (i=1,4) k_i * (1 + (-1)**(i+1)*cos(i*phi) ) // pd = dp/dc phi = acos(c); if (dx < 0.0) phi *= -1.0; si = sin(phi); if (fabs(si) < SMALLER) si = SMALLER; siinv = 1.0/si; p = k1[type]*(1.0 + c) + k2[type]*(1.0 - cos(2.0*phi)) + k3[type]*(1.0 + cos(3.0*phi)) + k4[type]*(1.0 - cos(4.0*phi)) ; pd = k1[type] - 2.0*k2[type]*sin(2.0*phi)*siinv + 3.0*k3[type]*sin(3.0*phi)*siinv - 4.0*k4[type]*sin(4.0*phi)*siinv; if (eflag) edihedral = p; a = pd; c = c * a; s12 = s12 * a; a11 = c*sb1*s1; a22 = -sb2 * (2.0*c0*s12 - c*(s1+s2)); a33 = c*sb3*s2; a12 = -r12c1 * (c1mag*c*s1 + c2mag*s12); a13 = -rb1*rb3*s12; a23 = r12c2 * (c2mag*c*s2 + c1mag*s12); sx2 = a12*vb1x + a22*vb2x + a23*vb3x; sy2 = a12*vb1y + a22*vb2y + a23*vb3y; sz2 = a12*vb1z + a22*vb2z + a23*vb3z; f1[0] = a11*vb1x + a12*vb2x + a13*vb3x; f1[1] = a11*vb1y + a12*vb2y + a13*vb3y; f1[2] = a11*vb1z + a12*vb2z + a13*vb3z; f2[0] = -sx2 - f1[0]; f2[1] = -sy2 - f1[1]; f2[2] = -sz2 - f1[2]; f4[0] = a13*vb1x + a23*vb2x + a33*vb3x; f4[1] = a13*vb1y + a23*vb2y + a33*vb3y; f4[2] = a13*vb1z + a23*vb2z + a33*vb3z; f3[0] = sx2 - f4[0]; f3[1] = sy2 - f4[1]; f3[2] = sz2 - f4[2]; // apply force to each of 4 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += f1[0]; f[i1][1] += f1[1]; f[i1][2] += f1[2]; } if (newton_bond || i2 < nlocal) { f[i2][0] += f2[0]; f[i2][1] += f2[1]; f[i2][2] += f2[2]; } if (newton_bond || i3 < nlocal) { f[i3][0] += f3[0]; f[i3][1] += f3[1]; f[i3][2] += f3[2]; } if (newton_bond || i4 < nlocal) { f[i4][0] += f4[0]; f[i4][1] += f4[1]; f[i4][2] += f4[2]; } if (evflag) ev_tally(i1,i2,i3,i4,nlocal,newton_bond,edihedral,f1,f3,f4, vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z); } } /* ---------------------------------------------------------------------- */ void DihedralOPLS::allocate() { allocated = 1; int n = atom->ndihedraltypes; memory->create(k1,n+1,"dihedral:k1"); memory->create(k2,n+1,"dihedral:k2"); memory->create(k3,n+1,"dihedral:k3"); memory->create(k4,n+1,"dihedral:k4"); memory->create(setflag,n+1,"dihedral:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one type ------------------------------------------------------------------------- */ void DihedralOPLS::coeff(int narg, char **arg) { if (narg != 5) error->all(FLERR,"Incorrect args for dihedral coefficients"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->ndihedraltypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->ndihedraltypes,ilo,ihi); double k1_one = force->numeric(FLERR,arg[1]); double k2_one = force->numeric(FLERR,arg[2]); double k3_one = force->numeric(FLERR,arg[3]); double k4_one = force->numeric(FLERR,arg[4]); // store 1/2 factor with prefactor int count = 0; for (int i = ilo; i <= ihi; i++) { k1[i] = 0.5*k1_one; k2[i] = 0.5*k2_one; k3[i] = 0.5*k3_one; k4[i] = 0.5*k4_one; setflag[i] = 1; count++; } if (count == 0) error->all(FLERR,"Incorrect args for dihedral coefficients"); } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void DihedralOPLS::write_restart(FILE *fp) { fwrite(&k1[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&k2[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&k3[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&k4[1],sizeof(double),atom->ndihedraltypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void DihedralOPLS::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&k1[1],sizeof(double),atom->ndihedraltypes,fp); fread(&k2[1],sizeof(double),atom->ndihedraltypes,fp); fread(&k3[1],sizeof(double),atom->ndihedraltypes,fp); fread(&k4[1],sizeof(double),atom->ndihedraltypes,fp); } MPI_Bcast(&k1[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&k2[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&k3[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&k4[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); for (int i = 1; i <= atom->ndihedraltypes; i++) setflag[i] = 1; } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void DihedralOPLS::write_data(FILE *fp) { for (int i = 1; i <= atom->ndihedraltypes; i++) fprintf(fp,"%d %g %g %g %g\n",i,2.0*k1[i],2.0*k2[i],2.0*k3[i],2.0*k4[i]); } diff --git a/src/MOLECULE/improper_cvff.cpp b/src/MOLECULE/improper_cvff.cpp index 28b3612c7..45740d788 100644 --- a/src/MOLECULE/improper_cvff.cpp +++ b/src/MOLECULE/improper_cvff.cpp @@ -1,358 +1,358 @@ /* ---------------------------------------------------------------------- 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 #include #include #include "improper_cvff.h" #include "atom.h" #include "comm.h" #include "neighbor.h" #include "domain.h" #include "force.h" #include "update.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define TOLERANCE 0.05 #define SMALL 0.001 /* ---------------------------------------------------------------------- */ ImproperCvff::ImproperCvff(LAMMPS *lmp) : Improper(lmp) { writedata = 1; } /* ---------------------------------------------------------------------- */ ImproperCvff::~ImproperCvff() { if (allocated) { memory->destroy(setflag); memory->destroy(k); memory->destroy(sign); memory->destroy(multiplicity); } } /* ---------------------------------------------------------------------- */ void ImproperCvff::compute(int eflag, int vflag) { int i1,i2,i3,i4,m,n,type; double vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z,vb2xm,vb2ym,vb2zm; double eimproper,f1[3],f2[3],f3[3],f4[3]; double sb1,sb2,sb3,rb1,rb3,c0,b1mag2,b1mag,b2mag2; double b2mag,b3mag2,b3mag,ctmp,r12c1,c1mag,r12c2; double c2mag,sc1,sc2,s1,s2,s12,c,p,pd,rc2,a,a11,a22; double a33,a12,a13,a23,sx2,sy2,sz2; eimproper = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; int **improperlist = neighbor->improperlist; int nimproperlist = neighbor->nimproperlist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < nimproperlist; n++) { i1 = improperlist[n][0]; i2 = improperlist[n][1]; i3 = improperlist[n][2]; i4 = improperlist[n][3]; type = improperlist[n][4]; // 1st bond vb1x = x[i1][0] - x[i2][0]; vb1y = x[i1][1] - x[i2][1]; vb1z = x[i1][2] - x[i2][2]; // 2nd bond vb2x = x[i3][0] - x[i2][0]; vb2y = x[i3][1] - x[i2][1]; vb2z = x[i3][2] - x[i2][2]; vb2xm = -vb2x; vb2ym = -vb2y; vb2zm = -vb2z; // 3rd bond vb3x = x[i4][0] - x[i3][0]; vb3y = x[i4][1] - x[i3][1]; vb3z = x[i4][2] - x[i3][2]; // c0 calculation sb1 = 1.0 / (vb1x*vb1x + vb1y*vb1y + vb1z*vb1z); sb2 = 1.0 / (vb2x*vb2x + vb2y*vb2y + vb2z*vb2z); sb3 = 1.0 / (vb3x*vb3x + vb3y*vb3y + vb3z*vb3z); rb1 = sqrt(sb1); rb3 = sqrt(sb3); c0 = (vb1x*vb3x + vb1y*vb3y + vb1z*vb3z) * rb1*rb3; // 1st and 2nd angle b1mag2 = vb1x*vb1x + vb1y*vb1y + vb1z*vb1z; b1mag = sqrt(b1mag2); b2mag2 = vb2x*vb2x + vb2y*vb2y + vb2z*vb2z; b2mag = sqrt(b2mag2); b3mag2 = vb3x*vb3x + vb3y*vb3y + vb3z*vb3z; b3mag = sqrt(b3mag2); ctmp = vb1x*vb2x + vb1y*vb2y + vb1z*vb2z; r12c1 = 1.0 / (b1mag*b2mag); c1mag = ctmp * r12c1; ctmp = vb2xm*vb3x + vb2ym*vb3y + vb2zm*vb3z; r12c2 = 1.0 / (b2mag*b3mag); c2mag = ctmp * r12c2; // cos and sin of 2 angles and final c sc1 = sqrt(1.0 - c1mag*c1mag); if (sc1 < SMALL) sc1 = SMALL; sc1 = 1.0/sc1; sc2 = sqrt(1.0 - c2mag*c2mag); if (sc2 < SMALL) sc2 = SMALL; sc2 = 1.0/sc2; s1 = sc1 * sc1; s2 = sc2 * sc2; s12 = sc1 * sc2; c = (c0 + c1mag*c2mag) * s12; // error check if (c > 1.0 + TOLERANCE || c < (-1.0 - TOLERANCE)) { int me; MPI_Comm_rank(world,&me); if (screen) { char str[128]; sprintf(str,"Improper problem: %d " BIGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT, me,update->ntimestep, atom->tag[i1],atom->tag[i2],atom->tag[i3],atom->tag[i4]); error->warning(FLERR,str,0); fprintf(screen," 1st atom: %d %g %g %g\n", me,x[i1][0],x[i1][1],x[i1][2]); fprintf(screen," 2nd atom: %d %g %g %g\n", me,x[i2][0],x[i2][1],x[i2][2]); fprintf(screen," 3rd atom: %d %g %g %g\n", me,x[i3][0],x[i3][1],x[i3][2]); fprintf(screen," 4th atom: %d %g %g %g\n", me,x[i4][0],x[i4][1],x[i4][2]); } } if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; // force & energy // p = 1 + cos(n*phi) for d = 1 // p = 1 - cos(n*phi) for d = -1 // pd = dp/dc / 2 m = multiplicity[type]; if (m == 2) { p = 2.0*c*c; pd = 2.0*c; } else if (m == 3) { rc2 = c*c; p = (4.0*rc2-3.0)*c + 1.0; pd = 6.0*rc2 - 1.5; } else if (m == 4) { rc2 = c*c; p = 8.0*(rc2-1)*rc2 + 2.0; pd = (16.0*rc2-8.0)*c; } else if (m == 6) { rc2 = c*c; p = ((32.0*rc2-48.0)*rc2 + 18.0)*rc2; pd = (96.0*(rc2-1.0)*rc2 + 18.0)*c; } else if (m == 1) { p = c + 1.0; pd = 0.5; } else if (m == 5) { rc2 = c*c; p = ((16.0*rc2-20.0)*rc2 + 5.0)*c + 1.0; pd = (40.0*rc2-30.0)*rc2 + 2.5; } else if (m == 0) { p = 2.0; pd = 0.0; } if (sign[type] == -1) { p = 2.0 - p; pd = -pd; } if (eflag) eimproper = k[type]*p; a = 2.0 * k[type] * pd; c = c * a; s12 = s12 * a; a11 = c*sb1*s1; a22 = -sb2*(2.0*c0*s12 - c*(s1+s2)); a33 = c*sb3*s2; a12 = -r12c1*(c1mag*c*s1 + c2mag*s12); a13 = -rb1*rb3*s12; a23 = r12c2*(c2mag*c*s2 + c1mag*s12); sx2 = a12*vb1x + a22*vb2x + a23*vb3x; sy2 = a12*vb1y + a22*vb2y + a23*vb3y; sz2 = a12*vb1z + a22*vb2z + a23*vb3z; f1[0] = a11*vb1x + a12*vb2x + a13*vb3x; f1[1] = a11*vb1y + a12*vb2y + a13*vb3y; f1[2] = a11*vb1z + a12*vb2z + a13*vb3z; f2[0] = -sx2 - f1[0]; f2[1] = -sy2 - f1[1]; f2[2] = -sz2 - f1[2]; f4[0] = a13*vb1x + a23*vb2x + a33*vb3x; f4[1] = a13*vb1y + a23*vb2y + a33*vb3y; f4[2] = a13*vb1z + a23*vb2z + a33*vb3z; f3[0] = sx2 - f4[0]; f3[1] = sy2 - f4[1]; f3[2] = sz2 - f4[2]; // apply force to each of 4 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += f1[0]; f[i1][1] += f1[1]; f[i1][2] += f1[2]; } if (newton_bond || i2 < nlocal) { f[i2][0] += f2[0]; f[i2][1] += f2[1]; f[i2][2] += f2[2]; } if (newton_bond || i3 < nlocal) { f[i3][0] += f3[0]; f[i3][1] += f3[1]; f[i3][2] += f3[2]; } if (newton_bond || i4 < nlocal) { f[i4][0] += f4[0]; f[i4][1] += f4[1]; f[i4][2] += f4[2]; } if (evflag) ev_tally(i1,i2,i3,i4,nlocal,newton_bond,eimproper,f1,f3,f4, vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z); } } /* ---------------------------------------------------------------------- */ void ImproperCvff::allocate() { allocated = 1; int n = atom->nimpropertypes; memory->create(k,n+1,"improper:k"); memory->create(sign,n+1,"improper:sign"); memory->create(multiplicity,n+1,"improper:multiplicity"); memory->create(setflag,n+1,"improper:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one type ------------------------------------------------------------------------- */ void ImproperCvff::coeff(int narg, char **arg) { if (narg != 4) error->all(FLERR,"Incorrect args for improper coefficients"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->nimpropertypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->nimpropertypes,ilo,ihi); double k_one = force->numeric(FLERR,arg[1]); int sign_one = force->inumeric(FLERR,arg[2]); int multiplicity_one = force->inumeric(FLERR,arg[3]); int count = 0; for (int i = ilo; i <= ihi; i++) { k[i] = k_one; sign[i] = sign_one; multiplicity[i] = multiplicity_one; setflag[i] = 1; count++; } if (count == 0) error->all(FLERR,"Incorrect args for improper coefficients"); } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void ImproperCvff::write_restart(FILE *fp) { fwrite(&k[1],sizeof(double),atom->nimpropertypes,fp); fwrite(&sign[1],sizeof(int),atom->nimpropertypes,fp); fwrite(&multiplicity[1],sizeof(int),atom->nimpropertypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void ImproperCvff::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&k[1],sizeof(double),atom->nimpropertypes,fp); fread(&sign[1],sizeof(int),atom->nimpropertypes,fp); fread(&multiplicity[1],sizeof(int),atom->nimpropertypes,fp); } MPI_Bcast(&k[1],atom->nimpropertypes,MPI_DOUBLE,0,world); MPI_Bcast(&sign[1],atom->nimpropertypes,MPI_INT,0,world); MPI_Bcast(&multiplicity[1],atom->nimpropertypes,MPI_INT,0,world); for (int i = 1; i <= atom->nimpropertypes; i++) setflag[i] = 1; } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void ImproperCvff::write_data(FILE *fp) { for (int i = 1; i <= atom->nimpropertypes; i++) fprintf(fp,"%d %g %d %d\n",i,k[i],sign[i],multiplicity[i]); } diff --git a/src/MOLECULE/improper_harmonic.cpp b/src/MOLECULE/improper_harmonic.cpp index 56ddce6f5..c482055c7 100644 --- a/src/MOLECULE/improper_harmonic.cpp +++ b/src/MOLECULE/improper_harmonic.cpp @@ -1,297 +1,297 @@ /* ---------------------------------------------------------------------- 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 #include #include #include "improper_harmonic.h" #include "atom.h" #include "comm.h" #include "neighbor.h" #include "domain.h" #include "force.h" #include "update.h" #include "math_const.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace MathConst; #define TOLERANCE 0.05 #define SMALL 0.001 /* ---------------------------------------------------------------------- */ ImproperHarmonic::ImproperHarmonic(LAMMPS *lmp) : Improper(lmp) { writedata = 1; } /* ---------------------------------------------------------------------- */ ImproperHarmonic::~ImproperHarmonic() { if (allocated && !copymode) { memory->destroy(setflag); memory->destroy(k); memory->destroy(chi); } } /* ---------------------------------------------------------------------- */ void ImproperHarmonic::compute(int eflag, int vflag) { int i1,i2,i3,i4,n,type; double vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z; double eimproper,f1[3],f2[3],f3[3],f4[3]; double ss1,ss2,ss3,r1,r2,r3,c0,c1,c2,s1,s2; double s12,c,s,domega,a,a11,a22,a33,a12,a13,a23; double sx2,sy2,sz2; eimproper = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; int **improperlist = neighbor->improperlist; int nimproperlist = neighbor->nimproperlist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < nimproperlist; n++) { i1 = improperlist[n][0]; i2 = improperlist[n][1]; i3 = improperlist[n][2]; i4 = improperlist[n][3]; type = improperlist[n][4]; // geometry of 4-body vb1x = x[i1][0] - x[i2][0]; vb1y = x[i1][1] - x[i2][1]; vb1z = x[i1][2] - x[i2][2]; vb2x = x[i3][0] - x[i2][0]; vb2y = x[i3][1] - x[i2][1]; vb2z = x[i3][2] - x[i2][2]; vb3x = x[i4][0] - x[i3][0]; vb3y = x[i4][1] - x[i3][1]; vb3z = x[i4][2] - x[i3][2]; ss1 = 1.0 / (vb1x*vb1x + vb1y*vb1y + vb1z*vb1z); ss2 = 1.0 / (vb2x*vb2x + vb2y*vb2y + vb2z*vb2z); ss3 = 1.0 / (vb3x*vb3x + vb3y*vb3y + vb3z*vb3z); r1 = sqrt(ss1); r2 = sqrt(ss2); r3 = sqrt(ss3); // sin and cos of angle c0 = (vb1x * vb3x + vb1y * vb3y + vb1z * vb3z) * r1 * r3; c1 = (vb1x * vb2x + vb1y * vb2y + vb1z * vb2z) * r1 * r2; c2 = -(vb3x * vb2x + vb3y * vb2y + vb3z * vb2z) * r3 * r2; s1 = 1.0 - c1*c1; if (s1 < SMALL) s1 = SMALL; s1 = 1.0 / s1; s2 = 1.0 - c2*c2; if (s2 < SMALL) s2 = SMALL; s2 = 1.0 / s2; s12 = sqrt(s1*s2); c = (c1*c2 + c0) * s12; // error check if (c > 1.0 + TOLERANCE || c < (-1.0 - TOLERANCE)) { int me; MPI_Comm_rank(world,&me); if (screen) { char str[128]; sprintf(str,"Improper problem: %d " BIGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT, me,update->ntimestep, atom->tag[i1],atom->tag[i2],atom->tag[i3],atom->tag[i4]); error->warning(FLERR,str,0); fprintf(screen," 1st atom: %d %g %g %g\n", me,x[i1][0],x[i1][1],x[i1][2]); fprintf(screen," 2nd atom: %d %g %g %g\n", me,x[i2][0],x[i2][1],x[i2][2]); fprintf(screen," 3rd atom: %d %g %g %g\n", me,x[i3][0],x[i3][1],x[i3][2]); fprintf(screen," 4th atom: %d %g %g %g\n", me,x[i4][0],x[i4][1],x[i4][2]); } } if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; s = sqrt(1.0 - c*c); if (s < SMALL) s = SMALL; // force & energy domega = acos(c) - chi[type]; a = k[type] * domega; if (eflag) eimproper = a*domega; a = -a * 2.0/s; c = c * a; s12 = s12 * a; a11 = c*ss1*s1; a22 = -ss2 * (2.0*c0*s12 - c*(s1+s2)); a33 = c*ss3*s2; a12 = -r1*r2*(c1*c*s1 + c2*s12); a13 = -r1*r3*s12; a23 = r2*r3*(c2*c*s2 + c1*s12); sx2 = a22*vb2x + a23*vb3x + a12*vb1x; sy2 = a22*vb2y + a23*vb3y + a12*vb1y; sz2 = a22*vb2z + a23*vb3z + a12*vb1z; f1[0] = a12*vb2x + a13*vb3x + a11*vb1x; f1[1] = a12*vb2y + a13*vb3y + a11*vb1y; f1[2] = a12*vb2z + a13*vb3z + a11*vb1z; f2[0] = -sx2 - f1[0]; f2[1] = -sy2 - f1[1]; f2[2] = -sz2 - f1[2]; f4[0] = a23*vb2x + a33*vb3x + a13*vb1x; f4[1] = a23*vb2y + a33*vb3y + a13*vb1y; f4[2] = a23*vb2z + a33*vb3z + a13*vb1z; f3[0] = sx2 - f4[0]; f3[1] = sy2 - f4[1]; f3[2] = sz2 - f4[2]; // apply force to each of 4 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += f1[0]; f[i1][1] += f1[1]; f[i1][2] += f1[2]; } if (newton_bond || i2 < nlocal) { f[i2][0] += f2[0]; f[i2][1] += f2[1]; f[i2][2] += f2[2]; } if (newton_bond || i3 < nlocal) { f[i3][0] += f3[0]; f[i3][1] += f3[1]; f[i3][2] += f3[2]; } if (newton_bond || i4 < nlocal) { f[i4][0] += f4[0]; f[i4][1] += f4[1]; f[i4][2] += f4[2]; } if (evflag) ev_tally(i1,i2,i3,i4,nlocal,newton_bond,eimproper,f1,f3,f4, vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z); } } /* ---------------------------------------------------------------------- */ void ImproperHarmonic::allocate() { allocated = 1; int n = atom->nimpropertypes; memory->create(k,n+1,"improper:k"); memory->create(chi,n+1,"improper:chi"); memory->create(setflag,n+1,"improper:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one type ------------------------------------------------------------------------- */ void ImproperHarmonic::coeff(int narg, char **arg) { if (narg != 3) error->all(FLERR,"Incorrect args for improper coefficients"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->nimpropertypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->nimpropertypes,ilo,ihi); double k_one = force->numeric(FLERR,arg[1]); double chi_one = force->numeric(FLERR,arg[2]); // convert chi from degrees to radians int count = 0; for (int i = ilo; i <= ihi; i++) { k[i] = k_one; chi[i] = chi_one/180.0 * MY_PI; setflag[i] = 1; count++; } if (count == 0) error->all(FLERR,"Incorrect args for improper coefficients"); } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void ImproperHarmonic::write_restart(FILE *fp) { fwrite(&k[1],sizeof(double),atom->nimpropertypes,fp); fwrite(&chi[1],sizeof(double),atom->nimpropertypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void ImproperHarmonic::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&k[1],sizeof(double),atom->nimpropertypes,fp); fread(&chi[1],sizeof(double),atom->nimpropertypes,fp); } MPI_Bcast(&k[1],atom->nimpropertypes,MPI_DOUBLE,0,world); MPI_Bcast(&chi[1],atom->nimpropertypes,MPI_DOUBLE,0,world); for (int i = 1; i <= atom->nimpropertypes; i++) setflag[i] = 1; } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void ImproperHarmonic::write_data(FILE *fp) { for (int i = 1; i <= atom->nimpropertypes; i++) fprintf(fp,"%d %g %g\n",i,k[i],chi[i]/MY_PI*180.0); } diff --git a/src/MOLECULE/improper_umbrella.cpp b/src/MOLECULE/improper_umbrella.cpp index a2f176e73..8a9b0b443 100644 --- a/src/MOLECULE/improper_umbrella.cpp +++ b/src/MOLECULE/improper_umbrella.cpp @@ -1,340 +1,340 @@ /* ---------------------------------------------------------------------- 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: Tod A Pascal (Caltech) ------------------------------------------------------------------------- */ #include #include #include #include "improper_umbrella.h" #include "atom.h" #include "comm.h" #include "neighbor.h" #include "domain.h" #include "force.h" #include "update.h" #include "math_const.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace MathConst; #define TOLERANCE 0.05 #define SMALL 0.001 /* ---------------------------------------------------------------------- */ ImproperUmbrella::ImproperUmbrella(LAMMPS *lmp) : Improper(lmp) { writedata = 1; } /* ---------------------------------------------------------------------- */ ImproperUmbrella::~ImproperUmbrella() { if (allocated) { memory->destroy(setflag); memory->destroy(kw); memory->destroy(w0); memory->destroy(C); } } /* ---------------------------------------------------------------------- */ void ImproperUmbrella::compute(int eflag, int vflag) { int i1,i2,i3,i4,n,type; double eimproper,f1[3],f2[3],f3[3],f4[3]; double vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z; double domega,c,a,s,projhfg,dhax,dhay,dhaz,dahx,dahy,dahz,cotphi; double ax,ay,az,ra2,rh2,ra,rh,rar,rhr,arx,ary,arz,hrx,hry,hrz; eimproper = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; int **improperlist = neighbor->improperlist; int nimproperlist = neighbor->nimproperlist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < nimproperlist; n++) { i1 = improperlist[n][0]; i2 = improperlist[n][1]; i3 = improperlist[n][2]; i4 = improperlist[n][3]; type = improperlist[n][4]; // 1st bond vb1x = x[i2][0] - x[i1][0]; vb1y = x[i2][1] - x[i1][1]; vb1z = x[i2][2] - x[i1][2]; // 2nd bond vb2x = x[i3][0] - x[i1][0]; vb2y = x[i3][1] - x[i1][1]; vb2z = x[i3][2] - x[i1][2]; // 3rd bond vb3x = x[i4][0] - x[i1][0]; vb3y = x[i4][1] - x[i1][1]; vb3z = x[i4][2] - x[i1][2]; // c0 calculation // A = vb1 X vb2 is perpendicular to IJK plane ax = vb1y*vb2z-vb1z*vb2y; ay = vb1z*vb2x-vb1x*vb2z; az = vb1x*vb2y-vb1y*vb2x; ra2 = ax*ax+ay*ay+az*az; rh2 = vb3x*vb3x+vb3y*vb3y+vb3z*vb3z; ra = sqrt(ra2); rh = sqrt(rh2); if (ra < SMALL) ra = SMALL; if (rh < SMALL) rh = SMALL; rar = 1/ra; rhr = 1/rh; arx = ax*rar; ary = ay*rar; arz = az*rar; hrx = vb3x*rhr; hry = vb3y*rhr; hrz = vb3z*rhr; c = arx*hrx+ary*hry+arz*hrz; // error check if (c > 1.0 + TOLERANCE || c < (-1.0 - TOLERANCE)) { int me; MPI_Comm_rank(world,&me); if (screen) { char str[128]; sprintf(str,"Improper problem: %d " BIGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT, me,update->ntimestep, atom->tag[i1],atom->tag[i2],atom->tag[i3],atom->tag[i4]); error->warning(FLERR,str,0); fprintf(screen," 1st atom: %d %g %g %g\n", me,x[i1][0],x[i1][1],x[i1][2]); fprintf(screen," 2nd atom: %d %g %g %g\n", me,x[i2][0],x[i2][1],x[i2][2]); fprintf(screen," 3rd atom: %d %g %g %g\n", me,x[i3][0],x[i3][1],x[i3][2]); fprintf(screen," 4th atom: %d %g %g %g\n", me,x[i4][0],x[i4][1],x[i4][2]); } } if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; s = sqrt(1.0 - c*c); if (s < SMALL) s = SMALL; cotphi = c/s; projhfg = (vb3x*vb1x+vb3y*vb1y+vb3z*vb1z) / sqrt(vb1x*vb1x+vb1y*vb1y+vb1z*vb1z); projhfg += (vb3x*vb2x+vb3y*vb2y+vb3z*vb2z) / sqrt(vb2x*vb2x+vb2y*vb2y+vb2z*vb2z); if (projhfg > 0.0) { s *= -1.0; cotphi *= -1.0; } // force and energy // if w0 = 0: E = k * (1 - cos w) // if w0 != 0: E = 0.5 * C (cos w - cos w0)^2, C = k/(sin(w0)^2 if (w0[type] == 0.0) { if (eflag) eimproper = kw[type] * (1.0-s); a = -kw[type]; } else { domega = s - cos(w0[type]); a = 0.5 * C[type] * domega; if (eflag) eimproper = a * domega; a *= 2.0; } // dhax = diffrence between H and A in X direction, etc a = a*cotphi; dhax = hrx-c*arx; dhay = hry-c*ary; dhaz = hrz-c*arz; dahx = arx-c*hrx; dahy = ary-c*hry; dahz = arz-c*hrz; f2[0] = (dhay*vb1z - dhaz*vb1y)*rar; f2[1] = (dhaz*vb1x - dhax*vb1z)*rar; f2[2] = (dhax*vb1y - dhay*vb1x)*rar; f3[0] = (-dhay*vb2z + dhaz*vb2y)*rar; f3[1] = (-dhaz*vb2x + dhax*vb2z)*rar; f3[2] = (-dhax*vb2y + dhay*vb2x)*rar; f4[0] = dahx*rhr; f4[1] = dahy*rhr; f4[2] = dahz*rhr; f1[0] = -(f2[0] + f3[0] + f4[0]); f1[1] = -(f2[1] + f3[1] + f4[1]); f1[2] = -(f2[2] + f3[2] + f4[2]); // apply force to each of 4 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += f1[0]*a; f[i1][1] += f1[1]*a; f[i1][2] += f1[2]*a; } if (newton_bond || i2 < nlocal) { f[i2][0] += f3[0]*a; f[i2][1] += f3[1]*a; f[i2][2] += f3[2]*a; } if (newton_bond || i3 < nlocal) { f[i3][0] += f2[0]*a; f[i3][1] += f2[1]*a; f[i3][2] += f2[2]*a; } if (newton_bond || i4 < nlocal) { f[i4][0] += f4[0]*a; f[i4][1] += f4[1]*a; f[i4][2] += f4[2]*a; } if (evflag) { // get correct 4-body geometry for virial tally vb1x = x[i1][0] - x[i2][0]; vb1y = x[i1][1] - x[i2][1]; vb1z = x[i1][2] - x[i2][2]; vb2x = x[i3][0] - x[i2][0]; vb2y = x[i3][1] - x[i2][1]; vb2z = x[i3][2] - x[i2][2]; vb3x = x[i4][0] - x[i3][0]; vb3y = x[i4][1] - x[i3][1]; vb3z = x[i4][2] - x[i3][2]; ev_tally(i1,i2,i3,i4,nlocal,newton_bond,eimproper,f1,f3,f4, vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z); } } } /* ---------------------------------------------------------------------- */ void ImproperUmbrella::allocate() { allocated = 1; int n = atom->nimpropertypes; memory->create(kw,n+1,"improper:kw"); memory->create(w0,n+1,"improper:w0"); memory->create(C,n+1,"improper:C"); memory->create(setflag,n+1,"improper:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one type ------------------------------------------------------------------------- */ void ImproperUmbrella::coeff(int narg, char **arg) { if (narg != 3) error->all(FLERR,"Incorrect args for improper coefficients"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->nimpropertypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->nimpropertypes,ilo,ihi); double k_one = force->numeric(FLERR,arg[1]); double w_one = force->numeric(FLERR,arg[2]); // convert w0 from degrees to radians int count = 0; for (int i = ilo; i <= ihi; i++) { kw[i] = k_one; w0[i] = w_one/180.0 * MY_PI; if (w_one == 0) C[i] = 1.0; else C[i] = kw[i]/(pow(sin(w0[i]),2.0)); setflag[i] = 1; count++; } if (count == 0) error->all(FLERR,"Incorrect args for improper coefficients"); } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void ImproperUmbrella::write_restart(FILE *fp) { fwrite(&kw[1],sizeof(double),atom->nimpropertypes,fp); fwrite(&w0[1],sizeof(double),atom->nimpropertypes,fp); fwrite(&C[1],sizeof(double),atom->nimpropertypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void ImproperUmbrella::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&kw[1],sizeof(double),atom->nimpropertypes,fp); fread(&w0[1],sizeof(double),atom->nimpropertypes,fp); fread(&C[1],sizeof(double),atom->nimpropertypes,fp); } MPI_Bcast(&kw[1],atom->nimpropertypes,MPI_DOUBLE,0,world); MPI_Bcast(&w0[1],atom->nimpropertypes,MPI_DOUBLE,0,world); MPI_Bcast(&C[1],atom->nimpropertypes,MPI_DOUBLE,0,world); for (int i = 1; i <= atom->nimpropertypes; i++) setflag[i] = 1; } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void ImproperUmbrella::write_data(FILE *fp) { for (int i = 1; i <= atom->nimpropertypes; i++) fprintf(fp,"%d %g %g\n",i,kw[i],w0[i]/MY_PI*180.0); } diff --git a/src/MOLECULE/pair_hbond_dreiding_lj.cpp b/src/MOLECULE/pair_hbond_dreiding_lj.cpp index af54c9bdf..ecb4883cb 100644 --- a/src/MOLECULE/pair_hbond_dreiding_lj.cpp +++ b/src/MOLECULE/pair_hbond_dreiding_lj.cpp @@ -1,571 +1,571 @@ /* ---------------------------------------------------------------------- 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: Tod A Pascal (Caltech) ------------------------------------------------------------------------- */ #include #include #include #include #include "pair_hbond_dreiding_lj.h" #include "atom.h" #include "atom_vec.h" #include "molecule.h" #include "comm.h" #include "force.h" #include "neighbor.h" #include "neigh_request.h" #include "neigh_list.h" #include "domain.h" #include "math_const.h" #include "math_special.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace MathConst; using namespace MathSpecial; #define SMALL 0.001 #define CHUNK 8 /* ---------------------------------------------------------------------- */ PairHbondDreidingLJ::PairHbondDreidingLJ(LAMMPS *lmp) : Pair(lmp) { // hbond cannot compute virial as F dot r // due to using map() to find bonded H atoms which are not near donor atom no_virial_fdotr_compute = 1; restartinfo = 0; nparams = maxparam = 0; params = NULL; nextra = 2; pvector = new double[2]; } /* ---------------------------------------------------------------------- */ PairHbondDreidingLJ::~PairHbondDreidingLJ() { memory->sfree(params); delete [] pvector; if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); delete [] donor; delete [] acceptor; memory->destroy(type2param); } } /* ---------------------------------------------------------------------- */ void PairHbondDreidingLJ::compute(int eflag, int vflag) { int i,j,k,m,ii,jj,kk,inum,jnum,knum,itype,jtype,ktype,iatom,imol; tagint tagprev; double delx,dely,delz,rsq,rsq1,rsq2,r1,r2; double factor_hb,force_angle,force_kernel,evdwl,eng_lj,ehbond,force_switch; double c,s,a,b,ac,a11,a12,a22,vx1,vx2,vy1,vy2,vz1,vz2,d; double fi[3],fj[3],delr1[3],delr2[3]; double r2inv,r10inv; double switch1,switch2; int *ilist,*jlist,*numneigh,**firstneigh; tagint *klist; evdwl = ehbond = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; double **x = atom->x; double **f = atom->f; tagint *tag = atom->tag; int *molindex = atom->molindex; int *molatom = atom->molatom; tagint **special = atom->special; int **nspecial = atom->nspecial; int *type = atom->type; double *special_lj = force->special_lj; int molecular = atom->molecular; Molecule **onemols = atom->avec->onemols; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // ii = loop over donors // jj = loop over acceptors // kk = loop over hydrogens bonded to donor int hbcount = 0; for (ii = 0; ii < inum; ii++) { i = ilist[ii]; itype = type[i]; if (!donor[itype]) continue; if (molecular == 1) { klist = special[i]; knum = nspecial[i][0]; } else { if (molindex[i] < 0) continue; imol = molindex[i]; iatom = molatom[i]; klist = onemols[imol]->special[iatom]; knum = onemols[imol]->nspecial[iatom][0]; tagprev = tag[i] - iatom - 1; } jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; factor_hb = special_lj[sbmask(j)]; j &= NEIGHMASK; jtype = type[j]; if (!acceptor[jtype]) continue; delx = x[i][0] - x[j][0]; dely = x[i][1] - x[j][1]; delz = x[i][2] - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; for (kk = 0; kk < knum; kk++) { if (molecular == 1) k = atom->map(klist[kk]); else k = atom->map(klist[kk]+tagprev); if (k < 0) continue; ktype = type[k]; m = type2param[itype][jtype][ktype]; if (m < 0) continue; const Param &pm = params[m]; if (rsq < pm.cut_outersq) { delr1[0] = x[i][0] - x[k][0]; delr1[1] = x[i][1] - x[k][1]; delr1[2] = x[i][2] - x[k][2]; domain->minimum_image(delr1); rsq1 = delr1[0]*delr1[0] + delr1[1]*delr1[1] + delr1[2]*delr1[2]; r1 = sqrt(rsq1); delr2[0] = x[j][0] - x[k][0]; delr2[1] = x[j][1] - x[k][1]; delr2[2] = x[j][2] - x[k][2]; domain->minimum_image(delr2); rsq2 = delr2[0]*delr2[0] + delr2[1]*delr2[1] + delr2[2]*delr2[2]; r2 = sqrt(rsq2); // angle (cos and sin) c = delr1[0]*delr2[0] + delr1[1]*delr2[1] + delr1[2]*delr2[2]; c /= r1*r2; if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; ac = acos(c); if (ac > pm.cut_angle && ac < (2.0*MY_PI - pm.cut_angle)) { s = sqrt(1.0 - c*c); if (s < SMALL) s = SMALL; // LJ-specific kernel r2inv = 1.0/rsq; r10inv = r2inv*r2inv*r2inv*r2inv*r2inv; force_kernel = r10inv*(pm.lj1*r2inv - pm.lj2)*r2inv * powint(c,pm.ap); force_angle = pm.ap * r10inv*(pm.lj3*r2inv - pm.lj4) * powint(c,pm.ap-1)*s; eng_lj = r10inv*(pm.lj3*r2inv - pm.lj4); force_switch=0.0; if (rsq > pm.cut_innersq) { switch1 = (pm.cut_outersq-rsq) * (pm.cut_outersq-rsq) * (pm.cut_outersq + 2.0*rsq - 3.0*pm.cut_innersq) / pm.denom_vdw; switch2 = 12.0*rsq * (pm.cut_outersq-rsq) * (rsq-pm.cut_innersq) / pm.denom_vdw; force_kernel *= switch1; force_angle *= switch1; force_switch = eng_lj*switch2/rsq; eng_lj *= switch1; } if (eflag) { evdwl = eng_lj * powint(c,pm.ap); evdwl *= factor_hb; ehbond += evdwl; } a = factor_hb*force_angle/s; b = factor_hb*force_kernel; d = factor_hb*force_switch; a11 = a*c / rsq1; a12 = -a / (r1*r2); a22 = a*c / rsq2; vx1 = a11*delr1[0] + a12*delr2[0]; vx2 = a22*delr2[0] + a12*delr1[0]; vy1 = a11*delr1[1] + a12*delr2[1]; vy2 = a22*delr2[1] + a12*delr1[1]; vz1 = a11*delr1[2] + a12*delr2[2]; vz2 = a22*delr2[2] + a12*delr1[2]; fi[0] = vx1 + b*delx + d*delx; fi[1] = vy1 + b*dely + d*dely; fi[2] = vz1 + b*delz + d*delz; fj[0] = vx2 - b*delx - d*delx; fj[1] = vy2 - b*dely - d*dely; fj[2] = vz2 - b*delz - d*delz; f[i][0] += fi[0]; f[i][1] += fi[1]; f[i][2] += fi[2]; f[j][0] += fj[0]; f[j][1] += fj[1]; f[j][2] += fj[2]; f[k][0] -= vx1 + vx2; f[k][1] -= vy1 + vy2; f[k][2] -= vz1 + vz2; // KIJ instead of IJK b/c delr1/delr2 are both with respect to k if (evflag) ev_tally3(k,i,j,evdwl,0.0,fi,fj,delr1,delr2); hbcount++; } } } } } if (eflag_global) { pvector[0] = hbcount; pvector[1] = ehbond; } } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairHbondDreidingLJ::allocate() { allocated = 1; int n = atom->ntypes; // mark all setflag as set, since don't require pair_coeff of all I,J 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] = 1; memory->create(cutsq,n+1,n+1,"pair:cutsq"); donor = new int[n+1]; acceptor = new int[n+1]; memory->create(type2param,n+1,n+1,n+1,"pair:type2param"); int i,j,k; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) for (k = 1; k <= n; k++) type2param[i][j][k] = -1; } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairHbondDreidingLJ::settings(int narg, char **arg) { if (narg != 4) error->all(FLERR,"Illegal pair_style command"); ap_global = force->inumeric(FLERR,arg[0]); cut_inner_global = force->numeric(FLERR,arg[1]); cut_outer_global = force->numeric(FLERR,arg[2]); cut_angle_global = force->numeric(FLERR,arg[3]) * MY_PI/180.0; } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairHbondDreidingLJ::coeff(int narg, char **arg) { if (narg < 6 || narg > 10) error->all(FLERR,"Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi,klo,khi; - force->bounds(arg[0],atom->ntypes,ilo,ihi); - force->bounds(arg[1],atom->ntypes,jlo,jhi); - force->bounds(arg[2],atom->ntypes,klo,khi); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); + force->bounds(FLERR,arg[2],atom->ntypes,klo,khi); int donor_flag; if (strcmp(arg[3],"i") == 0) donor_flag = 0; else if (strcmp(arg[3],"j") == 0) donor_flag = 1; else error->all(FLERR,"Incorrect args for pair coefficients"); double epsilon_one = force->numeric(FLERR,arg[4]); double sigma_one = force->numeric(FLERR,arg[5]); int ap_one = ap_global; if (narg > 6) ap_one = force->inumeric(FLERR,arg[6]); double cut_inner_one = cut_inner_global; double cut_outer_one = cut_outer_global; if (narg > 8) { cut_inner_one = force->numeric(FLERR,arg[7]); cut_outer_one = force->numeric(FLERR,arg[8]); } if (cut_inner_one>cut_outer_one) error->all(FLERR,"Pair inner cutoff >= Pair outer cutoff"); double cut_angle_one = cut_angle_global; if (narg == 10) cut_angle_one = force->numeric(FLERR,arg[9]) * MY_PI/180.0; // grow params array if necessary if (nparams == maxparam) { maxparam += CHUNK; params = (Param *) memory->srealloc(params,maxparam*sizeof(Param), "pair:params"); } params[nparams].epsilon = epsilon_one; params[nparams].sigma = sigma_one; params[nparams].ap = ap_one; params[nparams].cut_inner = cut_inner_one; params[nparams].cut_outer = cut_outer_one; params[nparams].cut_innersq = cut_inner_one*cut_inner_one; params[nparams].cut_outersq = cut_outer_one*cut_outer_one; params[nparams].cut_angle = cut_angle_one; params[nparams].denom_vdw = (params[nparams].cut_outersq-params[nparams].cut_innersq) * (params[nparams].cut_outersq-params[nparams].cut_innersq) * (params[nparams].cut_outersq-params[nparams].cut_innersq); // flag type2param with either i,j = D,A or j,i = D,A int count = 0; for (int i = ilo; i <= ihi; i++) for (int j = MAX(jlo,i); j <= jhi; j++) for (int k = klo; k <= khi; k++) { if (donor_flag == 0) type2param[i][j][k] = nparams; else type2param[j][i][k] = nparams; count++; } nparams++; if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairHbondDreidingLJ::init_style() { // molecular system required to use special list to find H atoms // tags required to use special list // pair newton on required since are looping over D atoms // and computing forces on A,H which may be on different procs if (atom->molecular == 0) error->all(FLERR,"Pair style hbond/dreiding requires molecular system"); if (atom->tag_enable == 0) error->all(FLERR,"Pair style hbond/dreiding requires atom IDs"); if (atom->map_style == 0) error->all(FLERR,"Pair style hbond/dreiding requires an atom map, " "see atom_modify"); if (force->newton_pair == 0) error->all(FLERR,"Pair style hbond/dreiding requires newton pair on"); // set donor[M]/acceptor[M] if any atom of type M is a donor/acceptor int anyflag = 0; int n = atom->ntypes; for (int m = 1; m <= n; m++) donor[m] = acceptor[m] = 0; for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) for (int k = 1; k <= n; k++) if (type2param[i][j][k] >= 0) { anyflag = 1; donor[i] = 1; acceptor[j] = 1; } if (!anyflag) error->all(FLERR,"No pair hbond/dreiding coefficients set"); // set additional param values // offset is for LJ only, angle term is not included for (int m = 0; m < nparams; m++) { params[m].lj1 = 60.0*params[m].epsilon*pow(params[m].sigma,12.0); params[m].lj2 = 60.0*params[m].epsilon*pow(params[m].sigma,10.0); params[m].lj3 = 5.0*params[m].epsilon*pow(params[m].sigma,12.0); params[m].lj4 = 6.0*params[m].epsilon*pow(params[m].sigma,10.0); /* if (offset_flag) { double ratio = params[m].sigma / params[m].cut_outer; params[m].offset = params[m].epsilon * ((2.0*pow(ratio,9.0)) - (3.0*pow(ratio,6.0))); } else params[m].offset = 0.0; */ } // full neighbor list request int irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->full = 1; } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairHbondDreidingLJ::init_one(int i, int j) { int m; // return maximum cutoff for any K with I,J = D,A or J,I = D,A // donor/acceptor is not symmetric, IJ interaction != JI interaction double cut = 0.0; for (int k = 1; k <= atom->ntypes; k++) { m = type2param[i][j][k]; if (m >= 0) cut = MAX(cut,params[m].cut_outer); m = type2param[j][i][k]; if (m >= 0) cut = MAX(cut,params[m].cut_outer); } return cut; } /* ---------------------------------------------------------------------- */ double PairHbondDreidingLJ::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { int k,kk,ktype,knum,m; tagint tagprev; double eng,eng_lj,force_kernel,force_angle; double rsq1,rsq2,r1,r2,c,s,ac,r2inv,r10inv,factor_hb; double switch1,switch2; double delr1[3],delr2[3]; tagint *klist; double **x = atom->x; int *type = atom->type; double *special_lj = force->special_lj; eng = 0.0; fforce = 0; // sanity check if (!donor[itype]) return 0.0; if (!acceptor[jtype]) return 0.0; int molecular = atom->molecular; if (molecular == 1) { klist = atom->special[i]; knum = atom->nspecial[i][0]; } else { if (atom->molindex[i] < 0) return 0.0; int imol = atom->molindex[i]; int iatom = atom->molatom[i]; Molecule **onemols = atom->avec->onemols; klist = onemols[imol]->special[iatom]; knum = onemols[imol]->nspecial[iatom][0]; tagprev = atom->tag[i] - iatom - 1; } factor_hb = special_lj[sbmask(j)]; for (kk = 0; kk < knum; kk++) { if (molecular == 1) k = atom->map(klist[kk]); else k = atom->map(klist[kk]+tagprev); if (k < 0) continue; ktype = type[k]; m = type2param[itype][jtype][ktype]; if (m < 0) continue; const Param &pm = params[m]; delr1[0] = x[i][0] - x[k][0]; delr1[1] = x[i][1] - x[k][1]; delr1[2] = x[i][2] - x[k][2]; domain->minimum_image(delr1); rsq1 = delr1[0]*delr1[0] + delr1[1]*delr1[1] + delr1[2]*delr1[2]; r1 = sqrt(rsq1); delr2[0] = x[j][0] - x[k][0]; delr2[1] = x[j][1] - x[k][1]; delr2[2] = x[j][2] - x[k][2]; domain->minimum_image(delr2); rsq2 = delr2[0]*delr2[0] + delr2[1]*delr2[1] + delr2[2]*delr2[2]; r2 = sqrt(rsq2); // angle (cos and sin) c = delr1[0]*delr2[0] + delr1[1]*delr2[1] + delr1[2]*delr2[2]; c /= r1*r2; if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; ac = acos(c); if (ac < pm.cut_angle || ac > (2.0*MY_PI - pm.cut_angle)) return 0.0; s = sqrt(1.0 - c*c); if (s < SMALL) s = SMALL; // LJ-specific kernel r2inv = 1.0/rsq; r10inv = r2inv*r2inv*r2inv*r2inv*r2inv; force_kernel = r10inv*(pm.lj1*r2inv - pm.lj2)*r2inv * powint(c,pm.ap); force_angle = pm.ap * r10inv*(pm.lj3*r2inv - pm.lj4) * powint(c,pm.ap-1)*s; // only lj part for now eng_lj = r10inv*(pm.lj3*r2inv - pm.lj4); if (rsq > pm.cut_innersq) { switch1 = (pm.cut_outersq-rsq) * (pm.cut_outersq-rsq) * (pm.cut_outersq + 2.0*rsq - 3.0*pm.cut_innersq) / pm.denom_vdw; switch2 = 12.0*rsq * (pm.cut_outersq-rsq) * (rsq-pm.cut_innersq) / pm.denom_vdw; force_kernel = force_kernel*switch1 + eng_lj*switch2; eng_lj *= switch1; } fforce += force_kernel*powint(c,pm.ap) + eng_lj*force_angle; eng += eng_lj * powint(c,pm.ap) * factor_hb; } return eng; } diff --git a/src/MOLECULE/pair_hbond_dreiding_morse.cpp b/src/MOLECULE/pair_hbond_dreiding_morse.cpp index ab793405d..5c61ea4a4 100644 --- a/src/MOLECULE/pair_hbond_dreiding_morse.cpp +++ b/src/MOLECULE/pair_hbond_dreiding_morse.cpp @@ -1,473 +1,473 @@ /* ---------------------------------------------------------------------- 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: Tod A Pascal (Caltech) ------------------------------------------------------------------------- */ #include #include #include #include #include "pair_hbond_dreiding_morse.h" #include "atom.h" #include "atom_vec.h" #include "molecule.h" #include "comm.h" #include "force.h" #include "neighbor.h" #include "neigh_request.h" #include "neigh_list.h" #include "domain.h" #include "math_const.h" #include "math_special.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace MathConst; using namespace MathSpecial; #define SMALL 0.001 #define CHUNK 8 /* ---------------------------------------------------------------------- */ PairHbondDreidingMorse::PairHbondDreidingMorse(LAMMPS *lmp) : PairHbondDreidingLJ(lmp) {} /* ---------------------------------------------------------------------- */ void PairHbondDreidingMorse::compute(int eflag, int vflag) { int i,j,k,m,ii,jj,kk,inum,jnum,knum,itype,jtype,ktype,imol,iatom; tagint tagprev; double delx,dely,delz,rsq,rsq1,rsq2,r1,r2; double factor_hb,force_angle,force_kernel,force_switch,evdwl,ehbond; double c,s,a,b,d,ac,a11,a12,a22,vx1,vx2,vy1,vy2,vz1,vz2; double fi[3],fj[3],delr1[3],delr2[3]; double r,dr,dexp,eng_morse,switch1,switch2; int *ilist,*jlist,*numneigh,**firstneigh; tagint *klist; evdwl = ehbond = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; double **x = atom->x; double **f = atom->f; tagint *tag = atom->tag; int *molindex = atom->molindex; int *molatom = atom->molatom; tagint **special = atom->special; int **nspecial = atom->nspecial; int *type = atom->type; double *special_lj = force->special_lj; int molecular = atom->molecular; Molecule **onemols = atom->avec->onemols; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // ii = loop over donors // jj = loop over acceptors // kk = loop over hydrogens bonded to donor int hbcount = 0; for (ii = 0; ii < inum; ii++) { i = ilist[ii]; itype = type[i]; if (!donor[itype]) continue; if (molecular == 1) { klist = special[i]; knum = nspecial[i][0]; } else { if (molindex[i] < 0) continue; imol = molindex[i]; iatom = molatom[i]; klist = onemols[imol]->special[iatom]; knum = onemols[imol]->nspecial[iatom][0]; tagprev = tag[i] - iatom - 1; } jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; factor_hb = special_lj[sbmask(j)]; j &= NEIGHMASK; jtype = type[j]; if (!acceptor[jtype]) continue; delx = x[i][0] - x[j][0]; dely = x[i][1] - x[j][1]; delz = x[i][2] - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; for (kk = 0; kk < knum; kk++) { if (molecular == 1) k = atom->map(klist[kk]); else k = atom->map(klist[kk]+tagprev); if (k < 0) continue; ktype = type[k]; m = type2param[itype][jtype][ktype]; if (m < 0) continue; const Param &pm = params[m]; if (rsq < pm.cut_outersq) { delr1[0] = x[i][0] - x[k][0]; delr1[1] = x[i][1] - x[k][1]; delr1[2] = x[i][2] - x[k][2]; domain->minimum_image(delr1); rsq1 = delr1[0]*delr1[0] + delr1[1]*delr1[1] + delr1[2]*delr1[2]; r1 = sqrt(rsq1); delr2[0] = x[j][0] - x[k][0]; delr2[1] = x[j][1] - x[k][1]; delr2[2] = x[j][2] - x[k][2]; domain->minimum_image(delr2); rsq2 = delr2[0]*delr2[0] + delr2[1]*delr2[1] + delr2[2]*delr2[2]; r2 = sqrt(rsq2); // angle (cos and sin) c = delr1[0]*delr2[0] + delr1[1]*delr2[1] + delr1[2]*delr2[2]; c /= r1*r2; if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; ac = acos(c); if (ac > pm.cut_angle && ac < (2.0*MY_PI - pm.cut_angle)) { s = sqrt(1.0 - c*c); if (s < SMALL) s = SMALL; // Morse-specific kernel r = sqrt(rsq); dr = r - pm.r0; dexp = exp(-pm.alpha * dr); eng_morse = pm.d0 * (dexp*dexp - 2.0*dexp); force_kernel = pm.morse1*(dexp*dexp - dexp)/r * powint(c,pm.ap); force_angle = pm.ap * eng_morse * powint(c,pm.ap-1)*s; force_switch = 0.0; if (rsq > pm.cut_innersq) { switch1 = (pm.cut_outersq-rsq) * (pm.cut_outersq-rsq) * (pm.cut_outersq + 2.0*rsq - 3.0*pm.cut_innersq) / pm.denom_vdw; switch2 = 12.0*rsq * (pm.cut_outersq-rsq) * (rsq-pm.cut_innersq) / pm.denom_vdw; force_kernel *= switch1; force_angle *= switch1; force_switch = eng_morse*switch2/rsq; eng_morse *= switch1; } if (eflag) { evdwl = eng_morse * powint(c,pm.ap); evdwl *= factor_hb; ehbond += evdwl; } a = factor_hb*force_angle/s; b = factor_hb*force_kernel; d = factor_hb*force_switch; a11 = a*c / rsq1; a12 = -a / (r1*r2); a22 = a*c / rsq2; vx1 = a11*delr1[0] + a12*delr2[0]; vx2 = a22*delr2[0] + a12*delr1[0]; vy1 = a11*delr1[1] + a12*delr2[1]; vy2 = a22*delr2[1] + a12*delr1[1]; vz1 = a11*delr1[2] + a12*delr2[2]; vz2 = a22*delr2[2] + a12*delr1[2]; fi[0] = vx1 + (b+d)*delx; fi[1] = vy1 + (b+d)*dely; fi[2] = vz1 + (b+d)*delz; fj[0] = vx2 - (b+d)*delx; fj[1] = vy2 - (b+d)*dely; fj[2] = vz2 - (b+d)*delz; f[i][0] += fi[0]; f[i][1] += fi[1]; f[i][2] += fi[2]; f[j][0] += fj[0]; f[j][1] += fj[1]; f[j][2] += fj[2]; f[k][0] -= vx1 + vx2; f[k][1] -= vy1 + vy2; f[k][2] -= vz1 + vz2; // KIJ instead of IJK b/c delr1/delr2 are both with respect to k if (evflag) ev_tally3(k,i,j,evdwl,0.0,fi,fj,delr1,delr2); hbcount++; } } } } } if (eflag_global) { pvector[0] = hbcount; pvector[1] = ehbond; } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairHbondDreidingMorse::coeff(int narg, char **arg) { if (narg < 7 || narg > 11) error->all(FLERR,"Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi,klo,khi; - force->bounds(arg[0],atom->ntypes,ilo,ihi); - force->bounds(arg[1],atom->ntypes,jlo,jhi); - force->bounds(arg[2],atom->ntypes,klo,khi); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); + force->bounds(FLERR,arg[2],atom->ntypes,klo,khi); int donor_flag; if (strcmp(arg[3],"i") == 0) donor_flag = 0; else if (strcmp(arg[3],"j") == 0) donor_flag = 1; else error->all(FLERR,"Incorrect args for pair coefficients"); double d0_one = force->numeric(FLERR,arg[4]); double alpha_one = force->numeric(FLERR,arg[5]); double r0_one = force->numeric(FLERR,arg[6]); int ap_one = ap_global; if (narg > 7) ap_one = force->inumeric(FLERR,arg[7]); double cut_inner_one = cut_inner_global; double cut_outer_one = cut_outer_global; if (narg > 9) { cut_inner_one = force->numeric(FLERR,arg[8]); cut_outer_one = force->numeric(FLERR,arg[9]); } if (cut_inner_one>cut_outer_one) error->all(FLERR,"Pair inner cutoff >= Pair outer cutoff"); double cut_angle_one = cut_angle_global; if (narg > 10) cut_angle_one = force->numeric(FLERR,arg[10]) * MY_PI/180.0; // grow params array if necessary if (nparams == maxparam) { maxparam += CHUNK; params = (Param *) memory->srealloc(params,maxparam*sizeof(Param), "pair:params"); } params[nparams].d0 = d0_one; params[nparams].alpha = alpha_one; params[nparams].r0 = r0_one; params[nparams].ap = ap_one; params[nparams].cut_inner = cut_inner_one; params[nparams].cut_outer = cut_outer_one; params[nparams].cut_innersq = cut_inner_one*cut_inner_one; params[nparams].cut_outersq = cut_outer_one*cut_outer_one; params[nparams].cut_angle = cut_angle_one; params[nparams].denom_vdw = (params[nparams].cut_outersq-params[nparams].cut_innersq) * (params[nparams].cut_outersq-params[nparams].cut_innersq) * (params[nparams].cut_outersq-params[nparams].cut_innersq); // flag type2param with either i,j = D,A or j,i = D,A int count = 0; for (int i = ilo; i <= ihi; i++) for (int j = MAX(jlo,i); j <= jhi; j++) for (int k = klo; k <= khi; k++) { if (donor_flag == 0) type2param[i][j][k] = nparams; else type2param[j][i][k] = nparams; count++; } nparams++; if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairHbondDreidingMorse::init_style() { // molecular system required to use special list to find H atoms // tags required to use special list // pair newton on required since are looping over D atoms // and computing forces on A,H which may be on different procs if (atom->molecular == 0) error->all(FLERR,"Pair style hbond/dreiding requires molecular system"); if (atom->tag_enable == 0) error->all(FLERR,"Pair style hbond/dreiding requires atom IDs"); if (atom->map_style == 0) error->all(FLERR,"Pair style hbond/dreiding requires an atom map, " "see atom_modify"); if (force->newton_pair == 0) error->all(FLERR,"Pair style hbond/dreiding requires newton pair on"); // set donor[M]/acceptor[M] if any atom of type M is a donor/acceptor int anyflag = 0; int n = atom->ntypes; for (int m = 1; m <= n; m++) donor[m] = acceptor[m] = 0; for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) for (int k = 1; k <= n; k++) if (type2param[i][j][k] >= 0) { anyflag = 1; donor[i] = 1; acceptor[j] = 1; } if (!anyflag) error->all(FLERR,"No pair hbond/dreiding coefficients set"); // set additional param values // offset is for Morse only, angle term is not included for (int m = 0; m < nparams; m++) { params[m].morse1 = 2.0*params[m].d0*params[m].alpha; /* if (offset_flag) { double alpha_dr = -params[m].alpha * (params[m].cut - params[m].r0); params[m].offset = params[m].d0 * ((exp(2.0*alpha_dr)) - (2.0*exp(alpha_dr))); } else params[m].offset = 0.0; */ } // full neighbor list request int irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->full = 1; } /* ---------------------------------------------------------------------- */ double PairHbondDreidingMorse::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { int k,kk,ktype,knum,m; tagint tagprev; double eng,eng_morse,force_kernel,force_angle; double rsq1,rsq2,r1,r2,c,s,ac,r,dr,dexp,factor_hb; double switch1,switch2; double delr1[3],delr2[3]; tagint *klist; double **x = atom->x; int *type = atom->type; double *special_lj = force->special_lj; eng = 0.0; fforce = 0; //sanity check if (!donor[itype]) return 0.0; if (!acceptor[jtype]) return 0.0; int molecular = atom->molecular; if (molecular == 1) { klist = atom->special[i]; knum = atom->nspecial[i][0]; } else { if (atom->molindex[i] < 0) return 0.0; int imol = atom->molindex[i]; int iatom = atom->molatom[i]; Molecule **onemols = atom->avec->onemols; klist = onemols[imol]->special[iatom]; knum = onemols[imol]->nspecial[iatom][0]; tagprev = atom->tag[i] - iatom - 1; } factor_hb = special_lj[sbmask(j)]; for (kk = 0; kk < knum; kk++) { if (molecular == 1) k = atom->map(klist[kk]); else k = atom->map(klist[kk]+tagprev); if (k < 0) continue; ktype = type[k]; m = type2param[itype][jtype][ktype]; if (m < 0) continue; const Param &pm = params[m]; delr1[0] = x[i][0] - x[k][0]; delr1[1] = x[i][1] - x[k][1]; delr1[2] = x[i][2] - x[k][2]; domain->minimum_image(delr1); rsq1 = delr1[0]*delr1[0] + delr1[1]*delr1[1] + delr1[2]*delr1[2]; r1 = sqrt(rsq1); delr2[0] = x[j][0] - x[k][0]; delr2[1] = x[j][1] - x[k][1]; delr2[2] = x[j][2] - x[k][2]; domain->minimum_image(delr2); rsq2 = delr2[0]*delr2[0] + delr2[1]*delr2[1] + delr2[2]*delr2[2]; r2 = sqrt(rsq2); // angle (cos and sin) c = delr1[0]*delr2[0] + delr1[1]*delr2[1] + delr1[2]*delr2[2]; c /= r1*r2; if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; ac = acos(c); if (ac < pm.cut_angle || ac > (2.0*MY_PI - pm.cut_angle)) return 0.0; s = sqrt(1.0 - c*c); if (s < SMALL) s = SMALL; // Morse-specific kernel r = sqrt(rsq); dr = r - pm.r0; dexp = exp(-pm.alpha * dr); eng_morse = pm.d0 * (dexp*dexp - 2.0*dexp); //<-- BUGFIX 2012-11-14 force_kernel = pm.morse1*(dexp*dexp - dexp)/r * powint(c,pm.ap); force_angle = pm.ap * eng_morse * powint(c,pm.ap-1)*s; if (rsq > pm.cut_innersq) { switch1 = (pm.cut_outersq-rsq) * (pm.cut_outersq-rsq) * (pm.cut_outersq + 2.0*rsq - 3.0*pm.cut_innersq) / pm.denom_vdw; switch2 = 12.0*rsq * (pm.cut_outersq-rsq) * (rsq-pm.cut_innersq) / pm.denom_vdw; force_kernel = force_kernel*switch1 + eng_morse*switch2; eng_morse *= switch1; } eng += eng_morse * powint(c,pm.ap)* factor_hb; fforce += force_kernel*powint(c,pm.ap) + eng_morse*force_angle; } return eng; } diff --git a/src/MOLECULE/pair_lj_charmm_coul_charmm.cpp b/src/MOLECULE/pair_lj_charmm_coul_charmm.cpp index f12bc8f3b..3700de00b 100644 --- a/src/MOLECULE/pair_lj_charmm_coul_charmm.cpp +++ b/src/MOLECULE/pair_lj_charmm_coul_charmm.cpp @@ -1,528 +1,528 @@ /* ---------------------------------------------------------------------- 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 #include #include #include #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; /* ---------------------------------------------------------------------- */ PairLJCharmmCoulCharmm::PairLJCharmmCoulCharmm(LAMMPS *lmp) : Pair(lmp) { implicit = 0; mix_flag = ARITHMETIC; writedata = 1; } /* ---------------------------------------------------------------------- */ PairLJCharmmCoulCharmm::~PairLJCharmmCoulCharmm() { if (!copymode) { 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; jtype = type[j]; 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; forcecoul *= switch1; } } 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; 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(FLERR,arg[0]); cut_lj = force->numeric(FLERR,arg[1]); if (narg == 2) { cut_coul_inner = cut_lj_inner; cut_coul = cut_lj; } else { cut_coul_inner = force->numeric(FLERR,arg[2]); cut_coul = force->numeric(FLERR,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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(FLERR,arg[2]); double sigma_one = force->numeric(FLERR,arg[3]); double eps14_one = epsilon_one; double sigma14_one = sigma_one; if (narg == 6) { eps14_one = force->numeric(FLERR,arg[4]); sigma14_one = force->numeric(FLERR,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,instance_me); // 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 data file ------------------------------------------------------------------------- */ void PairLJCharmmCoulCharmm::write_data(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) fprintf(fp,"%d %g %g %g %g\n", i,epsilon[i][i],sigma[i][i],eps14[i][i],sigma14[i][i]); } /* ---------------------------------------------------------------------- proc 0 writes all pairs to data file ------------------------------------------------------------------------- */ void PairLJCharmmCoulCharmm::write_data_all(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) fprintf(fp,"%d %d %g %g %g %g\n",i,j, epsilon[i][j],sigma[i][j],eps14[i][j],sigma14[i][j]); } /* ---------------------------------------------------------------------- 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; forcecoul *= switch1; } } 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(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_cut_tip4p_cut.cpp b/src/MOLECULE/pair_lj_cut_tip4p_cut.cpp index 0f5a1f68d..a9e00e80b 100644 --- a/src/MOLECULE/pair_lj_cut_tip4p_cut.cpp +++ b/src/MOLECULE/pair_lj_cut_tip4p_cut.cpp @@ -1,747 +1,747 @@ /* ---------------------------------------------------------------------- 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: Pavel Elkind (Gothenburg University) ------------------------------------------------------------------------- */ #include #include #include #include "pair_lj_cut_tip4p_cut.h" #include "atom.h" #include "force.h" #include "neighbor.h" #include "neigh_list.h" #include "domain.h" #include "angle.h" #include "bond.h" #include "comm.h" #include "math_const.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace MathConst; /* ---------------------------------------------------------------------- */ PairLJCutTIP4PCut::PairLJCutTIP4PCut(LAMMPS *lmp) : Pair(lmp) { single_enable = 0; writedata = 1; nmax = 0; hneigh = NULL; newsite = NULL; // TIP4P cannot compute virial as F dot r // due to finding bonded H atoms which are not near O atom no_virial_fdotr_compute = 1; } /* ---------------------------------------------------------------------- */ PairLJCutTIP4PCut::~PairLJCutTIP4PCut() { 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); } memory->destroy(hneigh); memory->destroy(newsite); } /* ---------------------------------------------------------------------- */ void PairLJCutTIP4PCut::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul; double rsq,r2inv,r6inv,forcecoul,forcelj,factor_lj,factor_coul; int *ilist,*jlist,*numneigh,**firstneigh; int key; int n,vlist[6]; int iH1,iH2,jH1,jH2; double cforce; double fO[3],fH[3],fd[3],v[6],xH1[3],xH2[3]; double *x1,*x2; evdwl = ecoul = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; // reallocate hneigh & newsite if necessary // initialize hneigh[0] to -1 on steps when reneighboring occurred // initialize hneigh[2] to 0 every step int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; if (atom->nmax > nmax) { nmax = atom->nmax; memory->destroy(hneigh); memory->create(hneigh,nmax,3,"pair:hneigh"); memory->destroy(newsite); memory->create(newsite,nmax,3,"pair:newsite"); } if (neighbor->ago == 0) for (i = 0; i < nall; i++) hneigh[i][0] = -1; for (i = 0; i < nall; i++) hneigh[i][2] = 0; double **f = atom->f; double **x = atom->x; double *q = atom->q; tagint *tag = atom->tag; int *type = atom->type; double *special_lj = force->special_lj; 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]; if (itype == typeO) { if (hneigh[i][0] < 0) { hneigh[i][0] = iH1 = atom->map(tag[i] + 1); hneigh[i][1] = iH2 = atom->map(tag[i] + 2); hneigh[i][2] = 1; 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"); compute_newsite(x[i],x[iH1],x[iH2],newsite[i]); } else { iH1 = hneigh[i][0]; iH2 = hneigh[i][1]; if (hneigh[i][2] == 0) { hneigh[i][2] = 1; compute_newsite(x[i],x[iH1],x[iH2],newsite[i]); } } x1 = newsite[i]; } 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]; // LJ interaction based on true rsq if (rsq < cut_ljsq[itype][jtype]) { r2inv = 1.0/rsq; 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 necessary // but only if they are within reach if (rsq < cut_coulsqplus) { if (itype == typeO || jtype == typeO) { // if atom J = water O, set x2 = offset charge site // else x2 = x of atom J if (jtype == typeO) { if (hneigh[j][0] < 0) { hneigh[j][0] = jH1 = atom->map(tag[j] + 1); hneigh[j][1] = jH2 = atom->map(tag[j] + 2); hneigh[j][2] = 1; if (jH1 == -1 || jH2 == -1) error->one(FLERR,"TIP4P hydrogen is missing"); if (atom->type[jH1] != typeH || atom->type[jH2] != typeH) error->one(FLERR,"TIP4P hydrogen has incorrect atom type"); compute_newsite(x[j],x[jH1],x[jH2],newsite[j]); } else { jH1 = hneigh[j][0]; jH2 = hneigh[j][1]; if (hneigh[j][2] == 0) { hneigh[j][2] = 1; compute_newsite(x[j],x[jH1],x[jH2],newsite[j]); } } x2 = newsite[j]; } 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; } // Coulombic interaction based on modified rsq if (rsq < cut_coulsq) { r2inv = 1.0 / rsq; forcecoul = qqrd2e * qtmp * q[j] * sqrt(r2inv); cforce = factor_coul * 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; key = 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 { key++; fd[0] = delx*cforce; fd[1] = dely*cforce; fd[2] = delz*cforce; fO[0] = fd[0]*(1.0 - alpha); fO[1] = fd[1]*(1.0 - alpha); fO[2] = fd[2]*(1.0 - alpha); fH[0] = 0.5 * alpha * fd[0]; fH[1] = 0.5 * alpha * fd[1]; fH[2] = 0.5 * alpha * fd[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 { key += 2; fd[0] = -delx*cforce; fd[1] = -dely*cforce; fd[2] = -delz*cforce; fO[0] = fd[0]*(1 - alpha); fO[1] = fd[1]*(1 - alpha); fO[2] = fd[2]*(1 - alpha); fH[0] = 0.5 * alpha * fd[0]; fH[1] = 0.5 * alpha * fd[1]; fH[2] = 0.5 * alpha * fd[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) { ecoul = qqrd2e * qtmp * q[j] * sqrt(r2inv); ecoul *= factor_coul; } else ecoul = 0.0; if (evflag) ev_tally_tip4p(key,vlist,v,ecoul,alpha); } } } } } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairLJCutTIP4PCut::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 PairLJCutTIP4PCut::settings(int narg, char **arg) { if (narg < 6 || narg > 7) error->all(FLERR,"Illegal pair_style command"); typeO = force->inumeric(FLERR,arg[0]); typeH = force->inumeric(FLERR,arg[1]); typeB = force->inumeric(FLERR,arg[2]); typeA = force->inumeric(FLERR,arg[3]); qdist = force->numeric(FLERR,arg[4]); cut_lj_global = force->numeric(FLERR,arg[5]); if (narg == 6) cut_coul = cut_lj_global; else cut_coul = force->numeric(FLERR,arg[6]); cut_coulsq = cut_coul * cut_coul; cut_coulsqplus = (cut_coul + 2.0*qdist) * (cut_coul + 2.0*qdist); 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 PairLJCutTIP4PCut::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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(FLERR,arg[2]); double sigma_one = force->numeric(FLERR,arg[3]); double cut_lj_one = cut_lj_global; if (narg == 5) cut_lj_one = force->numeric(FLERR,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 PairLJCutTIP4PCut::init_style() { if (atom->tag_enable == 0) error->all(FLERR,"Pair style lj/cut/tip4p/cut requires atom IDs"); if (!force->newton_pair) error->all(FLERR, "Pair style lj/cut/tip4p/cut requires newton pair on"); if (!atom->q_flag) error->all(FLERR, "Pair style lj/cut/tip4p/cut requires atom attribute q"); 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"); neighbor->request(this,instance_me); // set alpha parameter double theta = force->angle->equilibrium_angle(typeA); double blen = force->bond->equilibrium_distance(typeB); alpha = qdist / (cos(0.5*theta) * blen); } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairLJCutTIP4PCut::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]); } // include TIP4P qdist in full cutoff, qdist = 0.0 if not TIP4P double cut = MAX(cut_lj[i][j],cut_coul+2.0*qdist); 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]; // 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); } // check that LJ epsilon = 0.0 for water H // set LJ cutoff to 0.0 for any interaction involving water H // so LJ term isn't calculated in compute() if ((i == typeH && epsilon[i][i] != 0.0) || (j == typeH && epsilon[j][j] != 0.0)) error->all(FLERR,"Water H epsilon must be 0.0 for " "pair style lj/cut/tip4p/cut"); if (i == typeH || j == typeH) cut_ljsq[j][i] = cut_ljsq[i][j] = 0.0; return cut; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJCutTIP4PCut::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 PairLJCutTIP4PCut::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 PairLJCutTIP4PCut::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); fwrite(&tail_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJCutTIP4PCut::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); fread(&tail_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); MPI_Bcast(&tail_flag,1,MPI_INT,0,world); cut_coulsq = cut_coul * cut_coul; cut_coulsqplus = (cut_coul + 2.0*qdist) * (cut_coul + 2.0*qdist); } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void PairLJCutTIP4PCut::write_data(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) fprintf(fp,"%d %g %g\n",i,epsilon[i][i],sigma[i][i]); } /* ---------------------------------------------------------------------- proc 0 writes all pairs to data file ------------------------------------------------------------------------- */ void PairLJCutTIP4PCut::write_data_all(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) fprintf(fp,"%d %d %g %g %g\n",i,j,epsilon[i][j],sigma[i][j],cut_lj[i][j]); } /* ---------------------------------------------------------------------- compute position xM of fictitious charge site for O atom and 2 H atoms return it as xM ------------------------------------------------------------------------- */ void PairLJCutTIP4PCut::compute_newsite(double *xO, double *xH1, double *xH2, double *xM) { double delx1 = xH1[0] - xO[0]; double dely1 = xH1[1] - xO[1]; double delz1 = xH1[2] - xO[2]; domain->minimum_image(delx1,dely1,delz1); double delx2 = xH2[0] - xO[0]; double dely2 = xH2[1] - xO[1]; double delz2 = xH2[2] - xO[2]; domain->minimum_image(delx2,dely2,delz2); xM[0] = xO[0] + alpha * 0.5 * (delx1 + delx2); xM[1] = xO[1] + alpha * 0.5 * (dely1 + dely2); xM[2] = xO[2] + alpha * 0.5 * (delz1 + delz2); } /* ---------------------------------------------------------------------- */ void *PairLJCutTIP4PCut::extract(const char *str, int &dim) { dim = 0; if (strcmp(str,"cut_coul") == 0) return (void *) &cut_coul; dim = 2; if (strcmp(str,"epsilon") == 0) return (void *) epsilon; if (strcmp(str,"sigma") == 0) return (void *) sigma; return NULL; } /* ---------------------------------------------------------------------- memory usage of hneigh ------------------------------------------------------------------------- */ double PairLJCutTIP4PCut::memory_usage() { double bytes = maxeatom * sizeof(double); bytes += maxvatom*6 * sizeof(double); bytes += 2 * nmax * sizeof(double); return bytes; } diff --git a/src/MOLECULE/pair_tip4p_cut.cpp b/src/MOLECULE/pair_tip4p_cut.cpp index 47aa77304..dd48637f2 100644 --- a/src/MOLECULE/pair_tip4p_cut.cpp +++ b/src/MOLECULE/pair_tip4p_cut.cpp @@ -1,551 +1,551 @@ /* ---------------------------------------------------------------------- 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: Pavel Elkind (Gothenburg University) ------------------------------------------------------------------------- */ #include #include #include "pair_tip4p_cut.h" #include "atom.h" #include "force.h" #include "neighbor.h" #include "neigh_list.h" #include "domain.h" #include "angle.h" #include "bond.h" #include "comm.h" #include "math_const.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace MathConst; /* ---------------------------------------------------------------------- */ PairTIP4PCut::PairTIP4PCut(LAMMPS *lmp) : Pair(lmp) { single_enable = 0; nmax = 0; hneigh = NULL; newsite = NULL; // TIP4P cannot compute virial as F dot r // due to finding bonded H atoms which are not near O atom no_virial_fdotr_compute = 1; } /* ---------------------------------------------------------------------- */ PairTIP4PCut::~PairTIP4PCut() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); } memory->destroy(hneigh); memory->destroy(newsite); } /* ---------------------------------------------------------------------- */ void PairTIP4PCut::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,ecoul; double rsq,r2inv,forcecoul,factor_coul; int *ilist,*jlist,*numneigh,**firstneigh; int key; int n,vlist[6]; int iH1,iH2,jH1,jH2; double cforce; double fO[3],fH[3],fd[3],v[6],xH1[3],xH2[3]; double *x1,*x2; ecoul = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; // reallocate hneigh & newsite if necessary // initialize hneigh[0] to -1 on steps when reneighboring occurred // initialize hneigh[2] to 0 every step int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; if (atom->nmax > nmax) { nmax = atom->nmax; memory->destroy(hneigh); memory->create(hneigh,nmax,3,"pair:hneigh"); memory->destroy(newsite); memory->create(newsite,nmax,3,"pair:newsite"); } if (neighbor->ago == 0) for (i = 0; i < nall; i++) hneigh[i][0] = -1; for (i = 0; i < nall; i++) hneigh[i][2] = 0; double **f = atom->f; double **x = atom->x; double *q = atom->q; tagint *tag = atom->tag; int *type = atom->type; double *special_coul = force->special_coul; 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) { if (hneigh[i][0] < 0) { hneigh[i][0] = iH1 = atom->map(tag[i] + 1); hneigh[i][1] = iH2 = atom->map(tag[i] + 2); hneigh[i][2] = 1; 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"); compute_newsite(x[i],x[iH1],x[iH2],newsite[i]); } else { iH1 = hneigh[i][0]; iH2 = hneigh[i][1]; if (hneigh[i][2] == 0) { hneigh[i][2] = 1; compute_newsite(x[i],x[iH1],x[iH2],newsite[i]); } } x1 = newsite[i]; } else x1 = x[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]; // adjust rsq and delxyz for off-site O charge(s) if necessary // but only if they are within reach if (rsq < cut_coulsqplus) { if (itype == typeO || jtype == typeO) { // if atom J = water O, set x2 = offset charge site // else x2 = x of atom J if (jtype == typeO) { if (hneigh[j][0] < 0) { hneigh[j][0] = jH1 = atom->map(tag[j] + 1); hneigh[j][1] = jH2 = atom->map(tag[j] + 2); hneigh[j][2] = 1; if (jH1 == -1 || jH2 == -1) error->one(FLERR,"TIP4P hydrogen is missing"); if (atom->type[jH1] != typeH || atom->type[jH2] != typeH) error->one(FLERR,"TIP4P hydrogen has incorrect atom type"); compute_newsite(x[j],x[jH1],x[jH2],newsite[j]); } else { jH1 = hneigh[j][0]; jH2 = hneigh[j][1]; if (hneigh[j][2] == 0) { hneigh[j][2] = 1; compute_newsite(x[j],x[jH1],x[jH2],newsite[j]); } } x2 = newsite[j]; } 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; } // Coulombic interaction based on modified rsq if (rsq < cut_coulsq) { r2inv = 1.0 / rsq; forcecoul = qqrd2e * qtmp * q[j] * sqrt(r2inv); cforce = factor_coul * 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; key = 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 { key++; fd[0] = delx*cforce; fd[1] = dely*cforce; fd[2] = delz*cforce; fO[0] = fd[0]*(1.0 - alpha); fO[1] = fd[1]*(1.0 - alpha); fO[2] = fd[2]*(1.0 - alpha); fH[0] = 0.5 * alpha * fd[0]; fH[1] = 0.5 * alpha * fd[1]; fH[2] = 0.5 * alpha * fd[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 { key += 2; fd[0] = -delx*cforce; fd[1] = -dely*cforce; fd[2] = -delz*cforce; fO[0] = fd[0]*(1 - alpha); fO[1] = fd[1]*(1 - alpha); fO[2] = fd[2]*(1 - alpha); fH[0] = 0.5 * alpha * fd[0]; fH[1] = 0.5 * alpha * fd[1]; fH[2] = 0.5 * alpha * fd[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) { ecoul = qqrd2e * qtmp * q[j] * sqrt(r2inv); ecoul *= factor_coul; } else ecoul = 0.0; if (evflag) ev_tally_tip4p(key,vlist,v,ecoul,alpha); } } } } } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairTIP4PCut::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"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairTIP4PCut::settings(int narg, char **arg) { if (narg != 6) error->all(FLERR,"Illegal pair_style command"); typeO = force->inumeric(FLERR,arg[0]); typeH = force->inumeric(FLERR,arg[1]); typeB = force->inumeric(FLERR,arg[2]); typeA = force->inumeric(FLERR,arg[3]); qdist = force->numeric(FLERR,arg[4]); cut_coul = force->numeric(FLERR,arg[5]); cut_coulsq = cut_coul * cut_coul; cut_coulsqplus = (cut_coul + 2.0*qdist) * (cut_coul + 2.0*qdist); } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairTIP4PCut::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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,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++) { setflag[i][j] = 1; count++; } } if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairTIP4PCut::init_style() { if (atom->tag_enable == 0) error->all(FLERR,"Pair style tip4p/cut requires atom IDs"); if (!force->newton_pair) error->all(FLERR, "Pair style tip4p/cut requires newton pair on"); if (!atom->q_flag) error->all(FLERR, "Pair style tip4p/cut requires atom attribute q"); 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"); neighbor->request(this,instance_me); // set alpha parameter double theta = force->angle->equilibrium_angle(typeA); double blen = force->bond->equilibrium_distance(typeB); alpha = qdist / (cos(0.5*theta) * blen); } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairTIP4PCut::init_one(int i, int j) { // include TIP4P qdist in full cutoff, qdist = 0.0 if not TIP4P return cut_coul+2.0*qdist; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairTIP4PCut::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); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairTIP4PCut::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); } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairTIP4PCut::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_coul,sizeof(double),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairTIP4PCut::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_coul,sizeof(double),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_coul,1,MPI_DOUBLE,0,world); cut_coulsq = cut_coul * cut_coul; cut_coulsqplus = (cut_coul + 2.0*qdist) * (cut_coul + 2.0*qdist); } /* ---------------------------------------------------------------------- compute position xM of fictitious charge site for O atom and 2 H atoms return it as xM ------------------------------------------------------------------------- */ void PairTIP4PCut::compute_newsite(double *xO, double *xH1, double *xH2, double *xM) { double delx1 = xH1[0] - xO[0]; double dely1 = xH1[1] - xO[1]; double delz1 = xH1[2] - xO[2]; domain->minimum_image(delx1,dely1,delz1); double delx2 = xH2[0] - xO[0]; double dely2 = xH2[1] - xO[1]; double delz2 = xH2[2] - xO[2]; domain->minimum_image(delx2,dely2,delz2); xM[0] = xO[0] + alpha * 0.5 * (delx1 + delx2); xM[1] = xO[1] + alpha * 0.5 * (dely1 + dely2); xM[2] = xO[2] + alpha * 0.5 * (delz1 + delz2); } /* ---------------------------------------------------------------------- memory usage of hneigh ------------------------------------------------------------------------- */ double PairTIP4PCut::memory_usage() { double bytes = maxeatom * sizeof(double); bytes += maxvatom*6 * sizeof(double); bytes += 2 * nmax * sizeof(double); return bytes; } diff --git a/src/PERI/pair_peri_eps.cpp b/src/PERI/pair_peri_eps.cpp index ecf6f0a3f..b5807c0e3 100644 --- a/src/PERI/pair_peri_eps.cpp +++ b/src/PERI/pair_peri_eps.cpp @@ -1,826 +1,826 @@ /* ---------------------------------------------------------------------- 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: Rezwanur Rahman, John Foster (UTSA) ------------------------------------------------------------------------- */ #include #include #include #include "pair_peri_eps.h" #include "atom.h" #include "domain.h" #include "lattice.h" #include "force.h" #include "update.h" #include "modify.h" #include "fix.h" #include "fix_peri_neigh.h" #include "comm.h" #include "neighbor.h" #include "neigh_list.h" #include "memory.h" #include "error.h" #include "update.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ PairPeriEPS::PairPeriEPS(LAMMPS *lmp) : Pair(lmp) { for (int i = 0; i < 6; i++) virial[i] = 0.0; no_virial_fdotr_compute = 1; single_enable = 0; ifix_peri = -1; nmax = 0; s0_new = NULL; theta = NULL; bulkmodulus = NULL; shearmodulus = NULL; s00 = alpha = NULL; cut = NULL; m_yieldstress = NULL; // set comm size needed by this Pair // comm_reverse not needed comm_forward = 1; } /* ---------------------------------------------------------------------- */ PairPeriEPS::~PairPeriEPS() { if (ifix_peri >= 0) modify->delete_fix("PERI_NEIGH"); if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(bulkmodulus); memory->destroy(shearmodulus); memory->destroy(s00); memory->destroy(alpha); memory->destroy(cut); memory->destroy(m_yieldstress); memory->destroy(theta); memory->destroy(s0_new); } } /* ---------------------------------------------------------------------- */ void PairPeriEPS::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz; double xtmp0,ytmp0,ztmp0,delx0,dely0,delz0,rsq0; double rsq,r,dr,rk,rkNew,evdwl,fpair,fbond; double fbondElastoPlastic,fbondFinal; double deltalambda,edpNp1; int *ilist,*jlist,*numneigh,**firstneigh; double d_ij,delta,stretch; evdwl = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = eflag_global = eflag_atom = 0; double **f = atom->f; double **x = atom->x; int *type = atom->type; int nlocal = atom->nlocal; double *vfrac = atom->vfrac; double *s0 = atom->s0; double **x0 = atom->x0; double **r0 = ((FixPeriNeigh *) modify->fix[ifix_peri])->r0; double **deviatorPlasticextension = ((FixPeriNeigh *) modify->fix[ifix_peri])->deviatorPlasticextension; tagint **partner = ((FixPeriNeigh *) modify->fix[ifix_peri])->partner; int *npartner = ((FixPeriNeigh *) modify->fix[ifix_peri])->npartner; double *wvolume = ((FixPeriNeigh *) modify->fix[ifix_peri])->wvolume; double *lambdaValue = ((FixPeriNeigh *) modify->fix[ifix_peri])->lambdaValue; // lc = lattice constant // init_style guarantees it's the same in x, y, and z double lc = domain->lattice->xlattice; double half_lc = 0.5*lc; double vfrac_scale = 1.0; // short-range forces int newton_pair = force->newton_pair; int periodic = domain->xperiodic || domain->yperiodic || domain->zperiodic; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // loop over neighbors of my atoms // need minimg() for x0 difference since not ghosted for (ii = 0; ii < inum; ii++) { i = ilist[ii]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; xtmp0 = x0[i][0]; ytmp0 = x0[i][1]; ztmp0 = x0[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; delx0 = xtmp0 - x0[j][0]; dely0 = ytmp0 - x0[j][1]; delz0 = ztmp0 - x0[j][2]; if (periodic) domain->minimum_image(delx0,dely0,delz0); rsq0 = delx0*delx0 + dely0*dely0 + delz0*delz0; jtype = type[j]; r = sqrt(rsq); // short-range interaction distance based on initial particle position // 0.9 and 1.35 are constants d_ij = MIN(0.9*sqrt(rsq0),1.35*lc); // short-range contact forces // 15 is constant taken from the EMU Theory Manual // Silling, 12 May 2005, p 18 if (r < d_ij) { dr = r - d_ij; // kshort based upon short-range force constant // of the bond-based theory used in PMB model double kshort = (15.0 * 18.0 * bulkmodulus[itype][itype]) / (3.141592653589793 * cutsq[itype][jtype] * cutsq[itype][jtype]); rk = (kshort * vfrac[j]) * (dr / cut[itype][jtype]); if (r > 0.0) fpair = -(rk/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 = 0.5*rk*dr; if (evflag) ev_tally(i,j,nlocal,newton_pair,evdwl,0.0, fpair*vfrac[i],delx,dely,delz); } } } // grow bond forces array if necessary int maxpartner = 0; for (i = 0; i < nlocal; i++) maxpartner = MAX(maxpartner,npartner[i]); if (atom->nmax > nmax) { memory->destroy(s0_new); memory->destroy(theta); nmax = atom->nmax; memory->create(s0_new,nmax,"pair:s0_new"); memory->create(theta,nmax,"pair:theta"); } // ******** temp array to store Plastic extension *********** /// // create on heap to reduce stack use and to allow for faster zeroing double **deviatorPlasticExtTemp; memory->create(deviatorPlasticExtTemp,nlocal,maxpartner,"pair:plastext"); memset(&(deviatorPlasticExtTemp[0][0]),0,sizeof(double)*nlocal*maxpartner); // ******** temp array to store Plastic extension *********** /// // compute the dilatation on each particle compute_dilatation(); // communicate dilatation (theta) of each particle comm->forward_comm_pair(this); // communicate weighted volume (wvolume) upon every reneighbor if (neighbor->ago == 0) comm->forward_comm_fix(modify->fix[ifix_peri]); // volume-dependent part of the energy if (eflag) { for (i = 0; i < nlocal; i++) { itype = type[i]; if (eflag_global) eng_vdwl += 0.5 * bulkmodulus[itype][itype] * (theta[i] * theta[i]); if (eflag_atom) eatom[i] += 0.5 * bulkmodulus[itype][itype] * (theta[i] * theta[i]); } } // loop over my particles and their partners // partner list contains all bond partners, so I-J appears twice // if bond already broken, skip this partner // first = true if this is first neighbor of particle i bool first; double omega_minus, omega_plus; for (i = 0; i < nlocal; i++) { xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; xtmp0 = x0[i][0]; ytmp0 = x0[i][1]; ztmp0 = x0[i][2]; itype = type[i]; jnum = npartner[i]; first = true; double yieldStress = m_yieldstress[itype][itype]; double horizon = cut[itype][itype]; double tdnorm = compute_DeviatoricForceStateNorm(i); double pointwiseYieldvalue = 25.0 * yieldStress * yieldStress / 8 / M_PI / pow(horizon,5); double fsurf = (tdnorm * tdnorm)/2 - pointwiseYieldvalue; bool elastic = true; double alphavalue = (15 * shearmodulus[itype][itype]) /wvolume[i]; if (fsurf>0) { elastic = false; deltalambda = ((tdnorm /sqrt(2.0 * pointwiseYieldvalue)) - 1.0) / alphavalue; double templambda = lambdaValue[i]; lambdaValue[i] = templambda + deltalambda; } for (jj = 0; jj < jnum; jj++) { if (partner[i][jj] == 0) continue; j = atom->map(partner[i][jj]); // check if lost a partner without first breaking bond if (j < 0) { partner[i][jj] = 0; continue; } // compute force density, add to PD equation of motion delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; if (periodic) domain->minimum_image(delx,dely,delz); rsq = delx*delx + dely*dely + delz*delz; delx0 = xtmp0 - x0[j][0]; dely0 = ytmp0 - x0[j][1]; delz0 = ztmp0 - x0[j][2]; if (periodic) domain->minimum_image(delx0,dely0,delz0); jtype = type[j]; delta = cut[itype][jtype]; r = sqrt(rsq); dr = r - r0[i][jj]; // avoid roundoff errors if (fabs(dr) < 2.2204e-016) { dr = 0.0; } // scale vfrac[j] if particle j near the horizon if ((fabs(r0[i][jj] - delta)) <= half_lc) vfrac_scale = (-1.0/(2*half_lc))*(r0[i][jj]) + (1.0 + ((delta - half_lc)/(2*half_lc) ) ); else vfrac_scale = 1.0; omega_plus = influence_function(-1.0*delx0,-1.0*dely0,-1.0*delz0); omega_minus = influence_function(delx0,dely0,delz0); //Elastic Part rk = ((3.0 * bulkmodulus[itype][itype]) * ( (omega_plus * theta[i] / wvolume[i]) + ( omega_minus * theta[j] / wvolume[j] ) ) ) * r0[i][jj]; if (r > 0.0) fbond = -((rk/r) * vfrac[j] * vfrac_scale); else fbond = 0.0; //Plastic part double deviatoric_extension = dr - (theta[i]* r0[i][jj] / 3.0); edpNp1 = deviatorPlasticextension[i][jj]; double tdtrialValue = ( 15 * shearmodulus[itype][itype]) * ( (omega_plus / wvolume[i]) + (omega_minus / wvolume[j]) ) * (deviatoric_extension - edpNp1); if(elastic) { rkNew = tdtrialValue; } else { rkNew = (sqrt(2.0*pointwiseYieldvalue) * tdtrialValue) / tdnorm; deviatorPlasticExtTemp[i][jj] = edpNp1 + rkNew * deltalambda; } if (r > 0.0) fbondElastoPlastic = -((rkNew/r) * vfrac[j] * vfrac_scale); else fbondElastoPlastic = 0.0; // total Force state: elastic + plastic fbondFinal=fbond+fbondElastoPlastic; fbond=fbondFinal; f[i][0] += delx*fbond; f[i][1] += dely*fbond; f[i][2] += delz*fbond; // since I-J is double counted, set newton off & use 1/2 factor and I,I if (eflag) evdwl = (0.5 * 15 * shearmodulus[itype][itype]/wvolume[i] * omega_plus * (deviatoric_extension - edpNp1) * (deviatoric_extension-edpNp1)) * vfrac[j] * vfrac_scale; if (evflag) ev_tally(i,i,nlocal,0,0.5*evdwl,0.0, 0.5*fbond*vfrac[i],delx,dely,delz); // find stretch in bond I-J and break if necessary // use s0 from previous timestep stretch = dr / r0[i][jj]; if (stretch > MIN(s0[i],s0[j])) partner[i][jj] = 0; // update s0 for next timestep if (first) s0_new[i] = s00[itype][jtype] - (alpha[itype][jtype] * stretch); else s0_new[i] = MAX(s0_new[i],s00[itype][jtype] - (alpha[itype][jtype] * stretch)); first = false; } } // store new s0 memcpy(s0,s0_new,sizeof(double)*nlocal); memcpy(&(deviatorPlasticextension[0][0]), &(deviatorPlasticExtTemp[0][0]), sizeof(double)*nlocal*maxpartner); memory->destroy(deviatorPlasticExtTemp); } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairPeriEPS::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(bulkmodulus,n+1,n+1,"pair:bulkmodulus"); memory->create(shearmodulus,n+1,n+1,"pair:shearmodulus"); memory->create(s00,n+1,n+1,"pair:s00"); memory->create(alpha,n+1,n+1,"pair:alpha"); memory->create(cut,n+1,n+1,"pair:cut"); memory->create(m_yieldstress,n+1,n+1,"pair:m_yieldstress"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairPeriEPS::settings(int narg, char **arg) { if (narg) error->all(FLERR,"Illegal pair_style command"); } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairPeriEPS::coeff(int narg, char **arg) { if (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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double bulkmodulus_one = atof(arg[2]); double shearmodulus_one = atof(arg[3]); double cut_one = atof(arg[4]); double s00_one = atof(arg[5]); double alpha_one = atof(arg[6]); double myieldstress_one = atof(arg[7]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { bulkmodulus[i][j] = bulkmodulus_one; shearmodulus[i][j] = shearmodulus_one; cut[i][j] = cut_one; s00[i][j] = s00_one; alpha[i][j] = alpha_one; m_yieldstress[i][j] = myieldstress_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 PairPeriEPS::init_one(int i, int j) { if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set"); bulkmodulus[j][i] = bulkmodulus[i][j]; shearmodulus[j][i] = shearmodulus[i][j]; s00[j][i] = s00[i][j]; alpha[j][i] = alpha[i][j]; cut[j][i] = cut[i][j]; m_yieldstress[j][i] = m_yieldstress[i][j]; return cut[i][j]; } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairPeriEPS::init_style() { // error checks if (!atom->peri_flag) error->all(FLERR,"Pair style peri requires atom style peri"); if (atom->map_style == 0) error->all(FLERR,"Pair peri requires an atom map, see atom_modify"); if (domain->lattice == NULL) error->all(FLERR,"Pair peri requires a lattice be defined"); if (domain->lattice->xlattice != domain->lattice->ylattice || domain->lattice->xlattice != domain->lattice->zlattice || domain->lattice->ylattice != domain->lattice->zlattice) error->all(FLERR,"Pair peri lattice is not identical in x, y, and z"); // if first init, create Fix needed for storing fixed neighbors if (ifix_peri == -1) { char **fixarg = new char*[3]; fixarg[0] = (char *) "PERI_NEIGH"; fixarg[1] = (char *) "all"; fixarg[2] = (char *) "PERI_NEIGH"; modify->add_fix(3,fixarg); delete [] fixarg; } // find associated PERI_NEIGH fix that must exist // could have changed locations in fix list since created for (int i = 0; i < modify->nfix; i++) if (strcmp(modify->fix[i]->style,"PERI_NEIGH") == 0) ifix_peri = i; if (ifix_peri == -1) error->all(FLERR,"Fix peri neigh does not exist"); neighbor->request(this,instance_me); } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairPeriEPS::write_restart(FILE *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(&bulkmodulus[i][j],sizeof(double),1,fp); fwrite(&shearmodulus[i][j],sizeof(double),1,fp); fwrite(&s00[i][j],sizeof(double),1,fp); fwrite(&alpha[i][j],sizeof(double),1,fp); fwrite(&cut[i][j],sizeof(double),1,fp); fwrite(&m_yieldstress[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairPeriEPS::read_restart(FILE *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(&bulkmodulus[i][j],sizeof(double),1,fp); fread(&shearmodulus[i][j],sizeof(double),1,fp); fread(&s00[i][j],sizeof(double),1,fp); fread(&alpha[i][j],sizeof(double),1,fp); fread(&cut[i][j],sizeof(double),1,fp); fread(&m_yieldstress[i][j],sizeof(double),1,fp); } MPI_Bcast(&bulkmodulus[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&shearmodulus[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&s00[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&alpha[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&m_yieldstress[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- memory usage of local atom-based arrays ------------------------------------------------------------------------- */ double PairPeriEPS::memory_usage() { double bytes = 2 * nmax * sizeof(double); return bytes; } /* ---------------------------------------------------------------------- influence function definition ------------------------------------------------------------------------- */ double PairPeriEPS::influence_function(double xi_x, double xi_y, double xi_z) { double r = sqrt(xi_x*xi_x + xi_y*xi_y + xi_z*xi_z); double omega; if (fabs(r) < 2.2204e-016) error->one(FLERR,"Divide by 0 in influence function"); omega = 1.0/r; return omega; } /* ---------------------------------------------------------------------- */ void PairPeriEPS::compute_dilatation() { int i,j,jj,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz; double xtmp0,ytmp0,ztmp0,delx0,dely0,delz0; double rsq,r,dr; double delta; double **x = atom->x; int *type = atom->type; double **x0 = atom->x0; int nlocal = atom->nlocal; double *vfrac = atom->vfrac; double vfrac_scale = 1.0; double lc = domain->lattice->xlattice; double half_lc = 0.5*lc; double **r0 = ((FixPeriNeigh *) modify->fix[ifix_peri])->r0; tagint **partner = ((FixPeriNeigh *) modify->fix[ifix_peri])->partner; int *npartner = ((FixPeriNeigh *) modify->fix[ifix_peri])->npartner; double *wvolume = ((FixPeriNeigh *) modify->fix[ifix_peri])->wvolume; int periodic = domain->xperiodic || domain->yperiodic || domain->zperiodic; // compute the dilatation theta for (i = 0; i < nlocal; i++) { xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; xtmp0 = x0[i][0]; ytmp0 = x0[i][1]; ztmp0 = x0[i][2]; jnum = npartner[i]; theta[i] = 0.0; itype = type[i]; for (jj = 0; jj < jnum; jj++) { // if bond already broken, skip this partner if (partner[i][jj] == 0) continue; // look up local index of this partner particle j = atom->map(partner[i][jj]); // skip if particle is "lost" if (j < 0) continue; // compute force density and add to PD equation of motion delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; if (periodic) domain->minimum_image(delx,dely,delz); rsq = delx*delx + dely*dely + delz*delz; delx0 = xtmp0 - x0[j][0]; dely0 = ytmp0 - x0[j][1]; delz0 = ztmp0 - x0[j][2]; if (periodic) domain->minimum_image(delx0,dely0,delz0); r = sqrt(rsq); dr = r - r0[i][jj]; if (fabs(dr) < 2.2204e-016) dr = 0.0; jtype = type[j]; delta = cut[itype][jtype]; // scale vfrac[j] if particle j near the horizon if ((fabs(r0[i][jj] - delta)) <= half_lc) vfrac_scale = (-1.0/(2*half_lc))*(r0[i][jj]) + (1.0 + ((delta - half_lc)/(2*half_lc) ) ); else vfrac_scale = 1.0; theta[i] += influence_function(delx0, dely0, delz0) * r0[i][jj] * dr * vfrac[j] * vfrac_scale; } // if wvolume[i] is zero, then particle i has no bonds // therefore, the dilatation is set to if (wvolume[i] != 0.0) theta[i] = (3.0/wvolume[i]) * theta[i]; else theta[i] = 0; } } /* ---------------------------------------------------------------------- */ double PairPeriEPS::compute_DeviatoricForceStateNorm(int i) { int j,jj,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz; double xtmp0,ytmp0,ztmp0,delx0,dely0,delz0; double rsq,r,dr; double tdtrial; double norm = 0.0; double **x = atom->x; int *type = atom->type; double **x0 = atom->x0; double *vfrac = atom->vfrac; double lc = domain->lattice->xlattice; double half_lc = 0.5*lc; double **r0 = ((FixPeriNeigh *) modify->fix[ifix_peri])->r0; tagint **partner = ((FixPeriNeigh *) modify->fix[ifix_peri])->partner; int *npartner = ((FixPeriNeigh *) modify->fix[ifix_peri])->npartner; double *wvolume = ((FixPeriNeigh *) modify->fix[ifix_peri])->wvolume; double **deviatorPlasticextension = ((FixPeriNeigh *) modify->fix[ifix_peri])->deviatorPlasticextension; int periodic = domain->xperiodic || domain->yperiodic || domain->zperiodic; // compute the dilatation theta xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; xtmp0 = x0[i][0]; ytmp0 = x0[i][1]; ztmp0 = x0[i][2]; jnum = npartner[i]; itype = type[i]; for (jj = 0; jj < jnum; jj++) { if (partner[i][jj] == 0) continue; j = atom->map(partner[i][jj]); // check if lost a partner without first breaking bond if (j < 0) { partner[i][jj] = 0; continue; } delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; if (periodic) domain->minimum_image(delx,dely,delz); rsq = delx*delx + dely*dely + delz*delz; delx0 = xtmp0 - x0[j][0]; dely0 = ytmp0 - x0[j][1]; delz0 = ztmp0 - x0[j][2]; if (periodic) domain->minimum_image(delx0,dely0,delz0); r = sqrt(rsq); dr = r - r0[i][jj]; if (fabs(dr) < 2.2204e-016) dr = 0.0; // scale vfrac[j] if particle j near the horizon double vfrac_scale; jtype = type[j]; double delta = cut[itype][jtype]; // scale vfrac[j] if particle j near the horizon if ((fabs(r0[i][jj] - delta)) <= half_lc) vfrac_scale = (-1.0/(2*half_lc))*(r0[i][jj]) + (1.0 + ((delta - half_lc)/(2*half_lc) ) ); else vfrac_scale = 1.0; double ed = dr - (theta[i] * r0[i][jj])/3; double edPNP1 = deviatorPlasticextension[i][jj]; jtype = type[j]; delta = cut[itype][jtype]; double omega_plus = influence_function(-1.0*delx0,-1.0*dely0,-1.0*delz0); double omega_minus = influence_function(delx0,dely0,delz0); tdtrial = ( 15 * shearmodulus[itype][itype]) * ((omega_plus * theta[i] / wvolume[i]) + ( omega_minus * theta[j] / wvolume[j] ) ) * (ed - edPNP1); norm += tdtrial * tdtrial * vfrac[j] * vfrac_scale; } return sqrt(norm); } /* ---------------------------------------------------------------------- communication routines ---------------------------------------------------------------------- */ int PairPeriEPS::pack_forward_comm(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; m = 0; for (i = 0; i < n; i++) { j = list[i]; buf[m++] = theta[j]; } return m; } /* ---------------------------------------------------------------------- */ void PairPeriEPS::unpack_forward_comm(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { theta[i] = buf[m++]; } } diff --git a/src/PERI/pair_peri_lps.cpp b/src/PERI/pair_peri_lps.cpp index 7b2ccec92..cd88b4182 100644 --- a/src/PERI/pair_peri_lps.cpp +++ b/src/PERI/pair_peri_lps.cpp @@ -1,653 +1,653 @@ /* ---------------------------------------------------------------------- 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 Parks (SNL) ------------------------------------------------------------------------- */ #include #include #include #include "pair_peri_lps.h" #include "atom.h" #include "domain.h" #include "lattice.h" #include "force.h" #include "update.h" #include "modify.h" #include "fix.h" #include "fix_peri_neigh.h" #include "comm.h" #include "neighbor.h" #include "neigh_list.h" #include "memory.h" #include "error.h" #include "update.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ PairPeriLPS::PairPeriLPS(LAMMPS *lmp) : Pair(lmp) { for (int i = 0; i < 6; i++) virial[i] = 0.0; no_virial_fdotr_compute = 1; single_enable = 0; ifix_peri = -1; nmax = 0; s0_new = NULL; theta = NULL; bulkmodulus = NULL; shearmodulus = NULL; s00 = alpha = NULL; cut = NULL; // set comm size needed by this Pair // comm_reverse not needed comm_forward = 1; // for passing dilatation (theta) } /* ---------------------------------------------------------------------- */ PairPeriLPS::~PairPeriLPS() { if (ifix_peri >= 0) modify->delete_fix("PERI_NEIGH"); if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(bulkmodulus); memory->destroy(shearmodulus); memory->destroy(s00); memory->destroy(alpha); memory->destroy(cut); memory->destroy(theta); memory->destroy(s0_new); } } /* ---------------------------------------------------------------------- */ void PairPeriLPS::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz; double xtmp0,ytmp0,ztmp0,delx0,dely0,delz0,rsq0; double rsq,r,dr,rk,evdwl,fpair,fbond; int *ilist,*jlist,*numneigh,**firstneigh; double d_ij,delta,stretch; evdwl = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = eflag_global = eflag_atom = 0; double **f = atom->f; double **x = atom->x; int *type = atom->type; int nlocal = atom->nlocal; double *vfrac = atom->vfrac; double *s0 = atom->s0; double **x0 = atom->x0; double **r0 = ((FixPeriNeigh *) modify->fix[ifix_peri])->r0; tagint **partner = ((FixPeriNeigh *) modify->fix[ifix_peri])->partner; int *npartner = ((FixPeriNeigh *) modify->fix[ifix_peri])->npartner; double *wvolume = ((FixPeriNeigh *) modify->fix[ifix_peri])->wvolume; // lc = lattice constant // init_style guarantees it's the same in x, y, and z double lc = domain->lattice->xlattice; double half_lc = 0.5*lc; double vfrac_scale = 1.0; // short-range forces int newton_pair = force->newton_pair; int periodic = domain->xperiodic || domain->yperiodic || domain->zperiodic; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // loop over neighbors of my atoms // need minimg() for x0 difference since not ghosted for (ii = 0; ii < inum; ii++) { i = ilist[ii]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; xtmp0 = x0[i][0]; ytmp0 = x0[i][1]; ztmp0 = x0[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; delx0 = xtmp0 - x0[j][0]; dely0 = ytmp0 - x0[j][1]; delz0 = ztmp0 - x0[j][2]; if (periodic) domain->minimum_image(delx0,dely0,delz0); rsq0 = delx0*delx0 + dely0*dely0 + delz0*delz0; jtype = type[j]; r = sqrt(rsq); // short-range interaction distance based on initial particle position // 0.9 and 1.35 are constants d_ij = MIN(0.9*sqrt(rsq0),1.35*lc); // short-range contact forces // 15 is constant taken from the EMU Theory Manual // Silling, 12 May 2005, p 18 if (r < d_ij) { dr = r - d_ij; // kshort based upon short-range force constant // of the bond-based theory used in PMB model double kshort = (15.0 * 18.0 * bulkmodulus[itype][itype]) / (3.141592653589793 * cutsq[itype][jtype] * cutsq[itype][jtype]); rk = (kshort * vfrac[j]) * (dr / cut[itype][jtype]); if (r > 0.0) fpair = -(rk/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 = 0.5*rk*dr; if (evflag) ev_tally(i,j,nlocal,newton_pair,evdwl,0.0, fpair*vfrac[i],delx,dely,delz); } } } // grow bond forces array if necessary if (atom->nmax > nmax) { memory->destroy(s0_new); memory->destroy(theta); nmax = atom->nmax; memory->create(s0_new,nmax,"pair:s0_new"); memory->create(theta,nmax,"pair:theta"); } // Compute the dilatation on each particle compute_dilatation(); // communicate dilatation (theta) of each particle comm->forward_comm_pair(this); // communicate wighted volume (wvolume) upon every reneighbor if (neighbor->ago == 0) comm->forward_comm_fix(modify->fix[ifix_peri]); // Volume-dependent part of the energy if (eflag) { for (i = 0; i < nlocal; i++) { itype = type[i]; if (eflag_global) eng_vdwl += 0.5 * bulkmodulus[itype][itype] * (theta[i] * theta[i]); if (eflag_atom) eatom[i] += 0.5 * bulkmodulus[itype][itype] * (theta[i] * theta[i]); } } // loop over my particles and their partners // partner list contains all bond partners, so I-J appears twice // if bond already broken, skip this partner // first = true if this is first neighbor of particle i bool first; double omega_minus, omega_plus; for (i = 0; i < nlocal; i++) { xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; xtmp0 = x0[i][0]; ytmp0 = x0[i][1]; ztmp0 = x0[i][2]; itype = type[i]; jnum = npartner[i]; first = true; for (jj = 0; jj < jnum; jj++) { if (partner[i][jj] == 0) continue; j = atom->map(partner[i][jj]); // check if lost a partner without first breaking bond if (j < 0) { partner[i][jj] = 0; continue; } // compute force density, add to PD equation of motion delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; if (periodic) domain->minimum_image(delx,dely,delz); rsq = delx*delx + dely*dely + delz*delz; delx0 = xtmp0 - x0[j][0]; dely0 = ytmp0 - x0[j][1]; delz0 = ztmp0 - x0[j][2]; if (periodic) domain->minimum_image(delx0,dely0,delz0); jtype = type[j]; delta = cut[itype][jtype]; r = sqrt(rsq); dr = r - r0[i][jj]; // avoid roundoff errors if (fabs(dr) < 2.2204e-016) dr = 0.0; // scale vfrac[j] if particle j near the horizon if ((fabs(r0[i][jj] - delta)) <= half_lc) vfrac_scale = (-1.0/(2*half_lc))*(r0[i][jj]) + (1.0 + ((delta - half_lc)/(2*half_lc) ) ); else vfrac_scale = 1.0; omega_plus = influence_function(-1.0*delx0,-1.0*dely0,-1.0*delz0); omega_minus = influence_function(delx0,dely0,delz0); rk = ( (3.0 * bulkmodulus[itype][itype]) - (5.0 * shearmodulus[itype][itype]) ) * vfrac[j] * vfrac_scale * ( (omega_plus * theta[i] / wvolume[i]) + ( omega_minus * theta[j] / wvolume[j] ) ) * r0[i][jj]; rk += 15.0 * ( shearmodulus[itype][itype] * vfrac[j] * vfrac_scale ) * ( (omega_plus / wvolume[i]) + (omega_minus / wvolume[j]) ) * dr; if (r > 0.0) fbond = -(rk/r); else fbond = 0.0; f[i][0] += delx*fbond; f[i][1] += dely*fbond; f[i][2] += delz*fbond; // since I-J is double counted, set newton off & use 1/2 factor and I,I double deviatoric_extension = dr - (theta[i]* r0[i][jj] / 3.0); if (eflag) evdwl = 0.5 * 15 * (shearmodulus[itype][itype]/wvolume[i]) * omega_plus*(deviatoric_extension * deviatoric_extension) * vfrac[j] * vfrac_scale; if (evflag) ev_tally(i,i,nlocal,0,0.5*evdwl,0.0, 0.5*fbond*vfrac[i],delx,dely,delz); // find stretch in bond I-J and break if necessary // use s0 from previous timestep stretch = dr / r0[i][jj]; if (stretch > MIN(s0[i],s0[j])) partner[i][jj] = 0; // update s0 for next timestep if (first) s0_new[i] = s00[itype][jtype] - (alpha[itype][jtype] * stretch); else s0_new[i] = MAX(s0_new[i],s00[itype][jtype] - (alpha[itype][jtype] * stretch)); first = false; } } // store new s0 for (i = 0; i < nlocal; i++) s0[i] = s0_new[i]; } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairPeriLPS::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(bulkmodulus,n+1,n+1,"pair:bulkmodulus"); memory->create(shearmodulus,n+1,n+1,"pair:shearmodulus"); memory->create(s00,n+1,n+1,"pair:s00"); memory->create(alpha,n+1,n+1,"pair:alpha"); memory->create(cut,n+1,n+1,"pair:cut"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairPeriLPS::settings(int narg, char **arg) { if (narg) error->all(FLERR,"Illegal pair_style command"); } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairPeriLPS::coeff(int narg, char **arg) { if (narg != 7) 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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double bulkmodulus_one = force->numeric(FLERR,arg[2]); double shearmodulus_one = force->numeric(FLERR,arg[3]); double cut_one = force->numeric(FLERR,arg[4]); double s00_one = force->numeric(FLERR,arg[5]); double alpha_one = force->numeric(FLERR,arg[6]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { bulkmodulus[i][j] = bulkmodulus_one; shearmodulus[i][j] = shearmodulus_one; cut[i][j] = cut_one; s00[i][j] = s00_one; alpha[i][j] = alpha_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 PairPeriLPS::init_one(int i, int j) { if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set"); bulkmodulus[j][i] = bulkmodulus[i][j]; shearmodulus[j][i] = shearmodulus[i][j]; s00[j][i] = s00[i][j]; alpha[j][i] = alpha[i][j]; cut[j][i] = cut[i][j]; return cut[i][j]; } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairPeriLPS::init_style() { // error checks if (!atom->peri_flag) error->all(FLERR,"Pair style peri requires atom style peri"); if (atom->map_style == 0) error->all(FLERR,"Pair peri requires an atom map, see atom_modify"); if (domain->lattice->xlattice != domain->lattice->ylattice || domain->lattice->xlattice != domain->lattice->zlattice || domain->lattice->ylattice != domain->lattice->zlattice) error->all(FLERR,"Pair peri lattice is not identical in x, y, and z"); // if first init, create Fix needed for storing fixed neighbors if (ifix_peri == -1) { char **fixarg = new char*[3]; fixarg[0] = (char *) "PERI_NEIGH"; fixarg[1] = (char *) "all"; fixarg[2] = (char *) "PERI_NEIGH"; modify->add_fix(3,fixarg); delete [] fixarg; } // find associated PERI_NEIGH fix that must exist // could have changed locations in fix list since created for (int i = 0; i < modify->nfix; i++) if (strcmp(modify->fix[i]->style,"PERI_NEIGH") == 0) ifix_peri = i; if (ifix_peri == -1) error->all(FLERR,"Fix peri neigh does not exist"); neighbor->request(this,instance_me); } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairPeriLPS::write_restart(FILE *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(&bulkmodulus[i][j],sizeof(double),1,fp); fwrite(&shearmodulus[i][j],sizeof(double),1,fp); fwrite(&s00[i][j],sizeof(double),1,fp); fwrite(&alpha[i][j],sizeof(double),1,fp); fwrite(&cut[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairPeriLPS::read_restart(FILE *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(&bulkmodulus[i][j],sizeof(double),1,fp); fread(&shearmodulus[i][j],sizeof(double),1,fp); fread(&s00[i][j],sizeof(double),1,fp); fread(&alpha[i][j],sizeof(double),1,fp); fread(&cut[i][j],sizeof(double),1,fp); } MPI_Bcast(&bulkmodulus[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&shearmodulus[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&s00[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&alpha[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- memory usage of local atom-based arrays ------------------------------------------------------------------------- */ double PairPeriLPS::memory_usage() { double bytes = 2 * nmax * sizeof(double); return bytes; } /* ---------------------------------------------------------------------- influence function definition ------------------------------------------------------------------------- */ double PairPeriLPS::influence_function(double xi_x, double xi_y, double xi_z) { double r = sqrt(xi_x*xi_x + xi_y*xi_y + xi_z*xi_z); double omega; if (fabs(r) < 2.2204e-016) error->one(FLERR,"Divide by 0 in influence function of pair peri/lps"); omega = 1.0/r; return omega; } /* ---------------------------------------------------------------------- */ void PairPeriLPS::compute_dilatation() { int i,j,jj,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz; double xtmp0,ytmp0,ztmp0,delx0,dely0,delz0; double rsq,r,dr; double delta; double **x = atom->x; int *type = atom->type; double **x0 = atom->x0; int nlocal = atom->nlocal; double *vfrac = atom->vfrac; double vfrac_scale = 1.0; double lc = domain->lattice->xlattice; double half_lc = 0.5*lc; double **r0 = ((FixPeriNeigh *) modify->fix[ifix_peri])->r0; tagint **partner = ((FixPeriNeigh *) modify->fix[ifix_peri])->partner; int *npartner = ((FixPeriNeigh *) modify->fix[ifix_peri])->npartner; double *wvolume = ((FixPeriNeigh *) modify->fix[ifix_peri])->wvolume; int periodic = domain->xperiodic || domain->yperiodic || domain->zperiodic; // compute the dilatation theta for (i = 0; i < nlocal; i++) { xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; xtmp0 = x0[i][0]; ytmp0 = x0[i][1]; ztmp0 = x0[i][2]; jnum = npartner[i]; theta[i] = 0.0; itype = type[i]; for (jj = 0; jj < jnum; jj++) { // if bond already broken, skip this partner if (partner[i][jj] == 0) continue; // Look up local index of this partner particle j = atom->map(partner[i][jj]); // Skip if particle is "lost" if (j < 0) continue; // Compute force density and add to PD equation of motion delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; if (periodic) domain->minimum_image(delx,dely,delz); rsq = delx*delx + dely*dely + delz*delz; delx0 = xtmp0 - x0[j][0]; dely0 = ytmp0 - x0[j][1]; delz0 = ztmp0 - x0[j][2]; if (periodic) domain->minimum_image(delx0,dely0,delz0); r = sqrt(rsq); dr = r - r0[i][jj]; if (fabs(dr) < 2.2204e-016) dr = 0.0; jtype = type[j]; delta = cut[itype][jtype]; // scale vfrac[j] if particle j near the horizon if ((fabs(r0[i][jj] - delta)) <= half_lc) vfrac_scale = (-1.0/(2*half_lc))*(r0[i][jj]) + (1.0 + ((delta - half_lc)/(2*half_lc) ) ); else vfrac_scale = 1.0; theta[i] += influence_function(delx0, dely0, delz0) * r0[i][jj] * dr * vfrac[j] * vfrac_scale; } // if wvolume[i] is zero, then particle i has no bonds // therefore, the dilatation is set to if (wvolume[i] != 0.0) theta[i] = (3.0/wvolume[i]) * theta[i]; else theta[i] = 0; } } /* ---------------------------------------------------------------------- communication routines ---------------------------------------------------------------------- */ int PairPeriLPS::pack_forward_comm(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; m = 0; for (i = 0; i < n; i++) { j = list[i]; buf[m++] = theta[j]; } return m; } /* ---------------------------------------------------------------------- */ void PairPeriLPS::unpack_forward_comm(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { theta[i] = buf[m++]; } } diff --git a/src/PERI/pair_peri_pmb.cpp b/src/PERI/pair_peri_pmb.cpp index bc971cb24..9e598289b 100644 --- a/src/PERI/pair_peri_pmb.cpp +++ b/src/PERI/pair_peri_pmb.cpp @@ -1,509 +1,509 @@ /* ---------------------------------------------------------------------- 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 Parks (SNL) ------------------------------------------------------------------------- */ #include #include #include #include #include "pair_peri_pmb.h" #include "atom.h" #include "domain.h" #include "lattice.h" #include "force.h" #include "update.h" #include "modify.h" #include "fix.h" #include "fix_peri_neigh.h" #include "comm.h" #include "neighbor.h" #include "neigh_list.h" #include "neigh_request.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ PairPeriPMB::PairPeriPMB(LAMMPS *lmp) : Pair(lmp) { for (int i = 0; i < 6; i++) virial[i] = 0.0; no_virial_fdotr_compute=1; ifix_peri = -1; nmax = 0; s0_new = NULL; kspring = NULL; s00 = NULL; alpha = NULL; cut = NULL; } /* ---------------------------------------------------------------------- */ PairPeriPMB::~PairPeriPMB() { if (ifix_peri >= 0) modify->delete_fix("PERI_NEIGH"); if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(kspring); memory->destroy(s00); memory->destroy(alpha); memory->destroy(cut); memory->destroy(s0_new); } } /* ---------------------------------------------------------------------- */ void PairPeriPMB::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz; double xtmp0,ytmp0,ztmp0,delx0,dely0,delz0,rsq0; double rsq,r,dr,rk,evdwl,fpair,fbond; int *ilist,*jlist,*numneigh,**firstneigh; double d_ij,delta,stretch; evdwl = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; double **f = atom->f; double **x = atom->x; int *type = atom->type; int nlocal = atom->nlocal; double *vfrac = atom->vfrac; double *s0 = atom->s0; double **x0 = atom->x0; double **r0 = ((FixPeriNeigh *) modify->fix[ifix_peri])->r0; tagint **partner = ((FixPeriNeigh *) modify->fix[ifix_peri])->partner; int *npartner = ((FixPeriNeigh *) modify->fix[ifix_peri])->npartner; // lc = lattice constant // init_style guarantees it's the same in x, y, and z double lc = domain->lattice->xlattice; double half_lc = 0.5*lc; double vfrac_scale = 1.0; // short-range forces int newton_pair = force->newton_pair; int periodic = (domain->xperiodic || domain->yperiodic || domain->zperiodic); inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // loop over neighbors of my atoms // need minimg() for x0 difference since not ghosted for (ii = 0; ii < inum; ii++) { i = ilist[ii]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; xtmp0 = x0[i][0]; ytmp0 = x0[i][1]; ztmp0 = x0[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; delx0 = xtmp0 - x0[j][0]; dely0 = ytmp0 - x0[j][1]; delz0 = ztmp0 - x0[j][2]; if (periodic) domain->minimum_image(delx0,dely0,delz0); rsq0 = delx0*delx0 + dely0*dely0 + delz0*delz0; jtype = type[j]; r = sqrt(rsq); // short-range interaction distance based on initial particle position // 0.9 and 1.35 are constants d_ij = MIN(0.9*sqrt(rsq0),1.35*lc); // short-range contact forces // 15 is constant taken from the EMU Theory Manual // Silling, 12 May 2005, p 18 if (r < d_ij) { dr = r - d_ij; rk = (15.0 * kspring[itype][jtype] * vfrac[j]) * (dr / cut[itype][jtype]); if (r > 0.0) fpair = -(rk/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 = 0.5*rk*dr; if (evflag) ev_tally(i,j,nlocal,newton_pair,evdwl,0.0, fpair*vfrac[i],delx,dely,delz); } } } // grow bond forces array if necessary if (atom->nmax > nmax) { memory->destroy(s0_new); nmax = atom->nmax; memory->create(s0_new,nmax,"pair:s0_new"); } // loop over my particles and their partners // partner list contains all bond partners, so I-J appears twice // if bond already broken, skip this partner // first = true if this is first neighbor of particle i bool first; for (i = 0; i < nlocal; i++) { xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; jnum = npartner[i]; s0_new[i] = DBL_MAX; first = true; for (jj = 0; jj < jnum; jj++) { if (partner[i][jj] == 0) continue; j = atom->map(partner[i][jj]); // check if lost a partner without first breaking bond if (j < 0) { partner[i][jj] = 0; continue; } // compute force density, add to PD equation of motion delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; if (periodic) domain->minimum_image(delx,dely,delz); rsq = delx*delx + dely*dely + delz*delz; jtype = type[j]; delta = cut[itype][jtype]; r = sqrt(rsq); dr = r - r0[i][jj]; // avoid roundoff errors if (fabs(dr) < 2.2204e-016) dr = 0.0; // scale vfrac[j] if particle j near the horizon if ((fabs(r0[i][jj] - delta)) <= half_lc) vfrac_scale = (-1.0/(2*half_lc))*(r0[i][jj]) + (1.0 + ((delta - half_lc)/(2*half_lc) ) ); else vfrac_scale = 1.0; stretch = dr / r0[i][jj]; rk = (kspring[itype][jtype] * vfrac[j]) * vfrac_scale * stretch; if (r > 0.0) fbond = -(rk/r); else fbond = 0.0; f[i][0] += delx*fbond; f[i][1] += dely*fbond; f[i][2] += delz*fbond; // since I-J is double counted, set newton off & use 1/2 factor and I,I if (eflag) evdwl = 0.5*rk*dr; if (evflag) ev_tally(i,i,nlocal,0,0.5*evdwl,0.0,0.5*fbond*vfrac[i],delx,dely,delz); // find stretch in bond I-J and break if necessary // use s0 from previous timestep if (stretch > MIN(s0[i],s0[j])) partner[i][jj] = 0; // update s0 for next timestep if (first) s0_new[i] = s00[itype][jtype] - (alpha[itype][jtype] * stretch); else s0_new[i] = MAX(s0_new[i],s00[itype][jtype] - (alpha[itype][jtype] * stretch)); first = false; } } // store new s0 for (i = 0; i < nlocal; i++) s0[i] = s0_new[i]; } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairPeriPMB::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(kspring,n+1,n+1,"pair:kspring"); memory->create(s00,n+1,n+1,"pair:s00"); memory->create(alpha,n+1,n+1,"pair:alpha"); memory->create(cut,n+1,n+1,"pair:cut"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairPeriPMB::settings(int narg, char **arg) { if (narg) error->all(FLERR,"Illegal pair_style command"); } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairPeriPMB::coeff(int narg, char **arg) { if (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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double kspring_one = force->numeric(FLERR,arg[2]); double cut_one = force->numeric(FLERR,arg[3]); double s00_one = force->numeric(FLERR,arg[4]); double alpha_one = force->numeric(FLERR,arg[5]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { kspring[i][j] = kspring_one; s00[i][j] = s00_one; alpha[i][j] = alpha_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 PairPeriPMB::init_one(int i, int j) { if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set"); kspring[j][i] = kspring[i][j]; alpha[j][i] = alpha[i][j]; s00[j][i] = s00[i][j]; cut[j][i] = cut[i][j]; return cut[i][j]; } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairPeriPMB::init_style() { // error checks if (!atom->peri_flag) error->all(FLERR,"Pair style peri requires atom style peri"); if (atom->map_style == 0) error->all(FLERR,"Pair peri requires an atom map, see atom_modify"); if (domain->lattice->xlattice != domain->lattice->ylattice || domain->lattice->xlattice != domain->lattice->zlattice || domain->lattice->ylattice != domain->lattice->zlattice) error->all(FLERR,"Pair peri lattice is not identical in x, y, and z"); // if first init, create Fix needed for storing fixed neighbors if (ifix_peri == -1) { char **fixarg = new char*[3]; fixarg[0] = (char *) "PERI_NEIGH"; fixarg[1] = (char *) "all"; fixarg[2] = (char *) "PERI_NEIGH"; modify->add_fix(3,fixarg); delete [] fixarg; } // find associated PERI_NEIGH fix that must exist // could have changed locations in fix list since created for (int i = 0; i < modify->nfix; i++) if (strcmp(modify->fix[i]->style,"PERI_NEIGH") == 0) ifix_peri = i; if (ifix_peri == -1) error->all(FLERR,"Fix peri neigh does not exist"); neighbor->request(this,instance_me); } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairPeriPMB::write_restart(FILE *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(&kspring[i][j],sizeof(double),1,fp); fwrite(&s00[i][j],sizeof(double),1,fp); fwrite(&alpha[i][j],sizeof(double),1,fp); fwrite(&cut[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairPeriPMB::read_restart(FILE *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(&kspring[i][j],sizeof(double),1,fp); fread(&s00[i][j],sizeof(double),1,fp); fread(&alpha[i][j],sizeof(double),1,fp); fread(&cut[i][j],sizeof(double),1,fp); } MPI_Bcast(&kspring[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&s00[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&alpha[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- */ double PairPeriPMB::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double delx0,dely0,delz0,rsq0; double d_ij,r,dr,rk,vfrac_scale; double *vfrac = atom->vfrac; double **x0 = atom->x0; double **r0 = ((FixPeriNeigh *) modify->fix[ifix_peri])->r0; tagint **partner = ((FixPeriNeigh *) modify->fix[ifix_peri])->partner; int *npartner = ((FixPeriNeigh *) modify->fix[ifix_peri])->npartner; double lc = domain->lattice->xlattice; double half_lc = 0.5*lc; delx0 = x0[i][0] - x0[j][0]; dely0 = x0[i][1] - x0[j][1]; delz0 = x0[i][2] - x0[j][2]; int periodic = domain->xperiodic || domain->yperiodic || domain->zperiodic; if (periodic) domain->minimum_image(delx0,dely0,delz0); rsq0 = delx0*delx0 + dely0*dely0 + delz0*delz0; d_ij = MIN(0.9*sqrt(rsq0),1.35*lc); r = sqrt(rsq); double energy = 0.0; fforce = 0.0; if (r < d_ij) { dr = r - d_ij; rk = (15.0 * kspring[itype][jtype] * vfrac[j]) * (dr / sqrt(cutsq[itype][jtype])); if (r > 0.0) fforce += -(rk/r); energy += 0.5*rk*dr; } int jnum = npartner[i]; for (int jj = 0; jj < jnum; jj++) { if (partner[i][jj] == 0) continue; if (j < 0) continue; if (j == atom->map(partner[i][jj])) { dr = r - r0[i][jj]; if (fabs(dr) < 2.2204e-016) dr = 0.0; if ( (fabs(r0[i][jj] - sqrt(cutsq[itype][jtype]))) <= half_lc) vfrac_scale = (-1.0/(2*half_lc))*(r0[i][jj]) + (1.0 + ((sqrt(cutsq[itype][jtype]) - half_lc)/(2*half_lc))); else vfrac_scale = 1.0; rk = (kspring[itype][jtype] * vfrac[j] * vfrac_scale) * (dr / r0[i][jj]); if (r > 0.0) fforce += -(rk/r); energy += 0.5*rk*dr; } } return energy; } /* ---------------------------------------------------------------------- memory usage of local atom-based arrays ------------------------------------------------------------------------- */ double PairPeriPMB::memory_usage() { double bytes = nmax * sizeof(double); return bytes; } diff --git a/src/PERI/pair_peri_ves.cpp b/src/PERI/pair_peri_ves.cpp index c34fb87e2..87213b5b5 100644 --- a/src/PERI/pair_peri_ves.cpp +++ b/src/PERI/pair_peri_ves.cpp @@ -1,723 +1,723 @@ /* ---------------------------------------------------------------------- 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: Rezwanur Rahman, J.T. Foster (UTSA) ------------------------------------------------------------------------- */ #include #include #include #include "pair_peri_ves.h" #include "atom.h" #include "domain.h" #include "lattice.h" #include "force.h" #include "update.h" #include "modify.h" #include "fix.h" #include "fix_peri_neigh.h" #include "comm.h" #include "neighbor.h" #include "neigh_list.h" #include "memory.h" #include "error.h" #include "update.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ PairPeriVES::PairPeriVES(LAMMPS *lmp) : Pair(lmp) { for (int i = 0; i < 6; i++) virial[i] = 0.0; no_virial_fdotr_compute = 1; single_enable = 0; ifix_peri = -1; nmax = 0; s0_new = NULL; theta = NULL; bulkmodulus = NULL; shearmodulus = NULL; s00 = alpha = NULL; cut = NULL; m_lambdai = NULL; m_taubi = NULL; // set comm size needed by this Pair // comm_reverse not needed comm_forward = 1; } /* ---------------------------------------------------------------------- */ PairPeriVES::~PairPeriVES() { if (ifix_peri >= 0) modify->delete_fix("PERI_NEIGH"); if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(bulkmodulus); memory->destroy(shearmodulus); memory->destroy(s00); memory->destroy(alpha); memory->destroy(cut); memory->destroy(m_lambdai); memory->destroy(m_taubi); memory->destroy(theta); memory->destroy(s0_new); } } /* ---------------------------------------------------------------------- */ void PairPeriVES::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz; double xtmp0,ytmp0,ztmp0,delx0,dely0,delz0,rsq0; double rsq,r,dr,rk,evdwl,fpair,fbond; double deltaed,fbondViscoElastic,fbondFinal; double decay,betai,lambdai,edbNp1,rkNew; int *ilist,*jlist,*numneigh,**firstneigh; double d_ij,delta,stretch; evdwl = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = eflag_global = eflag_atom = 0; double **f = atom->f; double **x = atom->x; int *type = atom->type; int nlocal = atom->nlocal; double timestepsize = update->dt; double *vfrac = atom->vfrac; double *s0 = atom->s0; double **x0 = atom->x0; double **r0 = ((FixPeriNeigh *) modify->fix[ifix_peri])->r0; double **deviatorextention = ((FixPeriNeigh *) modify->fix[ifix_peri])->deviatorextention; double **deviatorBackextention = ((FixPeriNeigh *) modify->fix[ifix_peri])->deviatorBackextention; tagint **partner = ((FixPeriNeigh *) modify->fix[ifix_peri])->partner; int *npartner = ((FixPeriNeigh *) modify->fix[ifix_peri])->npartner; double *wvolume = ((FixPeriNeigh *) modify->fix[ifix_peri])->wvolume; // lc = lattice constant // init_style guarantees it's the same in x, y, and z double lc = domain->lattice->xlattice; double half_lc = 0.5*lc; double vfrac_scale = 1.0; // short-range forces int newton_pair = force->newton_pair; int periodic = domain->xperiodic || domain->yperiodic || domain->zperiodic; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // loop over neighbors of my atoms // need minimg() for x0 difference since not ghosted for (ii = 0; ii < inum; ii++) { i = ilist[ii]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; xtmp0 = x0[i][0]; ytmp0 = x0[i][1]; ztmp0 = x0[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; delx0 = xtmp0 - x0[j][0]; dely0 = ytmp0 - x0[j][1]; delz0 = ztmp0 - x0[j][2]; if (periodic) domain->minimum_image(delx0,dely0,delz0); rsq0 = delx0*delx0 + dely0*dely0 + delz0*delz0; jtype = type[j]; r = sqrt(rsq); // short-range interaction distance based on initial particle position // 0.9 and 1.35 are constants d_ij = MIN(0.9*sqrt(rsq0),1.35*lc); // short-range contact forces // 15 is constant taken from the EMU Theory Manual // Silling, 12 May 2005, p 18 if (r < d_ij) { dr = r - d_ij; // kshort based upon short-range force constant // of the bond-based theory used in PMB model double kshort = (15.0 * 18.0 * bulkmodulus[itype][itype]) / (3.141592653589793 * cutsq[itype][jtype] * cutsq[itype][jtype]); rk = (kshort * vfrac[j]) * (dr / cut[itype][jtype]); if (r > 0.0) fpair = -(rk/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 = 0.5*rk*dr; if (evflag) ev_tally(i,j,nlocal,newton_pair,evdwl,0.0, fpair*vfrac[i],delx,dely,delz); } } } // grow bond forces array if necessary if (atom->nmax > nmax) { memory->destroy(s0_new); memory->destroy(theta); nmax = atom->nmax; memory->create(s0_new,nmax,"pair:s0_new"); memory->create(theta,nmax,"pair:theta"); } // Compute the dilatation on each particle compute_dilatation(); // communicate dilatation (theta) of each particle comm->forward_comm_pair(this); // communicate weighted volume (wvolume) upon every reneighbor if (neighbor->ago == 0) comm->forward_comm_fix(modify->fix[ifix_peri]); // volume-dependent part of the energy if (eflag) { for (i = 0; i < nlocal; i++) { itype = type[i]; if (eflag_global) eng_vdwl += 0.5 * bulkmodulus[itype][itype] * (theta[i] * theta[i]); if (eflag_atom) eatom[i] += 0.5 * bulkmodulus[itype][itype] * (theta[i] * theta[i]); } } // loop over my particles and their partners // partner list contains all bond partners, so I-J appears twice // if bond already broken, skip this partner // first = true if this is first neighbor of particle i bool first; double omega_minus, omega_plus; for (i = 0; i < nlocal; i++) { xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; xtmp0 = x0[i][0]; ytmp0 = x0[i][1]; ztmp0 = x0[i][2]; itype = type[i]; jnum = npartner[i]; first = true; for (jj = 0; jj < jnum; jj++) { if (partner[i][jj] == 0) continue; j = atom->map(partner[i][jj]); // check if lost a partner without first breaking bond if (j < 0) { partner[i][jj] = 0; continue; } // compute force density, add to PD equation of motion delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; if (periodic) domain->minimum_image(delx,dely,delz); rsq = delx*delx + dely*dely + delz*delz; delx0 = xtmp0 - x0[j][0]; dely0 = ytmp0 - x0[j][1]; delz0 = ztmp0 - x0[j][2]; if (periodic) domain->minimum_image(delx0,dely0,delz0); jtype = type[j]; delta = cut[itype][jtype]; r = sqrt(rsq); dr = r - r0[i][jj]; // avoid roundoff errors if (fabs(dr) < 2.2204e-016) dr = 0.0; // scale vfrac[j] if particle j near the horizon if ((fabs(r0[i][jj] - delta)) <= half_lc) vfrac_scale = (-1.0/(2*half_lc))*(r0[i][jj]) + (1.0 + ((delta - half_lc)/(2*half_lc) ) ); else vfrac_scale = 1.0; omega_plus = influence_function(-1.0*delx0,-1.0*dely0,-1.0*delz0); omega_minus = influence_function(delx0,dely0,delz0); rk = ( (3.0 * bulkmodulus[itype][itype]) * vfrac[j] * vfrac_scale * ( (omega_plus * theta[i] / wvolume[i]) + ( omega_minus * theta[j] / wvolume[j] ) ) ) * r0[i][jj]; if (r > 0.0) fbond = -(rk/r); else fbond = 0.0; // for viscoelasticity lambdai=m_lambdai[itype][itype]; double taui = m_taubi[itype][itype]; double c1 = taui/timestepsize; decay=exp(-1.0/c1); betai=1.-c1*(1.-decay); double deviatoric_extension = dr - (theta[i]* r0[i][jj] / 3.0); deltaed = deviatoric_extension-deviatorextention[i][jj]; // back extention at current step edbNp1 = deviatorextention[i][jj]*(1-decay) + deviatorBackextention[i][jj]*decay+betai*deltaed; rkNew = ((1-lambdai)*15.0) * ( shearmodulus[itype][itype] * vfrac[j] * vfrac_scale ) * ( (omega_plus / wvolume[i]) + (omega_minus / wvolume[j]) ) * deviatoric_extension; rkNew += (lambdai*15.0) * ( shearmodulus[itype][itype] * vfrac[j] * vfrac_scale ) * ( (omega_plus / wvolume[i]) + (omega_minus / wvolume[j]) ) * (deviatoric_extension-edbNp1); if (r > 0.0) fbondViscoElastic = -(rkNew/r); else fbondViscoElastic = 0.0; // total Force: elastic + viscoelastic fbondFinal=fbond+fbondViscoElastic; fbond=fbondFinal; f[i][0] += delx*fbond; f[i][1] += dely*fbond; f[i][2] += delz*fbond; // since I-J is double counted, set newton off & use 1/2 factor and I,I if (eflag) evdwl = ((0.5 * 15 * (1 - lambdai) * shearmodulus[itype][itype]/wvolume[i] * omega_plus * deviatoric_extension * deviatoric_extension) + (0.5 * 15 * lambdai * shearmodulus[itype][itype]/wvolume[i] * omega_plus * (deviatoric_extension-edbNp1) * (deviatoric_extension-edbNp1))) * vfrac[j] * vfrac_scale; if (evflag) ev_tally(i,i,nlocal,0,0.5*evdwl,0.0, 0.5*fbond*vfrac[i],delx,dely,delz); // find stretch in bond I-J and break if necessary // use s0 from previous timestep // store current deviatoric extention deviatorextention[i][jj]=deviatoric_extension; deviatorBackextention[i][jj]=edbNp1; stretch = dr / r0[i][jj]; if (stretch > MIN(s0[i],s0[j])) partner[i][jj] = 0; // update s0 for next timestep if (first) s0_new[i] = s00[itype][jtype] - (alpha[itype][jtype] * stretch); else s0_new[i] = MAX(s0_new[i],s00[itype][jtype] - (alpha[itype][jtype] * stretch)); first = false; } } // store new s0 for (i = 0; i < nlocal; i++) s0[i] = s0_new[i]; } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairPeriVES::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(bulkmodulus,n+1,n+1,"pair:bulkmodulus"); memory->create(shearmodulus,n+1,n+1,"pair:shearmodulus"); memory->create(s00,n+1,n+1,"pair:s00"); memory->create(alpha,n+1,n+1,"pair:alpha"); memory->create(cut,n+1,n+1,"pair:cut"); memory->create(m_lambdai,n+1,n+1,"pair:m_lambdai"); memory->create(m_taubi,n+1,n+1,"pair:m_taubi"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairPeriVES::settings(int narg, char **arg) { if (narg) error->all(FLERR,"Illegal pair_style command"); } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairPeriVES::coeff(int narg, char **arg) { if (narg != 9) 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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double bulkmodulus_one = atof(arg[2]); double shearmodulus_one = atof(arg[3]); double cut_one = atof(arg[4]); double s00_one = atof(arg[5]); double alpha_one = atof(arg[6]); double mlambdai_one = atof(arg[7]); double mtaui_one = atof(arg[8]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { bulkmodulus[i][j] = bulkmodulus_one; shearmodulus[i][j] = shearmodulus_one; cut[i][j] = cut_one; s00[i][j] = s00_one; alpha[i][j] = alpha_one; m_lambdai[i][j] = mlambdai_one; m_taubi[i][j] = mtaui_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 PairPeriVES::init_one(int i, int j) { if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set"); bulkmodulus[j][i] = bulkmodulus[i][j]; shearmodulus[j][i] = shearmodulus[i][j]; s00[j][i] = s00[i][j]; alpha[j][i] = alpha[i][j]; cut[j][i] = cut[i][j]; m_lambdai[j][i] = m_lambdai[i][j]; m_taubi[j][i] = m_taubi[i][j]; return cut[i][j]; } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairPeriVES::init_style() { // error checks if (!atom->peri_flag) error->all(FLERR,"Pair style peri requires atom style peri"); if (atom->map_style == 0) error->all(FLERR,"Pair peri requires an atom map, see atom_modify"); if (domain->lattice == NULL) error->all(FLERR,"Pair peri requires a lattice be defined"); if (domain->lattice->xlattice != domain->lattice->ylattice || domain->lattice->xlattice != domain->lattice->zlattice || domain->lattice->ylattice != domain->lattice->zlattice) error->all(FLERR,"Pair peri lattice is not identical in x, y, and z"); // if first init, create Fix needed for storing fixed neighbors if (ifix_peri == -1) { char **fixarg = new char*[3]; fixarg[0] = (char *) "PERI_NEIGH"; fixarg[1] = (char *) "all"; fixarg[2] = (char *) "PERI_NEIGH"; modify->add_fix(3,fixarg); delete [] fixarg; } // find associated PERI_NEIGH fix that must exist // could have changed locations in fix list since created for (int i = 0; i < modify->nfix; i++) if (strcmp(modify->fix[i]->style,"PERI_NEIGH") == 0) ifix_peri = i; if (ifix_peri == -1) error->all(FLERR,"Fix peri neigh does not exist"); neighbor->request(this,instance_me); } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairPeriVES::write_restart(FILE *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(&bulkmodulus[i][j],sizeof(double),1,fp); fwrite(&shearmodulus[i][j],sizeof(double),1,fp); fwrite(&s00[i][j],sizeof(double),1,fp); fwrite(&alpha[i][j],sizeof(double),1,fp); fwrite(&cut[i][j],sizeof(double),1,fp); fwrite(&m_lambdai[i][j],sizeof(double),1,fp); fwrite(&m_taubi[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairPeriVES::read_restart(FILE *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(&bulkmodulus[i][j],sizeof(double),1,fp); fread(&shearmodulus[i][j],sizeof(double),1,fp); fread(&s00[i][j],sizeof(double),1,fp); fread(&alpha[i][j],sizeof(double),1,fp); fread(&cut[i][j],sizeof(double),1,fp); fread(&m_lambdai[i][j],sizeof(double),1,fp); fread(&m_taubi[i][j],sizeof(double),1,fp); } MPI_Bcast(&bulkmodulus[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&shearmodulus[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&s00[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&alpha[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&m_lambdai[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&m_taubi[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- memory usage of local atom-based arrays ------------------------------------------------------------------------- */ double PairPeriVES::memory_usage() { double bytes = 2 * nmax * sizeof(double); return bytes; } /* ---------------------------------------------------------------------- influence function definition ------------------------------------------------------------------------- */ double PairPeriVES::influence_function(double xi_x, double xi_y, double xi_z) { double r = sqrt(xi_x*xi_x + xi_y*xi_y + xi_z*xi_z); double omega; if (fabs(r) < 2.2204e-016) error->one(FLERR,"Divide by 0 in influence function of pair peri/lps"); omega = 1.0/r; return omega; } /* ---------------------------------------------------------------------- */ void PairPeriVES::compute_dilatation() { int i,j,jj,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz; double xtmp0,ytmp0,ztmp0,delx0,dely0,delz0; double rsq,r,dr; double delta; double **x = atom->x; int *type = atom->type; double **x0 = atom->x0; int nlocal = atom->nlocal; double *vfrac = atom->vfrac; double vfrac_scale = 1.0; double lc = domain->lattice->xlattice; double half_lc = 0.5*lc; double **r0 = ((FixPeriNeigh *) modify->fix[ifix_peri])->r0; tagint **partner = ((FixPeriNeigh *) modify->fix[ifix_peri])->partner; int *npartner = ((FixPeriNeigh *) modify->fix[ifix_peri])->npartner; double *wvolume = ((FixPeriNeigh *) modify->fix[ifix_peri])->wvolume; int periodic = domain->xperiodic || domain->yperiodic || domain->zperiodic; // compute the dilatation theta for (i = 0; i < nlocal; i++) { xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; xtmp0 = x0[i][0]; ytmp0 = x0[i][1]; ztmp0 = x0[i][2]; jnum = npartner[i]; theta[i] = 0.0; itype = type[i]; for (jj = 0; jj < jnum; jj++) { // if bond already broken, skip this partner if (partner[i][jj] == 0) continue; // look up local index of this partner particle j = atom->map(partner[i][jj]); // skip if particle is "lost" if (j < 0) continue; // compute force density and add to PD equation of motion delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; if (periodic) domain->minimum_image(delx,dely,delz); rsq = delx*delx + dely*dely + delz*delz; delx0 = xtmp0 - x0[j][0]; dely0 = ytmp0 - x0[j][1]; delz0 = ztmp0 - x0[j][2]; if (periodic) domain->minimum_image(delx0,dely0,delz0); r = sqrt(rsq); dr = r - r0[i][jj]; if (fabs(dr) < 2.2204e-016) dr = 0.0; jtype = type[j]; delta = cut[itype][jtype]; // scale vfrac[j] if particle j near the horizon if ((fabs(r0[i][jj] - delta)) <= half_lc) vfrac_scale = (-1.0/(2*half_lc))*(r0[i][jj]) + (1.0 + ((delta - half_lc)/(2*half_lc) ) ); else vfrac_scale = 1.0; theta[i] += influence_function(delx0, dely0, delz0) * r0[i][jj] * dr * vfrac[j] * vfrac_scale; } // if wvolume[i] is zero, then particle i has no bonds // therefore, the dilatation is set to if (wvolume[i] != 0.0) theta[i] = (3.0/wvolume[i]) * theta[i]; else theta[i] = 0; } } /* ---------------------------------------------------------------------- communication routines ---------------------------------------------------------------------- */ int PairPeriVES::pack_forward_comm(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; m = 0; for (i = 0; i < n; i++) { j = list[i]; buf[m++] = theta[j]; } return m; } /* ---------------------------------------------------------------------- */ void PairPeriVES::unpack_forward_comm(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { theta[i] = buf[m++]; } } diff --git a/src/RIGID/fix_rigid.cpp b/src/RIGID/fix_rigid.cpp index 2f2f84570..8c1ecdacc 100644 --- a/src/RIGID/fix_rigid.cpp +++ b/src/RIGID/fix_rigid.cpp @@ -1,2637 +1,2637 @@ /* ---------------------------------------------------------------------- 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 #include #include #include #include "fix_rigid.h" #include "math_extra.h" #include "atom.h" #include "atom_vec_ellipsoid.h" #include "atom_vec_line.h" #include "atom_vec_tri.h" #include "domain.h" #include "update.h" #include "respa.h" #include "modify.h" #include "group.h" #include "comm.h" #include "random_mars.h" #include "force.h" #include "output.h" #include "math_const.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace FixConst; using namespace MathConst; enum{SINGLE,MOLECULE,GROUP}; enum{NONE,XYZ,XY,YZ,XZ}; enum{ISO,ANISO,TRICLINIC}; #define MAXLINE 1024 #define CHUNK 1024 #define ATTRIBUTE_PERBODY 20 #define TOLERANCE 1.0e-6 #define EPSILON 1.0e-7 #define SINERTIA 0.4 // moment of inertia prefactor for sphere #define EINERTIA 0.4 // moment of inertia prefactor for ellipsoid #define LINERTIA (1.0/12.0) // moment of inertia prefactor for line segment /* ---------------------------------------------------------------------- */ FixRigid::FixRigid(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg) { int i,ibody; scalar_flag = 1; extscalar = 0; time_integrate = 1; rigid_flag = 1; virial_flag = 1; create_attribute = 1; dof_flag = 1; enforce2d_flag = 1; MPI_Comm_rank(world,&me); MPI_Comm_size(world,&nprocs); // perform initial allocation of atom-based arrays // register with Atom class extended = orientflag = dorientflag = 0; body = NULL; xcmimage = NULL; displace = NULL; eflags = NULL; orient = NULL; dorient = NULL; grow_arrays(atom->nmax); atom->add_callback(0); // parse args for rigid body specification // set nbody and body[i] for each atom if (narg < 4) error->all(FLERR,"Illegal fix rigid command"); int iarg; mol2body = NULL; body2mol = NULL; // single rigid body // nbody = 1 // all atoms in fix group are part of body if (strcmp(arg[3],"single") == 0) { rstyle = SINGLE; iarg = 4; nbody = 1; int *mask = atom->mask; int nlocal = atom->nlocal; for (i = 0; i < nlocal; i++) { body[i] = -1; if (mask[i] & groupbit) body[i] = 0; } // each molecule in fix group is a rigid body // maxmol = largest molecule ID // ncount = # of atoms in each molecule (have to sum across procs) // nbody = # of non-zero ncount values // use nall as incremented ptr to set body[] values for each atom } else if (strcmp(arg[3],"molecule") == 0) { rstyle = MOLECULE; iarg = 4; if (atom->molecule_flag == 0) error->all(FLERR,"Fix rigid molecule requires atom attribute molecule"); int *mask = atom->mask; tagint *molecule = atom->molecule; int nlocal = atom->nlocal; tagint maxmol_tag = -1; for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) maxmol_tag = MAX(maxmol_tag,molecule[i]); tagint itmp; MPI_Allreduce(&maxmol_tag,&itmp,1,MPI_LMP_TAGINT,MPI_MAX,world); if (itmp+1 > MAXSMALLINT) error->all(FLERR,"Too many molecules for fix rigid"); maxmol = (int) itmp; int *ncount; memory->create(ncount,maxmol+1,"rigid:ncount"); for (i = 0; i <= maxmol; i++) ncount[i] = 0; for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) ncount[molecule[i]]++; memory->create(mol2body,maxmol+1,"rigid:mol2body"); MPI_Allreduce(ncount,mol2body,maxmol+1,MPI_INT,MPI_SUM,world); nbody = 0; for (i = 0; i <= maxmol; i++) if (mol2body[i]) mol2body[i] = nbody++; else mol2body[i] = -1; memory->create(body2mol,nbody,"rigid:body2mol"); nbody = 0; for (i = 0; i <= maxmol; i++) if (mol2body[i] >= 0) body2mol[nbody++] = i; for (i = 0; i < nlocal; i++) { body[i] = -1; if (mask[i] & groupbit) body[i] = mol2body[molecule[i]]; } memory->destroy(ncount); // each listed group is a rigid body // check if all listed groups exist // an atom must belong to fix group and listed group to be in rigid body // error if atom belongs to more than 1 rigid body } else if (strcmp(arg[3],"group") == 0) { if (narg < 5) error->all(FLERR,"Illegal fix rigid command"); rstyle = GROUP; nbody = force->inumeric(FLERR,arg[4]); if (nbody <= 0) error->all(FLERR,"Illegal fix rigid command"); if (narg < 5+nbody) error->all(FLERR,"Illegal fix rigid command"); iarg = 5+nbody; int *igroups = new int[nbody]; for (ibody = 0; ibody < nbody; ibody++) { igroups[ibody] = group->find(arg[5+ibody]); if (igroups[ibody] == -1) error->all(FLERR,"Could not find fix rigid group ID"); } int *mask = atom->mask; int nlocal = atom->nlocal; int flag = 0; for (i = 0; i < nlocal; i++) { body[i] = -1; if (mask[i] & groupbit) for (ibody = 0; ibody < nbody; ibody++) if (mask[i] & group->bitmask[igroups[ibody]]) { if (body[i] >= 0) flag = 1; body[i] = ibody; } } int flagall; MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,world); if (flagall) error->all(FLERR,"One or more atoms belong to multiple rigid bodies"); delete [] igroups; } else error->all(FLERR,"Illegal fix rigid command"); // error check on nbody if (nbody == 0) error->all(FLERR,"No rigid bodies defined"); // create all nbody-length arrays memory->create(nrigid,nbody,"rigid:nrigid"); memory->create(masstotal,nbody,"rigid:masstotal"); memory->create(xcm,nbody,3,"rigid:xcm"); memory->create(vcm,nbody,3,"rigid:vcm"); memory->create(fcm,nbody,3,"rigid:fcm"); memory->create(inertia,nbody,3,"rigid:inertia"); memory->create(ex_space,nbody,3,"rigid:ex_space"); memory->create(ey_space,nbody,3,"rigid:ey_space"); memory->create(ez_space,nbody,3,"rigid:ez_space"); memory->create(angmom,nbody,3,"rigid:angmom"); memory->create(omega,nbody,3,"rigid:omega"); memory->create(torque,nbody,3,"rigid:torque"); memory->create(quat,nbody,4,"rigid:quat"); memory->create(imagebody,nbody,"rigid:imagebody"); memory->create(fflag,nbody,3,"rigid:fflag"); memory->create(tflag,nbody,3,"rigid:tflag"); memory->create(langextra,nbody,6,"rigid:langextra"); memory->create(sum,nbody,6,"rigid:sum"); memory->create(all,nbody,6,"rigid:all"); memory->create(remapflag,nbody,4,"rigid:remapflag"); // initialize force/torque flags to default = 1.0 // for 2d: fz, tx, ty = 0.0 array_flag = 1; size_array_rows = nbody; size_array_cols = 15; global_freq = 1; extarray = 0; for (i = 0; i < nbody; i++) { fflag[i][0] = fflag[i][1] = fflag[i][2] = 1.0; tflag[i][0] = tflag[i][1] = tflag[i][2] = 1.0; if (domain->dimension == 2) fflag[i][2] = tflag[i][0] = tflag[i][1] = 0.0; } // number of linear rigid bodies is counted later nlinear = 0; // parse optional args int seed; langflag = 0; tstat_flag = 0; pstat_flag = 0; allremap = 1; id_dilate = NULL; t_chain = 10; t_iter = 1; t_order = 3; p_chain = 10; infile = NULL; pcouple = NONE; pstyle = ANISO; dimension = domain->dimension; for (int i = 0; i < 3; i++) { p_start[i] = p_stop[i] = p_period[i] = 0.0; p_flag[i] = 0; } while (iarg < narg) { if (strcmp(arg[iarg],"force") == 0) { if (iarg+5 > narg) error->all(FLERR,"Illegal fix rigid command"); int mlo,mhi; - force->bounds(arg[iarg+1],nbody,mlo,mhi); + force->bounds(FLERR,arg[iarg+1],nbody,mlo,mhi); double xflag,yflag,zflag; if (strcmp(arg[iarg+2],"off") == 0) xflag = 0.0; else if (strcmp(arg[iarg+2],"on") == 0) xflag = 1.0; else error->all(FLERR,"Illegal fix rigid command"); if (strcmp(arg[iarg+3],"off") == 0) yflag = 0.0; else if (strcmp(arg[iarg+3],"on") == 0) yflag = 1.0; else error->all(FLERR,"Illegal fix rigid command"); if (strcmp(arg[iarg+4],"off") == 0) zflag = 0.0; else if (strcmp(arg[iarg+4],"on") == 0) zflag = 1.0; else error->all(FLERR,"Illegal fix rigid command"); if (domain->dimension == 2 && zflag == 1.0) error->all(FLERR,"Fix rigid z force cannot be on for 2d simulation"); int count = 0; for (int m = mlo; m <= mhi; m++) { fflag[m-1][0] = xflag; fflag[m-1][1] = yflag; fflag[m-1][2] = zflag; count++; } if (count == 0) error->all(FLERR,"Illegal fix rigid command"); iarg += 5; } else if (strcmp(arg[iarg],"torque") == 0) { if (iarg+5 > narg) error->all(FLERR,"Illegal fix rigid command"); int mlo,mhi; - force->bounds(arg[iarg+1],nbody,mlo,mhi); + force->bounds(FLERR,arg[iarg+1],nbody,mlo,mhi); double xflag,yflag,zflag; if (strcmp(arg[iarg+2],"off") == 0) xflag = 0.0; else if (strcmp(arg[iarg+2],"on") == 0) xflag = 1.0; else error->all(FLERR,"Illegal fix rigid command"); if (strcmp(arg[iarg+3],"off") == 0) yflag = 0.0; else if (strcmp(arg[iarg+3],"on") == 0) yflag = 1.0; else error->all(FLERR,"Illegal fix rigid command"); if (strcmp(arg[iarg+4],"off") == 0) zflag = 0.0; else if (strcmp(arg[iarg+4],"on") == 0) zflag = 1.0; else error->all(FLERR,"Illegal fix rigid command"); if (domain->dimension == 2 && (xflag == 1.0 || yflag == 1.0)) error->all(FLERR,"Fix rigid xy torque cannot be on for 2d simulation"); int count = 0; for (int m = mlo; m <= mhi; m++) { tflag[m-1][0] = xflag; tflag[m-1][1] = yflag; tflag[m-1][2] = zflag; count++; } if (count == 0) error->all(FLERR,"Illegal fix rigid command"); iarg += 5; } else if (strcmp(arg[iarg],"langevin") == 0) { if (iarg+5 > narg) error->all(FLERR,"Illegal fix rigid command"); if (strcmp(style,"rigid") != 0 && strcmp(style,"rigid/nve") != 0 && strcmp(style,"rigid/omp") != 0 && strcmp(style,"rigid/nve/omp") != 0) error->all(FLERR,"Illegal fix rigid command"); langflag = 1; t_start = force->numeric(FLERR,arg[iarg+1]); t_stop = force->numeric(FLERR,arg[iarg+2]); t_period = force->numeric(FLERR,arg[iarg+3]); seed = force->inumeric(FLERR,arg[iarg+4]); if (t_period <= 0.0) error->all(FLERR,"Fix rigid langevin period must be > 0.0"); if (seed <= 0) error->all(FLERR,"Illegal fix rigid command"); iarg += 5; } else if (strcmp(arg[iarg],"temp") == 0) { if (iarg+4 > narg) error->all(FLERR,"Illegal fix rigid command"); if (strcmp(style,"rigid/nvt") != 0 && strcmp(style,"rigid/npt") != 0 && strcmp(style,"rigid/nvt/omp") != 0 && strcmp(style,"rigid/npt/omp") != 0) error->all(FLERR,"Illegal fix rigid command"); tstat_flag = 1; t_start = force->numeric(FLERR,arg[iarg+1]); t_stop = force->numeric(FLERR,arg[iarg+2]); t_period = force->numeric(FLERR,arg[iarg+3]); iarg += 4; } else if (strcmp(arg[iarg],"iso") == 0) { if (iarg+4 > narg) error->all(FLERR,"Illegal fix rigid command"); if (strcmp(style,"rigid/npt") != 0 && strcmp(style,"rigid/nph") != 0 && strcmp(style,"rigid/npt/omp") != 0 && strcmp(style,"rigid/nph/omp") != 0) error->all(FLERR,"Illegal fix rigid command"); pcouple = XYZ; p_start[0] = p_start[1] = p_start[2] = force->numeric(FLERR,arg[iarg+1]); p_stop[0] = p_stop[1] = p_stop[2] = force->numeric(FLERR,arg[iarg+2]); p_period[0] = p_period[1] = p_period[2] = force->numeric(FLERR,arg[iarg+3]); p_flag[0] = p_flag[1] = p_flag[2] = 1; if (dimension == 2) { p_start[2] = p_stop[2] = p_period[2] = 0.0; p_flag[2] = 0; } iarg += 4; } else if (strcmp(arg[iarg],"aniso") == 0) { if (iarg+4 > narg) error->all(FLERR,"Illegal fix rigid command"); if (strcmp(style,"rigid/npt") != 0 && strcmp(style,"rigid/nph") != 0 && strcmp(style,"rigid/npt/omp") != 0 && strcmp(style,"rigid/nph/omp") != 0) error->all(FLERR,"Illegal fix rigid command"); p_start[0] = p_start[1] = p_start[2] = force->numeric(FLERR,arg[iarg+1]); p_stop[0] = p_stop[1] = p_stop[2] = force->numeric(FLERR,arg[iarg+2]); p_period[0] = p_period[1] = p_period[2] = force->numeric(FLERR,arg[iarg+3]); p_flag[0] = p_flag[1] = p_flag[2] = 1; if (dimension == 2) { p_start[2] = p_stop[2] = p_period[2] = 0.0; p_flag[2] = 0; } iarg += 4; } else if (strcmp(arg[iarg],"x") == 0) { if (iarg+4 > narg) error->all(FLERR,"Illegal fix rigid command"); if (strcmp(style,"rigid/npt") != 0 && strcmp(style,"rigid/nph") != 0 && strcmp(style,"rigid/npt/omp") != 0 && strcmp(style,"rigid/nph/omp") != 0) error->all(FLERR,"Illegal fix rigid command"); p_start[0] = force->numeric(FLERR,arg[iarg+1]); p_stop[0] = force->numeric(FLERR,arg[iarg+2]); p_period[0] = force->numeric(FLERR,arg[iarg+3]); p_flag[0] = 1; iarg += 4; } else if (strcmp(arg[iarg],"y") == 0) { if (iarg+4 > narg) error->all(FLERR,"Illegal fix rigid command"); if (strcmp(style,"rigid/npt") != 0 && strcmp(style,"rigid/nph") != 0 && strcmp(style,"rigid/npt/omp") != 0 && strcmp(style,"rigid/nph/omp") != 0) error->all(FLERR,"Illegal fix rigid command"); p_start[1] = force->numeric(FLERR,arg[iarg+1]); p_stop[1] = force->numeric(FLERR,arg[iarg+2]); p_period[1] = force->numeric(FLERR,arg[iarg+3]); p_flag[1] = 1; iarg += 4; } else if (strcmp(arg[iarg],"z") == 0) { if (iarg+4 > narg) error->all(FLERR,"Illegal fix rigid command"); if (strcmp(style,"rigid/npt") != 0 && strcmp(style,"rigid/nph") != 0 && strcmp(style,"rigid/npt/omp") != 0 && strcmp(style,"rigid/nph/omp") != 0) error->all(FLERR,"Illegal fix rigid command"); p_start[2] = force->numeric(FLERR,arg[iarg+1]); p_stop[2] = force->numeric(FLERR,arg[iarg+2]); p_period[2] = force->numeric(FLERR,arg[iarg+3]); p_flag[2] = 1; iarg += 4; } else if (strcmp(arg[iarg],"couple") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal fix rigid command"); if (strcmp(arg[iarg+1],"xyz") == 0) pcouple = XYZ; else if (strcmp(arg[iarg+1],"xy") == 0) pcouple = XY; else if (strcmp(arg[iarg+1],"yz") == 0) pcouple = YZ; else if (strcmp(arg[iarg+1],"xz") == 0) pcouple = XZ; else if (strcmp(arg[iarg+1],"none") == 0) pcouple = NONE; else error->all(FLERR,"Illegal fix rigid command"); iarg += 2; } else if (strcmp(arg[iarg],"dilate") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal fix rigid npt/nph command"); if (strcmp(arg[iarg+1],"all") == 0) allremap = 1; else { allremap = 0; delete [] id_dilate; int n = strlen(arg[iarg+1]) + 1; id_dilate = new char[n]; strcpy(id_dilate,arg[iarg+1]); int idilate = group->find(id_dilate); if (idilate == -1) error->all(FLERR, "Fix rigid npt/nph dilate group ID does not exist"); } iarg += 2; } else if (strcmp(arg[iarg],"tparam") == 0) { if (iarg+4 > narg) error->all(FLERR,"Illegal fix rigid command"); if (strcmp(style,"rigid/nvt") != 0 && strcmp(style,"rigid/npt") != 0 && strcmp(style,"rigid/nvt/omp") != 0 && strcmp(style,"rigid/npt/omp") != 0) error->all(FLERR,"Illegal fix rigid command"); t_chain = force->inumeric(FLERR,arg[iarg+1]); t_iter = force->inumeric(FLERR,arg[iarg+2]); t_order = force->inumeric(FLERR,arg[iarg+3]); iarg += 4; } else if (strcmp(arg[iarg],"pchain") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal fix rigid command"); if (strcmp(style,"rigid/npt") != 0 && strcmp(style,"rigid/nph") != 0 && strcmp(style,"rigid/npt/omp") != 0 && strcmp(style,"rigid/nph/omp") != 0) error->all(FLERR,"Illegal fix rigid command"); p_chain = force->inumeric(FLERR,arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"infile") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal fix rigid command"); delete [] infile; int n = strlen(arg[iarg+1]) + 1; infile = new char[n]; strcpy(infile,arg[iarg+1]); restart_file = 1; iarg += 2; } else error->all(FLERR,"Illegal fix rigid command"); } // set pstat_flag pstat_flag = 0; for (int i = 0; i < 3; i++) if (p_flag[i]) pstat_flag = 1; if (pcouple == XYZ || (dimension == 2 && pcouple == XY)) pstyle = ISO; else pstyle = ANISO; // initialize Marsaglia RNG with processor-unique seed if (langflag) random = new RanMars(lmp,seed + me); else random = NULL; // initialize vector output quantities in case accessed before run for (i = 0; i < nbody; i++) { xcm[i][0] = xcm[i][1] = xcm[i][2] = 0.0; vcm[i][0] = vcm[i][1] = vcm[i][2] = 0.0; fcm[i][0] = fcm[i][1] = fcm[i][2] = 0.0; torque[i][0] = torque[i][1] = torque[i][2] = 0.0; } // nrigid[n] = # of atoms in Nth rigid body // error if one or zero atoms int *ncount = new int[nbody]; for (ibody = 0; ibody < nbody; ibody++) ncount[ibody] = 0; int nlocal = atom->nlocal; for (i = 0; i < nlocal; i++) if (body[i] >= 0) ncount[body[i]]++; MPI_Allreduce(ncount,nrigid,nbody,MPI_INT,MPI_SUM,world); delete [] ncount; for (ibody = 0; ibody < nbody; ibody++) if (nrigid[ibody] <= 1) error->all(FLERR,"One or zero atoms in rigid body"); // bitmasks for properties of extended particles POINT = 1; SPHERE = 2; ELLIPSOID = 4; LINE = 8; TRIANGLE = 16; DIPOLE = 32; OMEGA = 64; ANGMOM = 128; TORQUE = 256; MINUSPI = -MY_PI; TWOPI = 2.0*MY_PI; // wait to setup bodies until first init() using current atom properties setupflag = 0; // print statistics int nsum = 0; for (ibody = 0; ibody < nbody; ibody++) nsum += nrigid[ibody]; if (me == 0) { if (screen) fprintf(screen,"%d rigid bodies with %d atoms\n",nbody,nsum); if (logfile) fprintf(logfile,"%d rigid bodies with %d atoms\n",nbody,nsum); } } /* ---------------------------------------------------------------------- */ FixRigid::~FixRigid() { // unregister callbacks to this fix from Atom class atom->delete_callback(id,0); delete random; delete [] infile; memory->destroy(mol2body); memory->destroy(body2mol); // delete locally stored per-atom arrays memory->destroy(body); memory->destroy(xcmimage); memory->destroy(displace); memory->destroy(eflags); memory->destroy(orient); memory->destroy(dorient); // delete nbody-length arrays memory->destroy(nrigid); memory->destroy(masstotal); memory->destroy(xcm); memory->destroy(vcm); memory->destroy(fcm); memory->destroy(inertia); memory->destroy(ex_space); memory->destroy(ey_space); memory->destroy(ez_space); memory->destroy(angmom); memory->destroy(omega); memory->destroy(torque); memory->destroy(quat); memory->destroy(imagebody); memory->destroy(fflag); memory->destroy(tflag); memory->destroy(langextra); memory->destroy(sum); memory->destroy(all); memory->destroy(remapflag); } /* ---------------------------------------------------------------------- */ int FixRigid::setmask() { int mask = 0; mask |= INITIAL_INTEGRATE; mask |= FINAL_INTEGRATE; if (langflag) mask |= POST_FORCE; mask |= PRE_NEIGHBOR; mask |= INITIAL_INTEGRATE_RESPA; mask |= FINAL_INTEGRATE_RESPA; return mask; } /* ---------------------------------------------------------------------- */ void FixRigid::init() { int i,ibody; triclinic = domain->triclinic; // atom style pointers to particles that store extra info avec_ellipsoid = (AtomVecEllipsoid *) atom->style_match("ellipsoid"); avec_line = (AtomVecLine *) atom->style_match("line"); avec_tri = (AtomVecTri *) atom->style_match("tri"); // warn if more than one rigid fix int count = 0; for (i = 0; i < modify->nfix; i++) if (strcmp(modify->fix[i]->style,"rigid") == 0) count++; if (count > 1 && me == 0) error->warning(FLERR,"More than one fix rigid"); // error if npt,nph fix comes before rigid fix for (i = 0; i < modify->nfix; i++) { if (strcmp(modify->fix[i]->style,"npt") == 0) break; if (strcmp(modify->fix[i]->style,"nph") == 0) break; } if (i < modify->nfix) { for (int j = i; j < modify->nfix; j++) if (strcmp(modify->fix[j]->style,"rigid") == 0) error->all(FLERR,"Rigid fix must come before NPT/NPH fix"); } // timestep info dtv = update->dt; dtf = 0.5 * update->dt * force->ftm2v; dtq = 0.5 * update->dt; if (strstr(update->integrate_style,"respa")) step_respa = ((Respa *) update->integrate)->step; // setup rigid bodies, using current atom info // only do initialization once, b/c properties may not be re-computable // especially if overlapping particles // do not do dynamic init if read body properties from infile // this is b/c the infile defines the static and dynamic properties // and may not be computable if contain overlapping particles // setup_bodies_static() reads infile itself if (!setupflag) { setup_bodies_static(); if (!infile) setup_bodies_dynamic(); setupflag = 1; } // temperature scale factor double ndof = 0.0; for (ibody = 0; ibody < nbody; ibody++) { ndof += fflag[ibody][0] + fflag[ibody][1] + fflag[ibody][2]; ndof += tflag[ibody][0] + tflag[ibody][1] + tflag[ibody][2]; } ndof -= nlinear; if (ndof > 0.0) tfactor = force->mvv2e / (ndof * force->boltz); else tfactor = 0.0; } /* ---------------------------------------------------------------------- invoke pre_neighbor() to insure body xcmimage flags are reset needed if Verlet::setup::pbc() has remapped/migrated atoms for 2nd run ------------------------------------------------------------------------- */ void FixRigid::setup_pre_neighbor() { pre_neighbor(); } /* ---------------------------------------------------------------------- compute initial fcm and torque on bodies, also initial virial reset all particle velocities to be consistent with vcm and omega ------------------------------------------------------------------------- */ void FixRigid::setup(int vflag) { int i,n,ibody; // fcm = force on center-of-mass of each rigid body double **f = atom->f; int nlocal = atom->nlocal; for (ibody = 0; ibody < nbody; ibody++) for (i = 0; i < 6; i++) sum[ibody][i] = 0.0; for (i = 0; i < nlocal; i++) { if (body[i] < 0) continue; ibody = body[i]; sum[ibody][0] += f[i][0]; sum[ibody][1] += f[i][1]; sum[ibody][2] += f[i][2]; } MPI_Allreduce(sum[0],all[0],6*nbody,MPI_DOUBLE,MPI_SUM,world); for (ibody = 0; ibody < nbody; ibody++) { fcm[ibody][0] = all[ibody][0]; fcm[ibody][1] = all[ibody][1]; fcm[ibody][2] = all[ibody][2]; } // torque = torque on each rigid body double **x = atom->x; double dx,dy,dz; double unwrap[3]; for (ibody = 0; ibody < nbody; ibody++) for (i = 0; i < 6; i++) sum[ibody][i] = 0.0; for (i = 0; i < nlocal; i++) { if (body[i] < 0) continue; ibody = body[i]; domain->unmap(x[i],xcmimage[i],unwrap); dx = unwrap[0] - xcm[ibody][0]; dy = unwrap[1] - xcm[ibody][1]; dz = unwrap[2] - xcm[ibody][2]; sum[ibody][0] += dy * f[i][2] - dz * f[i][1]; sum[ibody][1] += dz * f[i][0] - dx * f[i][2]; sum[ibody][2] += dx * f[i][1] - dy * f[i][0]; } // extended particles add their torque to torque of body if (extended) { double **torque_one = atom->torque; for (i = 0; i < nlocal; i++) { if (body[i] < 0) continue; ibody = body[i]; if (eflags[i] & TORQUE) { sum[ibody][0] += torque_one[i][0]; sum[ibody][1] += torque_one[i][1]; sum[ibody][2] += torque_one[i][2]; } } } MPI_Allreduce(sum[0],all[0],6*nbody,MPI_DOUBLE,MPI_SUM,world); for (ibody = 0; ibody < nbody; ibody++) { torque[ibody][0] = all[ibody][0]; torque[ibody][1] = all[ibody][1]; torque[ibody][2] = all[ibody][2]; } // zero langextra in case Langevin thermostat not used // no point to calling post_force() here since langextra // is only added to fcm/torque in final_integrate() for (ibody = 0; ibody < nbody; ibody++) for (i = 0; i < 6; i++) langextra[ibody][i] = 0.0; // virial setup before call to set_v if (vflag) v_setup(vflag); else evflag = 0; // set velocities from angmom & omega for (ibody = 0; ibody < nbody; ibody++) MathExtra::angmom_to_omega(angmom[ibody],ex_space[ibody],ey_space[ibody], ez_space[ibody],inertia[ibody],omega[ibody]); set_v(); // guesstimate virial as 2x the set_v contribution if (vflag_global) for (n = 0; n < 6; n++) virial[n] *= 2.0; if (vflag_atom) { for (i = 0; i < nlocal; i++) for (n = 0; n < 6; n++) vatom[i][n] *= 2.0; } } /* ---------------------------------------------------------------------- */ void FixRigid::initial_integrate(int vflag) { double dtfm; for (int ibody = 0; ibody < nbody; ibody++) { // update vcm by 1/2 step dtfm = dtf / masstotal[ibody]; vcm[ibody][0] += dtfm * fcm[ibody][0] * fflag[ibody][0]; vcm[ibody][1] += dtfm * fcm[ibody][1] * fflag[ibody][1]; vcm[ibody][2] += dtfm * fcm[ibody][2] * fflag[ibody][2]; // update xcm by full step xcm[ibody][0] += dtv * vcm[ibody][0]; xcm[ibody][1] += dtv * vcm[ibody][1]; xcm[ibody][2] += dtv * vcm[ibody][2]; // update angular momentum by 1/2 step angmom[ibody][0] += dtf * torque[ibody][0] * tflag[ibody][0]; angmom[ibody][1] += dtf * torque[ibody][1] * tflag[ibody][1]; angmom[ibody][2] += dtf * torque[ibody][2] * tflag[ibody][2]; // compute omega at 1/2 step from angmom at 1/2 step and current q // update quaternion a full step via Richardson iteration // returns new normalized quaternion, also updated omega at 1/2 step // update ex,ey,ez to reflect new quaternion MathExtra::angmom_to_omega(angmom[ibody],ex_space[ibody],ey_space[ibody], ez_space[ibody],inertia[ibody],omega[ibody]); MathExtra::richardson(quat[ibody],angmom[ibody],omega[ibody], inertia[ibody],dtq); MathExtra::q_to_exyz(quat[ibody], ex_space[ibody],ey_space[ibody],ez_space[ibody]); } // virial setup before call to set_xv if (vflag) v_setup(vflag); else evflag = 0; // set coords/orient and velocity/rotation of atoms in rigid bodies // from quarternion and omega set_xv(); } /* ---------------------------------------------------------------------- apply Langevin thermostat to all 6 DOF of rigid bodies computed by proc 0, broadcast to other procs unlike fix langevin, this stores extra force in extra arrays, which are added in when final_integrate() calculates a new fcm/torque ------------------------------------------------------------------------- */ void FixRigid::post_force(int vflag) { if (me == 0) { double gamma1,gamma2; double delta = update->ntimestep - update->beginstep; if (delta != 0.0) delta /= update->endstep - update->beginstep; t_target = t_start + delta * (t_stop-t_start); double tsqrt = sqrt(t_target); double boltz = force->boltz; double dt = update->dt; double mvv2e = force->mvv2e; double ftm2v = force->ftm2v; for (int i = 0; i < nbody; i++) { gamma1 = -masstotal[i] / t_period / ftm2v; gamma2 = sqrt(masstotal[i]) * tsqrt * sqrt(24.0*boltz/t_period/dt/mvv2e) / ftm2v; langextra[i][0] = gamma1*vcm[i][0] + gamma2*(random->uniform()-0.5); langextra[i][1] = gamma1*vcm[i][1] + gamma2*(random->uniform()-0.5); langextra[i][2] = gamma1*vcm[i][2] + gamma2*(random->uniform()-0.5); gamma1 = -1.0 / t_period / ftm2v; gamma2 = tsqrt * sqrt(24.0*boltz/t_period/dt/mvv2e) / ftm2v; langextra[i][3] = inertia[i][0]*gamma1*omega[i][0] + sqrt(inertia[i][0])*gamma2*(random->uniform()-0.5); langextra[i][4] = inertia[i][1]*gamma1*omega[i][1] + sqrt(inertia[i][1])*gamma2*(random->uniform()-0.5); langextra[i][5] = inertia[i][2]*gamma1*omega[i][2] + sqrt(inertia[i][2])*gamma2*(random->uniform()-0.5); } } MPI_Bcast(&langextra[0][0],6*nbody,MPI_DOUBLE,0,world); } /* ---------------------------------------------------------------------- called from FixEnforce2d post_force() for 2d problems zero all body values that should be zero for 2d model ------------------------------------------------------------------------- */ void FixRigid::enforce2d() { for (int ibody = 0; ibody < nbody; ibody++) { xcm[ibody][2] = 0.0; vcm[ibody][2] = 0.0; fcm[ibody][2] = 0.0; torque[ibody][0] = 0.0; torque[ibody][1] = 0.0; angmom[ibody][0] = 0.0; angmom[ibody][1] = 0.0; omega[ibody][0] = 0.0; omega[ibody][1] = 0.0; if (langflag) { langextra[ibody][2] = 0.0; langextra[ibody][3] = 0.0; langextra[ibody][4] = 0.0; } } } /* ---------------------------------------------------------------------- */ void FixRigid::final_integrate() { int i,ibody; double dtfm; // sum over atoms to get force and torque on rigid body double **x = atom->x; double **f = atom->f; int nlocal = atom->nlocal; double dx,dy,dz; double unwrap[3]; for (ibody = 0; ibody < nbody; ibody++) for (i = 0; i < 6; i++) sum[ibody][i] = 0.0; for (i = 0; i < nlocal; i++) { if (body[i] < 0) continue; ibody = body[i]; sum[ibody][0] += f[i][0]; sum[ibody][1] += f[i][1]; sum[ibody][2] += f[i][2]; domain->unmap(x[i],xcmimage[i],unwrap); dx = unwrap[0] - xcm[ibody][0]; dy = unwrap[1] - xcm[ibody][1]; dz = unwrap[2] - xcm[ibody][2]; sum[ibody][3] += dy*f[i][2] - dz*f[i][1]; sum[ibody][4] += dz*f[i][0] - dx*f[i][2]; sum[ibody][5] += dx*f[i][1] - dy*f[i][0]; } // extended particles add their torque to torque of body if (extended) { double **torque_one = atom->torque; for (i = 0; i < nlocal; i++) { if (body[i] < 0) continue; ibody = body[i]; if (eflags[i] & TORQUE) { sum[ibody][3] += torque_one[i][0]; sum[ibody][4] += torque_one[i][1]; sum[ibody][5] += torque_one[i][2]; } } } MPI_Allreduce(sum[0],all[0],6*nbody,MPI_DOUBLE,MPI_SUM,world); // update vcm and angmom // include Langevin thermostat forces // fflag,tflag = 0 for some dimensions in 2d for (ibody = 0; ibody < nbody; ibody++) { fcm[ibody][0] = all[ibody][0] + langextra[ibody][0]; fcm[ibody][1] = all[ibody][1] + langextra[ibody][1]; fcm[ibody][2] = all[ibody][2] + langextra[ibody][2]; torque[ibody][0] = all[ibody][3] + langextra[ibody][3]; torque[ibody][1] = all[ibody][4] + langextra[ibody][4]; torque[ibody][2] = all[ibody][5] + langextra[ibody][5]; // update vcm by 1/2 step dtfm = dtf / masstotal[ibody]; vcm[ibody][0] += dtfm * fcm[ibody][0] * fflag[ibody][0]; vcm[ibody][1] += dtfm * fcm[ibody][1] * fflag[ibody][1]; vcm[ibody][2] += dtfm * fcm[ibody][2] * fflag[ibody][2]; // update angular momentum by 1/2 step angmom[ibody][0] += dtf * torque[ibody][0] * tflag[ibody][0]; angmom[ibody][1] += dtf * torque[ibody][1] * tflag[ibody][1]; angmom[ibody][2] += dtf * torque[ibody][2] * tflag[ibody][2]; MathExtra::angmom_to_omega(angmom[ibody],ex_space[ibody],ey_space[ibody], ez_space[ibody],inertia[ibody],omega[ibody]); } // set velocity/rotation of atoms in rigid bodies // virial is already setup from initial_integrate set_v(); } /* ---------------------------------------------------------------------- */ void FixRigid::initial_integrate_respa(int vflag, int ilevel, int iloop) { dtv = step_respa[ilevel]; dtf = 0.5 * step_respa[ilevel] * force->ftm2v; dtq = 0.5 * step_respa[ilevel]; if (ilevel == 0) initial_integrate(vflag); else final_integrate(); } /* ---------------------------------------------------------------------- */ void FixRigid::final_integrate_respa(int ilevel, int iloop) { dtf = 0.5 * step_respa[ilevel] * force->ftm2v; final_integrate(); } /* ---------------------------------------------------------------------- remap xcm of each rigid body back into periodic simulation box done during pre_neighbor so will be after call to pbc() and after fix_deform::pre_exchange() may have flipped box use domain->remap() in case xcm is far away from box due to first-time definition of rigid body in setup_bodies_static() or due to box flip also adjust imagebody = rigid body image flags, due to xcm remap also reset body xcmimage flags of all atoms in bodies xcmimage flags are relative to xcm so that body can be unwrapped if don't do this, would need xcm to move with true image flags then a body could end up very far away from box set_xv() will then compute huge displacements every step to reset coords of all body atoms to be back inside the box, ditto for triclinic box flip, which causes numeric problems ------------------------------------------------------------------------- */ void FixRigid::pre_neighbor() { for (int ibody = 0; ibody < nbody; ibody++) domain->remap(xcm[ibody],imagebody[ibody]); image_shift(); } /* ---------------------------------------------------------------------- reset body xcmimage flags of atoms in bodies xcmimage flags are relative to xcm so that body can be unwrapped xcmimage = true image flag - imagebody flag ------------------------------------------------------------------------- */ void FixRigid::image_shift() { int ibody; imageint tdim,bdim,xdim[3]; imageint *image = atom->image; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) { if (body[i] < 0) continue; ibody = body[i]; tdim = image[i] & IMGMASK; bdim = imagebody[ibody] & IMGMASK; xdim[0] = IMGMAX + tdim - bdim; tdim = (image[i] >> IMGBITS) & IMGMASK; bdim = (imagebody[ibody] >> IMGBITS) & IMGMASK; xdim[1] = IMGMAX + tdim - bdim; tdim = image[i] >> IMG2BITS; bdim = imagebody[ibody] >> IMG2BITS; xdim[2] = IMGMAX + tdim - bdim; xcmimage[i] = (xdim[2] << IMG2BITS) | (xdim[1] << IMGBITS) | xdim[0]; } } /* ---------------------------------------------------------------------- count # of DOF removed by rigid bodies for atoms in igroup return total count of DOF ------------------------------------------------------------------------- */ int FixRigid::dof(int tgroup) { // cannot count DOF correctly unless setup_bodies_static() has been called if (!setupflag) { if (comm->me == 0) error->warning(FLERR,"Cannot count rigid body degrees-of-freedom " "before bodies are initialized"); return 0; } int tgroupbit = group->bitmask[tgroup]; // nall = # of point particles in each rigid body // mall = # of finite-size particles in each rigid body // particles must also be in temperature group int *mask = atom->mask; int nlocal = atom->nlocal; int *ncount = new int[nbody]; int *mcount = new int[nbody]; for (int ibody = 0; ibody < nbody; ibody++) ncount[ibody] = mcount[ibody] = 0; for (int i = 0; i < nlocal; i++) if (body[i] >= 0 && mask[i] & tgroupbit) { // do not count point particles or point dipoles as extended particles // a spheroid dipole will be counted as extended if (extended && (eflags[i] & ~(POINT | DIPOLE))) mcount[body[i]]++; else ncount[body[i]]++; } int *nall = new int[nbody]; int *mall = new int[nbody]; MPI_Allreduce(ncount,nall,nbody,MPI_INT,MPI_SUM,world); MPI_Allreduce(mcount,mall,nbody,MPI_INT,MPI_SUM,world); // warn if nall+mall != nrigid for any body included in temperature group int flag = 0; for (int ibody = 0; ibody < nbody; ibody++) { if (nall[ibody]+mall[ibody] > 0 && nall[ibody]+mall[ibody] != nrigid[ibody]) flag = 1; } if (flag && me == 0) error->warning(FLERR,"Computing temperature of portions of rigid bodies"); // remove appropriate DOFs for each rigid body wholly in temperature group // N = # of point particles in body // M = # of finite-size particles in body // 3d body has 3N + 6M dof to start with // 2d body has 2N + 3M dof to start with // 3d point-particle body with all non-zero I should have 6 dof, remove 3N-6 // 3d point-particle body (linear) with a 0 I should have 5 dof, remove 3N-5 // 2d point-particle body should have 3 dof, remove 2N-3 // 3d body with any finite-size M should have 6 dof, remove (3N+6M) - 6 // 2d body with any finite-size M should have 3 dof, remove (2N+3M) - 3 int n = 0; nlinear = 0; if (domain->dimension == 3) { for (int ibody = 0; ibody < nbody; ibody++) if (nall[ibody]+mall[ibody] == nrigid[ibody]) { n += 3*nall[ibody] + 6*mall[ibody] - 6; if (inertia[ibody][0] == 0.0 || inertia[ibody][1] == 0.0 || inertia[ibody][2] == 0.0) { n++; nlinear++; } } } else if (domain->dimension == 2) { for (int ibody = 0; ibody < nbody; ibody++) if (nall[ibody]+mall[ibody] == nrigid[ibody]) n += 2*nall[ibody] + 3*mall[ibody] - 3; } delete [] ncount; delete [] mcount; delete [] nall; delete [] mall; return n; } /* ---------------------------------------------------------------------- adjust xcm of each rigid body due to box deformation called by various fixes that change box size/shape flag = 0/1 means map from box to lamda coords or vice versa ------------------------------------------------------------------------- */ void FixRigid::deform(int flag) { if (flag == 0) for (int ibody = 0; ibody < nbody; ibody++) domain->x2lamda(xcm[ibody],xcm[ibody]); else for (int ibody = 0; ibody < nbody; ibody++) domain->lamda2x(xcm[ibody],xcm[ibody]); } /* ---------------------------------------------------------------------- set space-frame coords and velocity of each atom in each rigid body set orientation and rotation of extended particles x = Q displace + Xcm, mapped back to periodic box v = Vcm + (W cross (x - Xcm)) ------------------------------------------------------------------------- */ void FixRigid::set_xv() { int ibody; int xbox,ybox,zbox; double x0,x1,x2,v0,v1,v2,fc0,fc1,fc2,massone; double xy,xz,yz; double ione[3],exone[3],eyone[3],ezone[3],vr[6],p[3][3]; double **x = atom->x; double **v = atom->v; double **f = atom->f; double *rmass = atom->rmass; double *mass = atom->mass; int *type = atom->type; int nlocal = atom->nlocal; double xprd = domain->xprd; double yprd = domain->yprd; double zprd = domain->zprd; if (triclinic) { xy = domain->xy; xz = domain->xz; yz = domain->yz; } // set x and v of each atom for (int i = 0; i < nlocal; i++) { if (body[i] < 0) continue; ibody = body[i]; xbox = (xcmimage[i] & IMGMASK) - IMGMAX; ybox = (xcmimage[i] >> IMGBITS & IMGMASK) - IMGMAX; zbox = (xcmimage[i] >> IMG2BITS) - IMGMAX; // save old positions and velocities for virial if (evflag) { if (triclinic == 0) { x0 = x[i][0] + xbox*xprd; x1 = x[i][1] + ybox*yprd; x2 = x[i][2] + zbox*zprd; } else { x0 = x[i][0] + xbox*xprd + ybox*xy + zbox*xz; x1 = x[i][1] + ybox*yprd + zbox*yz; x2 = x[i][2] + zbox*zprd; } v0 = v[i][0]; v1 = v[i][1]; v2 = v[i][2]; } // x = displacement from center-of-mass, based on body orientation // v = vcm + omega around center-of-mass MathExtra::matvec(ex_space[ibody],ey_space[ibody], ez_space[ibody],displace[i],x[i]); v[i][0] = omega[ibody][1]*x[i][2] - omega[ibody][2]*x[i][1] + vcm[ibody][0]; v[i][1] = omega[ibody][2]*x[i][0] - omega[ibody][0]*x[i][2] + vcm[ibody][1]; v[i][2] = omega[ibody][0]*x[i][1] - omega[ibody][1]*x[i][0] + vcm[ibody][2]; // add center of mass to displacement // map back into periodic box via xbox,ybox,zbox // for triclinic, add in box tilt factors as well if (triclinic == 0) { x[i][0] += xcm[ibody][0] - xbox*xprd; x[i][1] += xcm[ibody][1] - ybox*yprd; x[i][2] += xcm[ibody][2] - zbox*zprd; } else { x[i][0] += xcm[ibody][0] - xbox*xprd - ybox*xy - zbox*xz; x[i][1] += xcm[ibody][1] - ybox*yprd - zbox*yz; x[i][2] += xcm[ibody][2] - zbox*zprd; } // virial = unwrapped coords dotted into body constraint force // body constraint force = implied force due to v change minus f external // assume f does not include forces internal to body // 1/2 factor b/c final_integrate contributes other half // assume per-atom contribution is due to constraint force on that atom if (evflag) { if (rmass) massone = rmass[i]; else massone = mass[type[i]]; fc0 = massone*(v[i][0] - v0)/dtf - f[i][0]; fc1 = massone*(v[i][1] - v1)/dtf - f[i][1]; fc2 = massone*(v[i][2] - v2)/dtf - f[i][2]; vr[0] = 0.5*x0*fc0; vr[1] = 0.5*x1*fc1; vr[2] = 0.5*x2*fc2; vr[3] = 0.5*x0*fc1; vr[4] = 0.5*x0*fc2; vr[5] = 0.5*x1*fc2; v_tally(1,&i,1.0,vr); } } // set orientation, omega, angmom of each extended particle if (extended) { double theta_body,theta; double *shape,*quatatom,*inertiaatom; AtomVecEllipsoid::Bonus *ebonus; if (avec_ellipsoid) ebonus = avec_ellipsoid->bonus; AtomVecLine::Bonus *lbonus; if (avec_line) lbonus = avec_line->bonus; AtomVecTri::Bonus *tbonus; if (avec_tri) tbonus = avec_tri->bonus; double **omega_one = atom->omega; double **angmom_one = atom->angmom; double **mu = atom->mu; int *ellipsoid = atom->ellipsoid; int *line = atom->line; int *tri = atom->tri; for (int i = 0; i < nlocal; i++) { if (body[i] < 0) continue; ibody = body[i]; if (eflags[i] & SPHERE) { omega_one[i][0] = omega[ibody][0]; omega_one[i][1] = omega[ibody][1]; omega_one[i][2] = omega[ibody][2]; } else if (eflags[i] & ELLIPSOID) { shape = ebonus[ellipsoid[i]].shape; quatatom = ebonus[ellipsoid[i]].quat; MathExtra::quatquat(quat[ibody],orient[i],quatatom); MathExtra::qnormalize(quatatom); ione[0] = EINERTIA*rmass[i] * (shape[1]*shape[1] + shape[2]*shape[2]); ione[1] = EINERTIA*rmass[i] * (shape[0]*shape[0] + shape[2]*shape[2]); ione[2] = EINERTIA*rmass[i] * (shape[0]*shape[0] + shape[1]*shape[1]); MathExtra::q_to_exyz(quatatom,exone,eyone,ezone); MathExtra::omega_to_angmom(omega[ibody],exone,eyone,ezone,ione, angmom_one[i]); } else if (eflags[i] & LINE) { if (quat[ibody][3] >= 0.0) theta_body = 2.0*acos(quat[ibody][0]); else theta_body = -2.0*acos(quat[ibody][0]); theta = orient[i][0] + theta_body; while (theta <= MINUSPI) theta += TWOPI; while (theta > MY_PI) theta -= TWOPI; lbonus[line[i]].theta = theta; omega_one[i][0] = omega[ibody][0]; omega_one[i][1] = omega[ibody][1]; omega_one[i][2] = omega[ibody][2]; } else if (eflags[i] & TRIANGLE) { inertiaatom = tbonus[tri[i]].inertia; quatatom = tbonus[tri[i]].quat; MathExtra::quatquat(quat[ibody],orient[i],quatatom); MathExtra::qnormalize(quatatom); MathExtra::q_to_exyz(quatatom,exone,eyone,ezone); MathExtra::omega_to_angmom(omega[ibody],exone,eyone,ezone, inertiaatom,angmom_one[i]); } if (eflags[i] & DIPOLE) { MathExtra::quat_to_mat(quat[ibody],p); MathExtra::matvec(p,dorient[i],mu[i]); MathExtra::snormalize3(mu[i][3],mu[i],mu[i]); } } } } /* ---------------------------------------------------------------------- set space-frame velocity of each atom in a rigid body set omega and angmom of extended particles v = Vcm + (W cross (x - Xcm)) ------------------------------------------------------------------------- */ void FixRigid::set_v() { int xbox,ybox,zbox; double x0,x1,x2,v0,v1,v2,fc0,fc1,fc2,massone; double xy,xz,yz; double ione[3],exone[3],eyone[3],ezone[3],delta[3],vr[6]; double **x = atom->x; double **v = atom->v; double **f = atom->f; double *rmass = atom->rmass; double *mass = atom->mass; int *type = atom->type; int nlocal = atom->nlocal; double xprd = domain->xprd; double yprd = domain->yprd; double zprd = domain->zprd; if (triclinic) { xy = domain->xy; xz = domain->xz; yz = domain->yz; } // set v of each atom for (int i = 0; i < nlocal; i++) { if (body[i] < 0) continue; const int ibody = body[i]; MathExtra::matvec(ex_space[ibody],ey_space[ibody], ez_space[ibody],displace[i],delta); // save old velocities for virial if (evflag) { v0 = v[i][0]; v1 = v[i][1]; v2 = v[i][2]; } v[i][0] = omega[ibody][1]*delta[2] - omega[ibody][2]*delta[1] + vcm[ibody][0]; v[i][1] = omega[ibody][2]*delta[0] - omega[ibody][0]*delta[2] + vcm[ibody][1]; v[i][2] = omega[ibody][0]*delta[1] - omega[ibody][1]*delta[0] + vcm[ibody][2]; // virial = unwrapped coords dotted into body constraint force // body constraint force = implied force due to v change minus f external // assume f does not include forces internal to body // 1/2 factor b/c initial_integrate contributes other half // assume per-atom contribution is due to constraint force on that atom if (evflag) { if (rmass) massone = rmass[i]; else massone = mass[type[i]]; fc0 = massone*(v[i][0] - v0)/dtf - f[i][0]; fc1 = massone*(v[i][1] - v1)/dtf - f[i][1]; fc2 = massone*(v[i][2] - v2)/dtf - f[i][2]; xbox = (xcmimage[i] & IMGMASK) - IMGMAX; ybox = (xcmimage[i] >> IMGBITS & IMGMASK) - IMGMAX; zbox = (xcmimage[i] >> IMG2BITS) - IMGMAX; if (triclinic == 0) { x0 = x[i][0] + xbox*xprd; x1 = x[i][1] + ybox*yprd; x2 = x[i][2] + zbox*zprd; } else { x0 = x[i][0] + xbox*xprd + ybox*xy + zbox*xz; x1 = x[i][1] + ybox*yprd + zbox*yz; x2 = x[i][2] + zbox*zprd; } vr[0] = 0.5*x0*fc0; vr[1] = 0.5*x1*fc1; vr[2] = 0.5*x2*fc2; vr[3] = 0.5*x0*fc1; vr[4] = 0.5*x0*fc2; vr[5] = 0.5*x1*fc2; v_tally(1,&i,1.0,vr); } } // set omega, angmom of each extended particle if (extended) { double *shape,*quatatom,*inertiaatom; AtomVecEllipsoid::Bonus *ebonus; if (avec_ellipsoid) ebonus = avec_ellipsoid->bonus; AtomVecTri::Bonus *tbonus; if (avec_tri) tbonus = avec_tri->bonus; double **omega_one = atom->omega; double **angmom_one = atom->angmom; int *ellipsoid = atom->ellipsoid; int *tri = atom->tri; for (int i = 0; i < nlocal; i++) { if (body[i] < 0) continue; const int ibody = body[i]; if (eflags[i] & SPHERE) { omega_one[i][0] = omega[ibody][0]; omega_one[i][1] = omega[ibody][1]; omega_one[i][2] = omega[ibody][2]; } else if (eflags[i] & ELLIPSOID) { shape = ebonus[ellipsoid[i]].shape; quatatom = ebonus[ellipsoid[i]].quat; ione[0] = EINERTIA*rmass[i] * (shape[1]*shape[1] + shape[2]*shape[2]); ione[1] = EINERTIA*rmass[i] * (shape[0]*shape[0] + shape[2]*shape[2]); ione[2] = EINERTIA*rmass[i] * (shape[0]*shape[0] + shape[1]*shape[1]); MathExtra::q_to_exyz(quatatom,exone,eyone,ezone); MathExtra::omega_to_angmom(omega[ibody],exone,eyone,ezone,ione, angmom_one[i]); } else if (eflags[i] & LINE) { omega_one[i][0] = omega[ibody][0]; omega_one[i][1] = omega[ibody][1]; omega_one[i][2] = omega[ibody][2]; } else if (eflags[i] & TRIANGLE) { inertiaatom = tbonus[tri[i]].inertia; quatatom = tbonus[tri[i]].quat; MathExtra::q_to_exyz(quatatom,exone,eyone,ezone); MathExtra::omega_to_angmom(omega[ibody],exone,eyone,ezone, inertiaatom,angmom_one[i]); } } } } /* ---------------------------------------------------------------------- one-time initialization of static rigid body attributes sets extended flags, masstotal, center-of-mass sets Cartesian and diagonalized inertia tensor sets body image flags may read some properties from infile ------------------------------------------------------------------------- */ void FixRigid::setup_bodies_static() { int i,ibody; // extended = 1 if any particle in a rigid body is finite size // or has a dipole moment extended = orientflag = dorientflag = 0; AtomVecEllipsoid::Bonus *ebonus; if (avec_ellipsoid) ebonus = avec_ellipsoid->bonus; AtomVecLine::Bonus *lbonus; if (avec_line) lbonus = avec_line->bonus; AtomVecTri::Bonus *tbonus; if (avec_tri) tbonus = avec_tri->bonus; double **mu = atom->mu; double *radius = atom->radius; double *rmass = atom->rmass; double *mass = atom->mass; int *ellipsoid = atom->ellipsoid; int *line = atom->line; int *tri = atom->tri; int *type = atom->type; int nlocal = atom->nlocal; if (atom->radius_flag || atom->ellipsoid_flag || atom->line_flag || atom->tri_flag || atom->mu_flag) { int flag = 0; for (i = 0; i < nlocal; i++) { if (body[i] < 0) continue; if (radius && radius[i] > 0.0) flag = 1; if (ellipsoid && ellipsoid[i] >= 0) flag = 1; if (line && line[i] >= 0) flag = 1; if (tri && tri[i] >= 0) flag = 1; if (mu && mu[i][3] > 0.0) flag = 1; } MPI_Allreduce(&flag,&extended,1,MPI_INT,MPI_MAX,world); } // grow extended arrays and set extended flags for each particle // orientflag = 4 if any particle stores ellipsoid or tri orientation // orientflag = 1 if any particle stores line orientation // dorientflag = 1 if any particle stores dipole orientation if (extended) { if (atom->ellipsoid_flag) orientflag = 4; if (atom->line_flag) orientflag = 1; if (atom->tri_flag) orientflag = 4; if (atom->mu_flag) dorientflag = 1; grow_arrays(atom->nmax); for (i = 0; i < nlocal; i++) { eflags[i] = 0; if (body[i] < 0) continue; // set to POINT or SPHERE or ELLIPSOID or LINE if (radius && radius[i] > 0.0) { eflags[i] |= SPHERE; eflags[i] |= OMEGA; eflags[i] |= TORQUE; } else if (ellipsoid && ellipsoid[i] >= 0) { eflags[i] |= ELLIPSOID; eflags[i] |= ANGMOM; eflags[i] |= TORQUE; } else if (line && line[i] >= 0) { eflags[i] |= LINE; eflags[i] |= OMEGA; eflags[i] |= TORQUE; } else if (tri && tri[i] >= 0) { eflags[i] |= TRIANGLE; eflags[i] |= ANGMOM; eflags[i] |= TORQUE; } else eflags[i] |= POINT; // set DIPOLE if atom->mu and mu[3] > 0.0 if (atom->mu_flag && mu[i][3] > 0.0) eflags[i] |= DIPOLE; } } // set body xcmimage flags = true image flags imageint *image = atom->image; for (i = 0; i < nlocal; i++) if (body[i] >= 0) xcmimage[i] = image[i]; else xcmimage[i] = 0; // compute masstotal & center-of-mass of each rigid body // error if image flag is not 0 in a non-periodic dim double **x = atom->x; int *periodicity = domain->periodicity; double xprd = domain->xprd; double yprd = domain->yprd; double zprd = domain->zprd; double xy = domain->xy; double xz = domain->xz; double yz = domain->yz; for (ibody = 0; ibody < nbody; ibody++) for (i = 0; i < 6; i++) sum[ibody][i] = 0.0; int xbox,ybox,zbox; double massone,xunwrap,yunwrap,zunwrap; for (i = 0; i < nlocal; i++) { if (body[i] < 0) continue; ibody = body[i]; xbox = (xcmimage[i] & IMGMASK) - IMGMAX; ybox = (xcmimage[i] >> IMGBITS & IMGMASK) - IMGMAX; zbox = (xcmimage[i] >> IMG2BITS) - IMGMAX; if (rmass) massone = rmass[i]; else massone = mass[type[i]]; if ((xbox && !periodicity[0]) || (ybox && !periodicity[1]) || (zbox && !periodicity[2])) error->one(FLERR,"Fix rigid atom has non-zero image flag " "in a non-periodic dimension"); if (triclinic == 0) { xunwrap = x[i][0] + xbox*xprd; yunwrap = x[i][1] + ybox*yprd; zunwrap = x[i][2] + zbox*zprd; } else { xunwrap = x[i][0] + xbox*xprd + ybox*xy + zbox*xz; yunwrap = x[i][1] + ybox*yprd + zbox*yz; zunwrap = x[i][2] + zbox*zprd; } sum[ibody][0] += xunwrap * massone; sum[ibody][1] += yunwrap * massone; sum[ibody][2] += zunwrap * massone; sum[ibody][3] += massone; } MPI_Allreduce(sum[0],all[0],6*nbody,MPI_DOUBLE,MPI_SUM,world); for (ibody = 0; ibody < nbody; ibody++) { masstotal[ibody] = all[ibody][3]; xcm[ibody][0] = all[ibody][0]/masstotal[ibody]; xcm[ibody][1] = all[ibody][1]/masstotal[ibody]; xcm[ibody][2] = all[ibody][2]/masstotal[ibody]; } // set vcm, angmom = 0.0 in case infile is used // and doesn't overwrite all body's values // since setup_bodies_dynamic() will not be called for (ibody = 0; ibody < nbody; ibody++) { vcm[ibody][0] = vcm[ibody][1] = vcm[ibody][2] = 0.0; angmom[ibody][0] = angmom[ibody][1] = angmom[ibody][2] = 0.0; } // set rigid body image flags to default values for (ibody = 0; ibody < nbody; ibody++) imagebody[ibody] = ((imageint) IMGMAX << IMG2BITS) | ((imageint) IMGMAX << IMGBITS) | IMGMAX; // overwrite masstotal, center-of-mass, image flags with file values // inbody[i] = 0/1 if Ith rigid body is initialized by file int *inbody; if (infile) { memory->create(inbody,nbody,"rigid:inbody"); for (ibody = 0; ibody < nbody; ibody++) inbody[ibody] = 0; readfile(0,masstotal,xcm,vcm,angmom,imagebody,inbody); } // remap the xcm of each body back into simulation box // and reset body and atom xcmimage flags via pre_neighbor() pre_neighbor(); // compute 6 moments of inertia of each body in Cartesian reference frame // dx,dy,dz = coords relative to center-of-mass // symmetric 3x3 inertia tensor stored in Voigt notation as 6-vector double dx,dy,dz; for (ibody = 0; ibody < nbody; ibody++) for (i = 0; i < 6; i++) sum[ibody][i] = 0.0; for (i = 0; i < nlocal; i++) { if (body[i] < 0) continue; ibody = body[i]; xbox = (xcmimage[i] & IMGMASK) - IMGMAX; ybox = (xcmimage[i] >> IMGBITS & IMGMASK) - IMGMAX; zbox = (xcmimage[i] >> IMG2BITS) - IMGMAX; if (triclinic == 0) { xunwrap = x[i][0] + xbox*xprd; yunwrap = x[i][1] + ybox*yprd; zunwrap = x[i][2] + zbox*zprd; } else { xunwrap = x[i][0] + xbox*xprd + ybox*xy + zbox*xz; yunwrap = x[i][1] + ybox*yprd + zbox*yz; zunwrap = x[i][2] + zbox*zprd; } dx = xunwrap - xcm[ibody][0]; dy = yunwrap - xcm[ibody][1]; dz = zunwrap - xcm[ibody][2]; if (rmass) massone = rmass[i]; else massone = mass[type[i]]; sum[ibody][0] += massone * (dy*dy + dz*dz); sum[ibody][1] += massone * (dx*dx + dz*dz); sum[ibody][2] += massone * (dx*dx + dy*dy); sum[ibody][3] -= massone * dy*dz; sum[ibody][4] -= massone * dx*dz; sum[ibody][5] -= massone * dx*dy; } // extended particles may contribute extra terms to moments of inertia if (extended) { double ivec[6]; double *shape,*quatatom,*inertiaatom; double length,theta; for (i = 0; i < nlocal; i++) { if (body[i] < 0) continue; ibody = body[i]; if (rmass) massone = rmass[i]; else massone = mass[type[i]]; if (eflags[i] & SPHERE) { sum[ibody][0] += SINERTIA*massone * radius[i]*radius[i]; sum[ibody][1] += SINERTIA*massone * radius[i]*radius[i]; sum[ibody][2] += SINERTIA*massone * radius[i]*radius[i]; } else if (eflags[i] & ELLIPSOID) { shape = ebonus[ellipsoid[i]].shape; quatatom = ebonus[ellipsoid[i]].quat; MathExtra::inertia_ellipsoid(shape,quatatom,massone,ivec); sum[ibody][0] += ivec[0]; sum[ibody][1] += ivec[1]; sum[ibody][2] += ivec[2]; sum[ibody][3] += ivec[3]; sum[ibody][4] += ivec[4]; sum[ibody][5] += ivec[5]; } else if (eflags[i] & LINE) { length = lbonus[line[i]].length; theta = lbonus[line[i]].theta; MathExtra::inertia_line(length,theta,massone,ivec); sum[ibody][0] += ivec[0]; sum[ibody][1] += ivec[1]; sum[ibody][2] += ivec[2]; sum[ibody][3] += ivec[3]; sum[ibody][4] += ivec[4]; sum[ibody][5] += ivec[5]; } else if (eflags[i] & TRIANGLE) { inertiaatom = tbonus[tri[i]].inertia; quatatom = tbonus[tri[i]].quat; MathExtra::inertia_triangle(inertiaatom,quatatom,massone,ivec); sum[ibody][0] += ivec[0]; sum[ibody][1] += ivec[1]; sum[ibody][2] += ivec[2]; sum[ibody][3] += ivec[3]; sum[ibody][4] += ivec[4]; sum[ibody][5] += ivec[5]; } } } MPI_Allreduce(sum[0],all[0],6*nbody,MPI_DOUBLE,MPI_SUM,world); // overwrite Cartesian inertia tensor with file values if (infile) readfile(1,NULL,all,NULL,NULL,NULL,inbody); // diagonalize inertia tensor for each body via Jacobi rotations // inertia = 3 eigenvalues = principal moments of inertia // evectors and exzy_space = 3 evectors = principal axes of rigid body int ierror; double cross[3]; double tensor[3][3],evectors[3][3]; for (ibody = 0; ibody < nbody; ibody++) { tensor[0][0] = all[ibody][0]; tensor[1][1] = all[ibody][1]; tensor[2][2] = all[ibody][2]; tensor[1][2] = tensor[2][1] = all[ibody][3]; tensor[0][2] = tensor[2][0] = all[ibody][4]; tensor[0][1] = tensor[1][0] = all[ibody][5]; ierror = MathExtra::jacobi(tensor,inertia[ibody],evectors); if (ierror) error->all(FLERR, "Insufficient Jacobi rotations for rigid body"); ex_space[ibody][0] = evectors[0][0]; ex_space[ibody][1] = evectors[1][0]; ex_space[ibody][2] = evectors[2][0]; ey_space[ibody][0] = evectors[0][1]; ey_space[ibody][1] = evectors[1][1]; ey_space[ibody][2] = evectors[2][1]; ez_space[ibody][0] = evectors[0][2]; ez_space[ibody][1] = evectors[1][2]; ez_space[ibody][2] = evectors[2][2]; // if any principal moment < scaled EPSILON, set to 0.0 double max; max = MAX(inertia[ibody][0],inertia[ibody][1]); max = MAX(max,inertia[ibody][2]); if (inertia[ibody][0] < EPSILON*max) inertia[ibody][0] = 0.0; if (inertia[ibody][1] < EPSILON*max) inertia[ibody][1] = 0.0; if (inertia[ibody][2] < EPSILON*max) inertia[ibody][2] = 0.0; // enforce 3 evectors as a right-handed coordinate system // flip 3rd vector if needed MathExtra::cross3(ex_space[ibody],ey_space[ibody],cross); if (MathExtra::dot3(cross,ez_space[ibody]) < 0.0) MathExtra::negate3(ez_space[ibody]); // create initial quaternion MathExtra::exyz_to_q(ex_space[ibody],ey_space[ibody],ez_space[ibody], quat[ibody]); } // displace = initial atom coords in basis of principal axes // set displace = 0.0 for atoms not in any rigid body // for extended particles, set their orientation wrt to rigid body double qc[4],delta[3]; double *quatatom; double theta_body; for (i = 0; i < nlocal; i++) { if (body[i] < 0) { displace[i][0] = displace[i][1] = displace[i][2] = 0.0; continue; } ibody = body[i]; xbox = (xcmimage[i] & IMGMASK) - IMGMAX; ybox = (xcmimage[i] >> IMGBITS & IMGMASK) - IMGMAX; zbox = (xcmimage[i] >> IMG2BITS) - IMGMAX; if (triclinic == 0) { xunwrap = x[i][0] + xbox*xprd; yunwrap = x[i][1] + ybox*yprd; zunwrap = x[i][2] + zbox*zprd; } else { xunwrap = x[i][0] + xbox*xprd + ybox*xy + zbox*xz; yunwrap = x[i][1] + ybox*yprd + zbox*yz; zunwrap = x[i][2] + zbox*zprd; } delta[0] = xunwrap - xcm[ibody][0]; delta[1] = yunwrap - xcm[ibody][1]; delta[2] = zunwrap - xcm[ibody][2]; MathExtra::transpose_matvec(ex_space[ibody],ey_space[ibody], ez_space[ibody],delta,displace[i]); if (extended) { if (eflags[i] & ELLIPSOID) { quatatom = ebonus[ellipsoid[i]].quat; MathExtra::qconjugate(quat[ibody],qc); MathExtra::quatquat(qc,quatatom,orient[i]); MathExtra::qnormalize(orient[i]); } else if (eflags[i] & LINE) { if (quat[ibody][3] >= 0.0) theta_body = 2.0*acos(quat[ibody][0]); else theta_body = -2.0*acos(quat[ibody][0]); orient[i][0] = lbonus[line[i]].theta - theta_body; while (orient[i][0] <= MINUSPI) orient[i][0] += TWOPI; while (orient[i][0] > MY_PI) orient[i][0] -= TWOPI; if (orientflag == 4) orient[i][1] = orient[i][2] = orient[i][3] = 0.0; } else if (eflags[i] & TRIANGLE) { quatatom = tbonus[tri[i]].quat; MathExtra::qconjugate(quat[ibody],qc); MathExtra::quatquat(qc,quatatom,orient[i]); MathExtra::qnormalize(orient[i]); } else if (orientflag == 4) { orient[i][0] = orient[i][1] = orient[i][2] = orient[i][3] = 0.0; } else if (orientflag == 1) orient[i][0] = 0.0; if (eflags[i] & DIPOLE) { MathExtra::transpose_matvec(ex_space[ibody],ey_space[ibody], ez_space[ibody],mu[i],dorient[i]); MathExtra::snormalize3(mu[i][3],dorient[i],dorient[i]); } else if (dorientflag) dorient[i][0] = dorient[i][1] = dorient[i][2] = 0.0; } } // test for valid principal moments & axes // recompute moments of inertia around new axes // 3 diagonal moments should equal principal moments // 3 off-diagonal moments should be 0.0 // extended particles may contribute extra terms to moments of inertia for (ibody = 0; ibody < nbody; ibody++) for (i = 0; i < 6; i++) sum[ibody][i] = 0.0; for (i = 0; i < nlocal; i++) { if (body[i] < 0) continue; ibody = body[i]; if (rmass) massone = rmass[i]; else massone = mass[type[i]]; sum[ibody][0] += massone * (displace[i][1]*displace[i][1] + displace[i][2]*displace[i][2]); sum[ibody][1] += massone * (displace[i][0]*displace[i][0] + displace[i][2]*displace[i][2]); sum[ibody][2] += massone * (displace[i][0]*displace[i][0] + displace[i][1]*displace[i][1]); sum[ibody][3] -= massone * displace[i][1]*displace[i][2]; sum[ibody][4] -= massone * displace[i][0]*displace[i][2]; sum[ibody][5] -= massone * displace[i][0]*displace[i][1]; } if (extended) { double ivec[6]; double *shape,*inertiaatom; double length; for (i = 0; i < nlocal; i++) { if (body[i] < 0) continue; ibody = body[i]; if (rmass) massone = rmass[i]; else massone = mass[type[i]]; if (eflags[i] & SPHERE) { sum[ibody][0] += SINERTIA*massone * radius[i]*radius[i]; sum[ibody][1] += SINERTIA*massone * radius[i]*radius[i]; sum[ibody][2] += SINERTIA*massone * radius[i]*radius[i]; } else if (eflags[i] & ELLIPSOID) { shape = ebonus[ellipsoid[i]].shape; MathExtra::inertia_ellipsoid(shape,orient[i],massone,ivec); sum[ibody][0] += ivec[0]; sum[ibody][1] += ivec[1]; sum[ibody][2] += ivec[2]; sum[ibody][3] += ivec[3]; sum[ibody][4] += ivec[4]; sum[ibody][5] += ivec[5]; } else if (eflags[i] & LINE) { length = lbonus[line[i]].length; MathExtra::inertia_line(length,orient[i][0],massone,ivec); sum[ibody][0] += ivec[0]; sum[ibody][1] += ivec[1]; sum[ibody][2] += ivec[2]; sum[ibody][3] += ivec[3]; sum[ibody][4] += ivec[4]; sum[ibody][5] += ivec[5]; } else if (eflags[i] & TRIANGLE) { inertiaatom = tbonus[tri[i]].inertia; MathExtra::inertia_triangle(inertiaatom,orient[i],massone,ivec); sum[ibody][0] += ivec[0]; sum[ibody][1] += ivec[1]; sum[ibody][2] += ivec[2]; sum[ibody][3] += ivec[3]; sum[ibody][4] += ivec[4]; sum[ibody][5] += ivec[5]; } } } MPI_Allreduce(sum[0],all[0],6*nbody,MPI_DOUBLE,MPI_SUM,world); // error check that re-computed moments of inertia match diagonalized ones // do not do test for bodies with params read from infile double norm; for (ibody = 0; ibody < nbody; ibody++) { if (infile && inbody[ibody]) continue; if (inertia[ibody][0] == 0.0) { if (fabs(all[ibody][0]) > TOLERANCE) error->all(FLERR,"Fix rigid: Bad principal moments"); } else { if (fabs((all[ibody][0]-inertia[ibody][0])/inertia[ibody][0]) > TOLERANCE) error->all(FLERR,"Fix rigid: Bad principal moments"); } if (inertia[ibody][1] == 0.0) { if (fabs(all[ibody][1]) > TOLERANCE) error->all(FLERR,"Fix rigid: Bad principal moments"); } else { if (fabs((all[ibody][1]-inertia[ibody][1])/inertia[ibody][1]) > TOLERANCE) error->all(FLERR,"Fix rigid: Bad principal moments"); } if (inertia[ibody][2] == 0.0) { if (fabs(all[ibody][2]) > TOLERANCE) error->all(FLERR,"Fix rigid: Bad principal moments"); } else { if (fabs((all[ibody][2]-inertia[ibody][2])/inertia[ibody][2]) > TOLERANCE) error->all(FLERR,"Fix rigid: Bad principal moments"); } norm = (inertia[ibody][0] + inertia[ibody][1] + inertia[ibody][2]) / 3.0; if (fabs(all[ibody][3]/norm) > TOLERANCE || fabs(all[ibody][4]/norm) > TOLERANCE || fabs(all[ibody][5]/norm) > TOLERANCE) error->all(FLERR,"Fix rigid: Bad principal moments"); } if (infile) memory->destroy(inbody); } /* ---------------------------------------------------------------------- one-time initialization of dynamic rigid body attributes set vcm and angmom, computed explicitly from constituent particles not done if body properites read from file, e.g. for overlapping particles ------------------------------------------------------------------------- */ void FixRigid::setup_bodies_dynamic() { int i,ibody; double massone,radone; // vcm = velocity of center-of-mass of each rigid body // angmom = angular momentum of each rigid body double **x = atom->x; double **v = atom->v; double *rmass = atom->rmass; double *mass = atom->mass; int *type = atom->type; int nlocal = atom->nlocal; double dx,dy,dz; double unwrap[3]; for (ibody = 0; ibody < nbody; ibody++) for (i = 0; i < 6; i++) sum[ibody][i] = 0.0; for (i = 0; i < nlocal; i++) { if (body[i] < 0) continue; ibody = body[i]; if (rmass) massone = rmass[i]; else massone = mass[type[i]]; sum[ibody][0] += v[i][0] * massone; sum[ibody][1] += v[i][1] * massone; sum[ibody][2] += v[i][2] * massone; domain->unmap(x[i],xcmimage[i],unwrap); dx = unwrap[0] - xcm[ibody][0]; dy = unwrap[1] - xcm[ibody][1]; dz = unwrap[2] - xcm[ibody][2]; sum[ibody][3] += dy * massone*v[i][2] - dz * massone*v[i][1]; sum[ibody][4] += dz * massone*v[i][0] - dx * massone*v[i][2]; sum[ibody][5] += dx * massone*v[i][1] - dy * massone*v[i][0]; } // extended particles add their rotation to angmom of body if (extended) { AtomVecLine::Bonus *lbonus; if (avec_line) lbonus = avec_line->bonus; double **omega_one = atom->omega; double **angmom_one = atom->angmom; double *radius = atom->radius; int *line = atom->line; for (i = 0; i < nlocal; i++) { if (body[i] < 0) continue; ibody = body[i]; if (eflags[i] & OMEGA) { if (eflags[i] & SPHERE) { radone = radius[i]; sum[ibody][3] += SINERTIA*rmass[i] * radone*radone * omega_one[i][0]; sum[ibody][4] += SINERTIA*rmass[i] * radone*radone * omega_one[i][1]; sum[ibody][5] += SINERTIA*rmass[i] * radone*radone * omega_one[i][2]; } else if (eflags[i] & LINE) { radone = lbonus[line[i]].length; sum[ibody][5] += LINERTIA*rmass[i] * radone*radone * omega_one[i][2]; } } if (eflags[i] & ANGMOM) { sum[ibody][3] += angmom_one[i][0]; sum[ibody][4] += angmom_one[i][1]; sum[ibody][5] += angmom_one[i][2]; } } } MPI_Allreduce(sum[0],all[0],6*nbody,MPI_DOUBLE,MPI_SUM,world); // normalize velocity of COM for (ibody = 0; ibody < nbody; ibody++) { vcm[ibody][0] = all[ibody][0]/masstotal[ibody]; vcm[ibody][1] = all[ibody][1]/masstotal[ibody]; vcm[ibody][2] = all[ibody][2]/masstotal[ibody]; angmom[ibody][0] = all[ibody][3]; angmom[ibody][1] = all[ibody][4]; angmom[ibody][2] = all[ibody][5]; } } /* ---------------------------------------------------------------------- read per rigid body info from user-provided file which = 0 to read everthing except 6 moments of inertia which = 1 to read 6 moments of inertia flag inbody = 0 for bodies whose info is read from file nlines = # of lines of rigid body info one line = rigid-ID mass xcm ycm zcm ixx iyy izz ixy ixz iyz vxcm vycm vzcm lx ly lz ix iy iz ------------------------------------------------------------------------- */ void FixRigid::readfile(int which, double *vec, double **array1, double **array2, double **array3, imageint *ivec, int *inbody) { int j,nchunk,id,eofflag,xbox,ybox,zbox; int nlines; FILE *fp; char *eof,*start,*next,*buf; char line[MAXLINE]; if (me == 0) { fp = fopen(infile,"r"); if (fp == NULL) { char str[128]; sprintf(str,"Cannot open fix rigid infile %s",infile); error->one(FLERR,str); } while (1) { eof = fgets(line,MAXLINE,fp); if (eof == NULL) error->one(FLERR,"Unexpected end of fix rigid file"); start = &line[strspn(line," \t\n\v\f\r")]; if (*start != '\0' && *start != '#') break; } sscanf(line,"%d",&nlines); } MPI_Bcast(&nlines,1,MPI_INT,0,world); if (nlines == 0) error->all(FLERR,"Fix rigid file has no lines"); char *buffer = new char[CHUNK*MAXLINE]; char **values = new char*[ATTRIBUTE_PERBODY]; int nread = 0; while (nread < nlines) { nchunk = MIN(nlines-nread,CHUNK); eofflag = comm->read_lines_from_file(fp,nchunk,MAXLINE,buffer); if (eofflag) error->all(FLERR,"Unexpected end of fix rigid file"); buf = buffer; next = strchr(buf,'\n'); *next = '\0'; int nwords = atom->count_words(buf); *next = '\n'; if (nwords != ATTRIBUTE_PERBODY) error->all(FLERR,"Incorrect rigid body format in fix rigid file"); // loop over lines of rigid body attributes // tokenize the line into values // id = rigid body ID // use ID as-is for SINGLE, as mol-ID for MOLECULE, as-is for GROUP // for which = 0, store all but inertia in vecs and arrays // for which = 1, store inertia tensor array, invert 3,4,5 values to Voigt for (int i = 0; i < nchunk; i++) { next = strchr(buf,'\n'); values[0] = strtok(buf," \t\n\r\f"); for (j = 1; j < nwords; j++) values[j] = strtok(NULL," \t\n\r\f"); id = atoi(values[0]); if (rstyle == MOLECULE) { if (id <= 0 || id > maxmol) error->all(FLERR,"Invalid rigid body ID in fix rigid file"); id = mol2body[id]; } else id--; if (id < 0 || id >= nbody) error->all(FLERR,"Invalid rigid body ID in fix rigid file"); inbody[id] = 1; if (which == 0) { vec[id] = atof(values[1]); array1[id][0] = atof(values[2]); array1[id][1] = atof(values[3]); array1[id][2] = atof(values[4]); array2[id][0] = atof(values[11]); array2[id][1] = atof(values[12]); array2[id][2] = atof(values[13]); array3[id][0] = atof(values[14]); array3[id][1] = atof(values[15]); array3[id][2] = atof(values[16]); xbox = atoi(values[17]); ybox = atoi(values[18]); zbox = atoi(values[19]); ivec[id] = ((imageint) (xbox + IMGMAX) & IMGMASK) | (((imageint) (ybox + IMGMAX) & IMGMASK) << IMGBITS) | (((imageint) (zbox + IMGMAX) & IMGMASK) << IMG2BITS); } else { array1[id][0] = atof(values[5]); array1[id][1] = atof(values[6]); array1[id][2] = atof(values[7]); array1[id][3] = atof(values[10]); array1[id][4] = atof(values[9]); array1[id][5] = atof(values[8]); } buf = next + 1; } nread += nchunk; } if (me == 0) fclose(fp); delete [] buffer; delete [] values; } /* ---------------------------------------------------------------------- write out restart info for mass, COM, inertia tensor, image flags to file identical format to infile option, so info can be read in when restarting only proc 0 writes list of global bodies to file ------------------------------------------------------------------------- */ void FixRigid::write_restart_file(char *file) { if (me) return; char outfile[128]; sprintf(outfile,"%s.rigid",file); FILE *fp = fopen(outfile,"w"); if (fp == NULL) { char str[128]; sprintf(str,"Cannot open fix rigid restart file %s",outfile); error->one(FLERR,str); } fprintf(fp,"# fix rigid mass, COM, inertia tensor info for " "%d bodies on timestep " BIGINT_FORMAT "\n\n", nbody,update->ntimestep); fprintf(fp,"%d\n",nbody); // compute I tensor against xyz axes from diagonalized I and current quat // Ispace = P Idiag P_transpose // P is stored column-wise in exyz_space int xbox,ybox,zbox; double p[3][3],pdiag[3][3],ispace[3][3]; int id; for (int i = 0; i < nbody; i++) { if (rstyle == SINGLE || rstyle == GROUP) id = i; else id = body2mol[i]; MathExtra::col2mat(ex_space[i],ey_space[i],ez_space[i],p); MathExtra::times3_diag(p,inertia[i],pdiag); MathExtra::times3_transpose(pdiag,p,ispace); xbox = (imagebody[i] & IMGMASK) - IMGMAX; ybox = (imagebody[i] >> IMGBITS & IMGMASK) - IMGMAX; zbox = (imagebody[i] >> IMG2BITS) - IMGMAX; fprintf(fp,"%d %-1.16e %-1.16e %-1.16e %-1.16e " "%-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e " "%-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e " "%d %d %d\n", id,masstotal[i],xcm[i][0],xcm[i][1],xcm[i][2], ispace[0][0],ispace[1][1],ispace[2][2], ispace[0][1],ispace[0][2],ispace[1][2], vcm[i][0],vcm[i][1],vcm[i][2], angmom[i][0],angmom[i][1],angmom[i][2], xbox,ybox,zbox); } fclose(fp); } /* ---------------------------------------------------------------------- memory usage of local atom-based arrays ------------------------------------------------------------------------- */ double FixRigid::memory_usage() { int nmax = atom->nmax; double bytes = nmax * sizeof(int); bytes += nmax * sizeof(imageint); bytes += nmax*3 * sizeof(double); bytes += maxvatom*6 * sizeof(double); // vatom if (extended) { bytes += nmax * sizeof(int); if (orientflag) bytes = nmax*orientflag * sizeof(double); if (dorientflag) bytes = nmax*3 * sizeof(double); } return bytes; } /* ---------------------------------------------------------------------- allocate local atom-based arrays ------------------------------------------------------------------------- */ void FixRigid::grow_arrays(int nmax) { memory->grow(body,nmax,"rigid:body"); memory->grow(xcmimage,nmax,"rigid:xcmimage"); memory->grow(displace,nmax,3,"rigid:displace"); if (extended) { memory->grow(eflags,nmax,"rigid:eflags"); if (orientflag) memory->grow(orient,nmax,orientflag,"rigid:orient"); if (dorientflag) memory->grow(dorient,nmax,3,"rigid:dorient"); } // check for regrow of vatom // must be done whether per-atom virial is accumulated on this step or not // b/c this is only time grow_array() may be called // need to regrow b/c vatom is calculated before and after atom migration if (nmax > maxvatom) { maxvatom = atom->nmax; memory->grow(vatom,maxvatom,6,"fix:vatom"); } } /* ---------------------------------------------------------------------- copy values within local atom-based arrays ------------------------------------------------------------------------- */ void FixRigid::copy_arrays(int i, int j, int delflag) { body[j] = body[i]; xcmimage[j] = xcmimage[i]; displace[j][0] = displace[i][0]; displace[j][1] = displace[i][1]; displace[j][2] = displace[i][2]; if (extended) { eflags[j] = eflags[i]; for (int k = 0; k < orientflag; k++) orient[j][k] = orient[i][k]; if (dorientflag) { dorient[j][0] = dorient[i][0]; dorient[j][1] = dorient[i][1]; dorient[j][2] = dorient[i][2]; } } // must also copy vatom if per-atom virial calculated on this timestep // since vatom is calculated before and after atom migration if (vflag_atom) for (int k = 0; k < 6; k++) vatom[j][k] = vatom[i][k]; } /* ---------------------------------------------------------------------- initialize one atom's array values, called when atom is created ------------------------------------------------------------------------- */ void FixRigid::set_arrays(int i) { body[i] = -1; xcmimage[i] = 0; displace[i][0] = 0.0; displace[i][1] = 0.0; displace[i][2] = 0.0; // must also zero vatom if per-atom virial calculated on this timestep // since vatom is calculated before and after atom migration if (vflag_atom) for (int k = 0; k < 6; k++) vatom[i][k] = 0.0; } /* ---------------------------------------------------------------------- pack values in local atom-based arrays for exchange with another proc ------------------------------------------------------------------------- */ int FixRigid::pack_exchange(int i, double *buf) { buf[0] = ubuf(body[i]).d; buf[1] = ubuf(xcmimage[i]).d; buf[2] = displace[i][0]; buf[3] = displace[i][1]; buf[4] = displace[i][2]; if (!extended) return 5; int m = 5; buf[m++] = eflags[i]; for (int j = 0; j < orientflag; j++) buf[m++] = orient[i][j]; if (dorientflag) { buf[m++] = dorient[i][0]; buf[m++] = dorient[i][1]; buf[m++] = dorient[i][2]; } // must also pack vatom if per-atom virial calculated on this timestep // since vatom is calculated before and after atom migration if (vflag_atom) for (int k = 0; k < 6; k++) buf[m++] = vatom[i][k]; return m; } /* ---------------------------------------------------------------------- unpack values in local atom-based arrays from exchange with another proc ------------------------------------------------------------------------- */ int FixRigid::unpack_exchange(int nlocal, double *buf) { body[nlocal] = (int) ubuf(buf[0]).i; xcmimage[nlocal] = (imageint) ubuf(buf[1]).i; displace[nlocal][0] = buf[2]; displace[nlocal][1] = buf[3]; displace[nlocal][2] = buf[4]; if (!extended) return 5; int m = 5; eflags[nlocal] = static_cast (buf[m++]); for (int j = 0; j < orientflag; j++) orient[nlocal][j] = buf[m++]; if (dorientflag) { dorient[nlocal][0] = buf[m++]; dorient[nlocal][1] = buf[m++]; dorient[nlocal][2] = buf[m++]; } // must also unpack vatom if per-atom virial calculated on this timestep // since vatom is calculated before and after atom migration if (vflag_atom) for (int k = 0; k < 6; k++) vatom[nlocal][k] = buf[m++]; return m; } /* ---------------------------------------------------------------------- */ void FixRigid::reset_dt() { dtv = update->dt; dtf = 0.5 * update->dt * force->ftm2v; dtq = 0.5 * update->dt; } /* ---------------------------------------------------------------------- zero linear momentum of each rigid body set Vcm to 0.0, then reset velocities of particles via set_v() ------------------------------------------------------------------------- */ void FixRigid::zero_momentum() { for (int ibody = 0; ibody < nbody; ibody++) vcm[ibody][0] = vcm[ibody][1] = vcm[ibody][2] = 0.0; evflag = 0; set_v(); } /* ---------------------------------------------------------------------- zero angular momentum of each rigid body set angmom/omega to 0.0, then reset velocities of particles via set_v() ------------------------------------------------------------------------- */ void FixRigid::zero_rotation() { for (int ibody = 0; ibody < nbody; ibody++) { angmom[ibody][0] = angmom[ibody][1] = angmom[ibody][2] = 0.0; omega[ibody][0] = omega[ibody][1] = omega[ibody][2] = 0.0; } evflag = 0; set_v(); } /* ---------------------------------------------------------------------- return temperature of collection of rigid bodies non-active DOF are removed by fflag/tflag and in tfactor ------------------------------------------------------------------------- */ double FixRigid::compute_scalar() { double wbody[3],rot[3][3]; double t = 0.0; for (int i = 0; i < nbody; i++) { t += masstotal[i] * (fflag[i][0]*vcm[i][0]*vcm[i][0] + fflag[i][1]*vcm[i][1]*vcm[i][1] + fflag[i][2]*vcm[i][2]*vcm[i][2]); // wbody = angular velocity in body frame MathExtra::quat_to_mat(quat[i],rot); MathExtra::transpose_matvec(rot,angmom[i],wbody); if (inertia[i][0] == 0.0) wbody[0] = 0.0; else wbody[0] /= inertia[i][0]; if (inertia[i][1] == 0.0) wbody[1] = 0.0; else wbody[1] /= inertia[i][1]; if (inertia[i][2] == 0.0) wbody[2] = 0.0; else wbody[2] /= inertia[i][2]; t += tflag[i][0]*inertia[i][0]*wbody[0]*wbody[0] + tflag[i][1]*inertia[i][1]*wbody[1]*wbody[1] + tflag[i][2]*inertia[i][2]*wbody[2]*wbody[2]; } t *= tfactor; return t; } /* ---------------------------------------------------------------------- */ void *FixRigid::extract(const char *str, int &dim) { if (strcmp(str,"body") == 0) { dim = 1; return body; } if (strcmp(str,"masstotal") == 0) { dim = 1; return masstotal; } if (strcmp(str,"t_target") == 0) { dim = 0; return &t_target; } return NULL; } /* ---------------------------------------------------------------------- return translational KE for all rigid bodies KE = 1/2 M Vcm^2 ------------------------------------------------------------------------- */ double FixRigid::extract_ke() { double ke = 0.0; for (int i = 0; i < nbody; i++) ke += masstotal[i] * (vcm[i][0]*vcm[i][0] + vcm[i][1]*vcm[i][1] + vcm[i][2]*vcm[i][2]); return 0.5*ke; } /* ---------------------------------------------------------------------- return rotational KE for all rigid bodies Erotational = 1/2 I wbody^2 ------------------------------------------------------------------------- */ double FixRigid::extract_erotational() { double wbody[3],rot[3][3]; double erotate = 0.0; for (int i = 0; i < nbody; i++) { // wbody = angular velocity in body frame MathExtra::quat_to_mat(quat[i],rot); MathExtra::transpose_matvec(rot,angmom[i],wbody); if (inertia[i][0] == 0.0) wbody[0] = 0.0; else wbody[0] /= inertia[i][0]; if (inertia[i][1] == 0.0) wbody[1] = 0.0; else wbody[1] /= inertia[i][1]; if (inertia[i][2] == 0.0) wbody[2] = 0.0; else wbody[2] /= inertia[i][2]; erotate += inertia[i][0]*wbody[0]*wbody[0] + inertia[i][1]*wbody[1]*wbody[1] + inertia[i][2]*wbody[2]*wbody[2]; } return 0.5*erotate; } /* ---------------------------------------------------------------------- return attributes of a rigid body 15 values per body xcm = 0,1,2; vcm = 3,4,5; fcm = 6,7,8; torque = 9,10,11; image = 12,13,14 ------------------------------------------------------------------------- */ double FixRigid::compute_array(int i, int j) { if (j < 3) return xcm[i][j]; if (j < 6) return vcm[i][j-3]; if (j < 9) return fcm[i][j-6]; if (j < 12) return torque[i][j-9]; if (j == 12) return (imagebody[i] & IMGMASK) - IMGMAX; if (j == 13) return (imagebody[i] >> IMGBITS & IMGMASK) - IMGMAX; return (imagebody[i] >> IMG2BITS) - IMGMAX; } diff --git a/src/USER-AWPMD/pair_awpmd_cut.cpp b/src/USER-AWPMD/pair_awpmd_cut.cpp index 29feb37ca..cd89c3984 100644 --- a/src/USER-AWPMD/pair_awpmd_cut.cpp +++ b/src/USER-AWPMD/pair_awpmd_cut.cpp @@ -1,750 +1,750 @@ /* ---------------------------------------------------------------------- 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: Ilya Valuev (JIHT, Moscow, Russia) ------------------------------------------------------------------------- */ #include #include #include #include #include "pair_awpmd_cut.h" #include "atom.h" #include "update.h" #include "min.h" #include "domain.h" #include "comm.h" #include "force.h" #include "neighbor.h" #include "neigh_list.h" #include "neigh_request.h" #include "memory.h" #include "error.h" #include "TCP/wpmd_split.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ PairAWPMDCut::PairAWPMDCut(LAMMPS *lmp) : Pair(lmp) { single_enable = 0; nmax = 0; min_var = NULL; min_varforce = NULL; nextra = 4; pvector = new double[nextra]; ermscale=1.; width_pbc=0.; wpmd= new AWPMD_split(); half_box_length=0; } /* ---------------------------------------------------------------------- */ PairAWPMDCut::~PairAWPMDCut() { delete [] pvector; memory->destroy(min_var); memory->destroy(min_varforce); if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut); } delete wpmd; } struct cmp_x{ double **xx; double tol; cmp_x(double **xx_=NULL, double tol_=1e-12):xx(xx_),tol(tol_){} bool operator()(const pair &left, const pair &right) const { if(left.first==right.first){ double d=xx[left.second][0]-xx[right.second][0]; if(d<-tol) return true; else if(d>tol) return false; d=xx[left.second][1]-xx[right.second][1]; if(d<-tol) return true; else if(d>tol) return false; d=xx[left.second][2]-xx[right.second][2]; if(d<-tol) return true; else return false; } else return left.firstx; double **f = atom->f; double *q = atom->q; int *spin = atom->spin; int *type = atom->type; int *etag = atom->etag; double **v = atom->v; int nlocal = atom->nlocal; int nghost = atom->nghost; int ntot=nlocal+nghost; int newton_pair = force->newton_pair; int inum = list->inum; int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; // width pbc if(width_pbc<0) wpmd->Lextra=2*half_box_length; else wpmd->Lextra=width_pbc; wpmd->newton_pair=newton_pair; # if 1 // mapping of the LAMMPS numbers to the AWPMC numbers vector gmap(ntot,-1); for (int ii = 0; ii < inum; ii++) { int i = ilist[ii]; // local particles are all there gmap[i]=0; Vector_3 ri=Vector_3(x[i][0],x[i][1],x[i][2]); int itype = type[i]; int *jlist = firstneigh[i]; int jnum = numneigh[i]; for (int jj = 0; jj < jnum; jj++) { int j = jlist[jj]; j &= NEIGHMASK; if(j>=nlocal){ // this is a ghost Vector_3 rj=Vector_3(x[j][0],x[j][1],x[j][2]); int jtype = type[j]; double rsq=(ri-rj).norm2(); if (rsq < cutsq[itype][jtype]) gmap[j]=0; //bingo, this ghost is really needed } } } # else // old mapping // mapping of the LAMMPS numbers to the AWPMC numbers vector gmap(ntot,-1); // map for filtering the clones out: [tag,image] -> id typedef map< pair, int, cmp_x > map_t; cmp_x cmp(x); map_t idmap(cmp); for (int ii = 0; ii < inum; ii++) { int i = ilist[ii]; // local particles are all there idmap[make_pair(atom->tag[i],i)]=i; bool i_local= i res=idmap.insert(make_pair(make_pair(atom->tag[j],j),j)); bool have_it=!res.second; if(have_it){ // the clone of this particle is already listed if(res.first->second!=j) // check that was not the very same particle gmap[j]=-1; // filter out continue; } bool j_local= jreset(); map > etmap; // add particles to the AWPMD solver object for (int i = 0; i < ntot; i++) { //int i = ilist[ii]; if(gmap[i]<0) // this particle was filtered out continue; if(spin[i]==0) // this is an ion gmap[i]=wpmd->add_ion(q[i], Vector_3(x[i][0],x[i][1],x[i][2]),itag[i] : -atom->tag[i]); else if(spin[i]==1 || spin[i]==-1){ // electron, sort them according to the tag etmap[etag[i]].push_back(i); } else error->all(FLERR,fmt("Invalid spin value (%d) for particle %d !",spin[i],i)); } // ion force vector Vector_3 *fi=NULL; if(wpmd->ni) fi= new Vector_3[wpmd->ni]; // adding electrons for(map >::iterator it=etmap.begin(); it!= etmap.end(); ++it){ vector &el=it->second; if(!el.size()) // should not happen continue; int s=spin[el[0]] >0 ? 0 : 1; wpmd->add_electron(s); // starts adding the spits for(size_t k=0;kall(FLERR,fmt("WP splits for one electron should have the same spin (at particles %d, %d)!",el[0],i)); double m= atom->mass ? atom->mass[type[i]] : force->e_mass; Vector_3 xx=Vector_3(x[i][0],x[i][1],x[i][2]); Vector_3 rv=m*Vector_3(v[i][0],v[i][1],v[i][2]); double pv=ermscale*m*atom->ervel[i]; Vector_2 cc=Vector_2(atom->cs[2*i],atom->cs[2*i+1]); gmap[i]=wpmd->add_split(xx,rv,atom->eradius[i],pv,cc,1.,atom->q[i],itag[i] : -atom->tag[i]); // resetting for the case constraints were applied v[i][0]=rv[0]/m; v[i][1]=rv[1]/m; v[i][2]=rv[2]/m; atom->ervel[i]=pv/(m*ermscale); } } wpmd->set_pbc(NULL); // not required for LAMMPS wpmd->interaction(0x1|0x4|0x10,fi); // get forces from the AWPMD solver object for (int ii = 0; ii < inum; ii++) { int i = ilist[ii]; if(gmap[i]<0) // this particle was filtered out continue; if(spin[i]==0){ // this is an ion, copying forces int ion=gmap[i]; f[i][0]=fi[ion][0]; f[i][0]=fi[ion][1]; f[i][0]=fi[ion][2]; } else { // electron int iel=gmap[i]; int s=spin[i] >0 ? 0 : 1; wpmd->get_wp_force(s,iel,(Vector_3 *)f[i],(Vector_3 *)(atom->vforce+3*i),atom->erforce+i,atom->ervelforce+i,(Vector_2 *)(atom->csforce+2*i)); } } if(fi) delete [] fi; // update LAMMPS energy if (eflag_either) { if (eflag_global){ eng_coul+= wpmd->get_energy(); // pvector = [KE, Pauli, ecoul, radial_restraint] pvector[0] = wpmd->Ee[0]+wpmd->Ee[1]; pvector[2] = wpmd->Eii+wpmd->Eei[0]+wpmd->Eei[1]+wpmd->Eee; pvector[1] = pvector[0] + pvector[2] - wpmd->Edk - wpmd->Edc - wpmd->Eii; // All except diagonal terms pvector[3] = wpmd->Ew; } if (eflag_atom) { // transfer per-atom energies here for (int i = 0; i < ntot; i++) { if(gmap[i]<0) // this particle was filtered out continue; if(spin[i]==0){ eatom[i]=wpmd->Eiep[gmap[i]]+wpmd->Eiip[gmap[i]]; } else { int s=spin[i] >0 ? 0 : 1; eatom[i]=wpmd->Eep[s][gmap[i]]+wpmd->Eeip[s][gmap[i]]+wpmd->Eeep[s][gmap[i]]+wpmd->Ewp[s][gmap[i]]; } } } } if (vflag_fdotr) { virial_fdotr_compute(); if (flexible_pressure_flag) virial_eradius_compute(); } } /* ---------------------------------------------------------------------- electron width-specific contribution to global virial ------------------------------------------------------------------------- */ void PairAWPMDCut::virial_eradius_compute() { double *eradius = atom->eradius; double *erforce = atom->erforce; double e_virial; int *spin = atom->spin; // sum over force on all particles including ghosts if (neighbor->includegroup == 0) { int nall = atom->nlocal + atom->nghost; for (int i = 0; i < nall; i++) { if (spin[i]) { e_virial = erforce[i]*eradius[i]/3; virial[0] += e_virial; virial[1] += e_virial; virial[2] += e_virial; } } // neighbor includegroup flag is set // sum over force on initial nfirst particles and ghosts } else { int nall = atom->nfirst; for (int i = 0; i < nall; i++) { if (spin[i]) { e_virial = erforce[i]*eradius[i]/3; virial[0] += e_virial; virial[1] += e_virial; virial[2] += e_virial; } } nall = atom->nlocal + atom->nghost; for (int i = atom->nlocal; i < nall; i++) { if (spin[i]) { e_virial = erforce[i]*eradius[i]/3; virial[0] += e_virial; virial[1] += e_virial; virial[2] += e_virial; } } } } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairAWPMDCut::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"); } /* --------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ // the format is: pair_style awpmd/cut [ [command1] [command2] ...] // commands: // [hartree|dproduct|uhf] -- quantum approximation level (default is hartree) // [free|pbc |fix |relax|harm ] -- width restriction (default is free) // [ermscale ] -- scaling factor between electron mass and effective width mass (used for equations of motion only) (default is 1) // [flex_press] -- set flexible pressure flag // -1 for length means default setting (L/2 for cutoff and L for width PBC) void PairAWPMDCut::settings(int narg, char **arg){ if (narg < 1) error->all(FLERR,"Illegal pair_style command"); cut_global = force->numeric(FLERR,arg[0]); ermscale=1.; width_pbc=0.; for(int i=1;iapprox=AWPMD::HARTREE; else if(!strcmp(arg[i],"dproduct")) wpmd->approx=AWPMD::DPRODUCT; else if(!strcmp(arg[i],"uhf")) wpmd->approx=AWPMD::UHF; else if(!strcmp(arg[i],"free")) wpmd->constraint=AWPMD::NONE; else if(!strcmp(arg[i],"fix")){ wpmd->constraint=AWPMD::FIX; i++; if(i>=narg) error->all(FLERR,"Setting 'fix' should be followed by a number in awpmd/cut"); wpmd->w0=force->numeric(FLERR,arg[i]); } else if(!strcmp(arg[i],"harm")){ wpmd->constraint=AWPMD::HARM; i++; if(i>=narg) error->all(FLERR,"Setting 'harm' should be followed by a number in awpmd/cut"); wpmd->w0=force->numeric(FLERR,arg[i]); wpmd->set_harm_constr(wpmd->w0); } else if(!strcmp(arg[i],"pbc")){ i++; if(i>=narg) error->all(FLERR,"Setting 'pbc' should be followed by a number in awpmd/cut"); width_pbc=force->numeric(FLERR,arg[i]); } else if(!strcmp(arg[i],"relax")) wpmd->constraint=AWPMD::RELAX; else if(!strcmp(arg[i],"ermscale")){ i++; if(i>=narg) error->all(FLERR,"Setting 'ermscale' should be followed by a number in awpmd/cut"); ermscale=force->numeric(FLERR,arg[i]); } else if(!strcmp(arg[i],"flex_press")) flexible_pressure_flag = 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[i][j] = cut_global; }*/ } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ // pair settings are as usual void PairAWPMDCut::coeff(int narg, char **arg) { if (narg < 2 || narg > 3) error->all(FLERR,"Incorrect args for pair coefficients"); /*if(domain->xperiodic == 1 || domain->yperiodic == 1 || domain->zperiodic == 1) {*/ double delx = domain->boxhi[0]-domain->boxlo[0]; double dely = domain->boxhi[1]-domain->boxlo[1]; double delz = domain->boxhi[2]-domain->boxlo[2]; half_box_length = 0.5 * MIN(delx, MIN(dely, delz)); //} if(cut_global<0) cut_global=half_box_length; if (!allocated) allocate(); else{ 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; } int ilo,ihi,jlo,jhi; - force->bounds(arg[0],atom->ntypes,ilo,ihi); - force->bounds(arg[1],atom->ntypes,jlo,jhi); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double cut_one = cut_global; if (narg == 3) cut_one = force->numeric(FLERR,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; setflag[i][j] = 1; count++; } } if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairAWPMDCut::init_style() { // error and warning checks if (!atom->q_flag || !atom->spin_flag || !atom->eradius_flag || !atom->erforce_flag ) // TO DO: adjust this to match approximation used error->all(FLERR,"Pair awpmd/cut requires atom attributes " "q, spin, eradius, erforce"); /* if(vflag_atom){ // can't compute virial per atom //warning-> error->all(FLERR,"Pair style awpmd can't compute per atom virials"); }*/ // add hook to minimizer for eradius and erforce if (update->whichflag == 2) int ignore = update->minimize->request(this,1,0.01); // make sure to use the appropriate timestep when using real units /*if (update->whichflag == 1) { if (force->qqr2e == 332.06371 && update->dt == 1.0) error->all(FLERR,"You must lower the default real units timestep for pEFF "); }*/ // need a half neigh list and optionally a granular history neigh list //int irequest = neighbor->request(this,instance_me); //if (atom->tag_enable == 0) // error->all(FLERR,"Pair style reax requires atom IDs"); //if (force->newton_pair == 0) //error->all(FLERR,"Pair style awpmd requires newton pair on"); //if (strcmp(update->unit_style,"real") != 0 && comm->me == 0) //error->warning(FLERR,"Not using real units with pair reax"); int irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->newton = 2; if(force->e_mass==0. || force->hhmrr2e==0. || force->mvh2r==0.) error->all(FLERR,"Pair style awpmd requires e_mass and conversions hhmrr2e, mvh2r to be properly set for unit system"); wpmd->me=force->e_mass; wpmd->h2_me=force->hhmrr2e/force->e_mass; wpmd->one_h=force->mvh2r; wpmd->coul_pref=force->qqrd2e; wpmd->calc_ii=1; } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairAWPMDCut::init_one(int i, int j) { if (setflag[i][j] == 0) cut[i][j] = mix_distance(cut[i][i],cut[j][j]); return cut[i][j]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairAWPMDCut::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 PairAWPMDCut::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 PairAWPMDCut::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 PairAWPMDCut::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); } /* ---------------------------------------------------------------------- returns pointers to the log() of electron radius and corresponding force minimizer operates on log(radius) so radius never goes negative these arrays are stored locally by pair style ------------------------------------------------------------------------- */ void PairAWPMDCut::min_xf_pointers(int ignore, double **xextra, double **fextra) { // grow arrays if necessary // need to be atom->nmax in length int nvar=atom->nmax*(3+1+1+2); // w(1), vel(3), pw(1), cs(2) if (nvar > nmax) { memory->destroy(min_var); memory->destroy(min_varforce); nmax = nvar; memory->create(min_var,nmax,"pair:min_var"); memory->create(min_varforce,nmax,"pair:min_varforce"); } *xextra = min_var; *fextra = min_varforce; } /* ---------------------------------------------------------------------- minimizer requests the log() of electron radius and corresponding force calculate and store in min_eradius and min_erforce ------------------------------------------------------------------------- */ void PairAWPMDCut::min_xf_get(int ignore) { double *eradius = atom->eradius; double *erforce = atom->erforce; double **v=atom->v; double *vforce=atom->vforce; double *ervel=atom->ervel; double *ervelforce=atom->ervelforce; double *cs=atom->cs; double *csforce=atom->csforce; int *spin = atom->spin; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (spin[i]) { min_var[7*i] = log(eradius[i]); min_varforce[7*i] = eradius[i]*erforce[i]; for(int j=0;j<3;j++){ min_var[7*i+1+3*j] = v[i][j]; min_varforce[7*i+1+3*j] = vforce[3*i+j]; } min_var[7*i+4] = ervel[i]; min_varforce[7*i+4] = ervelforce[i]; min_var[7*i+5] = cs[2*i]; min_varforce[7*i+5] = csforce[2*i]; min_var[7*i+6] = cs[2*i+1]; min_varforce[7*i+6] = csforce[2*i+1]; } else { for(int j=0;j<7;j++) min_var[7*i+j] = min_varforce[7*i+j] = 0.0; } } /* ---------------------------------------------------------------------- propagate the minimizer values to the atom values ------------------------------------------------------------------------- */ void PairAWPMDCut::min_x_set(int ignore) { double *eradius = atom->eradius; double **v=atom->v; double *ervel=atom->ervel; double *cs=atom->cs; int *spin = atom->spin; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) { if (spin[i]){ eradius[i]=exp(min_var[7*i]); for(int j=0;j<3;j++) v[i][j]=min_var[7*i+1+3*j]; ervel[i]=min_var[7*i+4]; cs[2*i]=min_var[7*i+5]; cs[2*i+1]=min_var[7*i+6]; } } } /* ---------------------------------------------------------------------- memory usage of local atom-based arrays ------------------------------------------------------------------------- */ double PairAWPMDCut::memory_usage() { double bytes = maxeatom * sizeof(double); bytes += maxvatom*6 * sizeof(double); bytes += 2 * nmax * sizeof(double); return bytes; } diff --git a/src/USER-CG-CMM/angle_sdk.cpp b/src/USER-CG-CMM/angle_sdk.cpp index 31136e5cd..cc5498599 100644 --- a/src/USER-CG-CMM/angle_sdk.cpp +++ b/src/USER-CG-CMM/angle_sdk.cpp @@ -1,504 +1,504 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Variant of the harmonic angle potential for use with the lj/sdk potential for coarse grained MD simulations. Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ #include #include #include "angle_sdk.h" #include "atom.h" #include "neighbor.h" #include "pair.h" #include "domain.h" #include "comm.h" #include "force.h" #include "math_const.h" #include "memory.h" #include "error.h" #include "lj_sdk_common.h" using namespace LAMMPS_NS; using namespace MathConst; using namespace LJSDKParms; #define SMALL 0.001 /* ---------------------------------------------------------------------- */ AngleSDK::AngleSDK(LAMMPS *lmp) : Angle(lmp) { repflag = 0;} /* ---------------------------------------------------------------------- */ AngleSDK::~AngleSDK() { if (allocated) { memory->destroy(setflag); memory->destroy(k); memory->destroy(theta0); memory->destroy(repscale); allocated = 0; } } /* ---------------------------------------------------------------------- */ void AngleSDK::compute(int eflag, int vflag) { int i1,i2,i3,n,type; double delx1,dely1,delz1,delx2,dely2,delz2,delx3,dely3,delz3; double eangle,f1[3],f3[3],e13,f13; double dtheta,tk; double rsq1,rsq2,rsq3,r1,r2,c,s,a,a11,a12,a22; eangle = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; int **anglelist = neighbor->anglelist; int nanglelist = neighbor->nanglelist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < nanglelist; n++) { i1 = anglelist[n][0]; i2 = anglelist[n][1]; i3 = anglelist[n][2]; type = anglelist[n][3]; // 1st bond delx1 = x[i1][0] - x[i2][0]; dely1 = x[i1][1] - x[i2][1]; delz1 = x[i1][2] - x[i2][2]; rsq1 = delx1*delx1 + dely1*dely1 + delz1*delz1; r1 = sqrt(rsq1); // 2nd bond delx2 = x[i3][0] - x[i2][0]; dely2 = x[i3][1] - x[i2][1]; delz2 = x[i3][2] - x[i2][2]; rsq2 = delx2*delx2 + dely2*dely2 + delz2*delz2; r2 = sqrt(rsq2); // angle (cos and sin) c = delx1*delx2 + dely1*dely2 + delz1*delz2; c /= r1*r2; if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; s = sqrt(1.0 - c*c); if (s < SMALL) s = SMALL; s = 1.0/s; // 1-3 LJ interaction. // we only want to use the repulsive part, // and it can be scaled (or off). // so this has to be done here and not in the // general non-bonded code. f13 = e13 = delx3 = dely3 = delz3 = 0.0; if (repflag) { delx3 = x[i1][0] - x[i3][0]; dely3 = x[i1][1] - x[i3][1]; delz3 = x[i1][2] - x[i3][2]; rsq3 = delx3*delx3 + dely3*dely3 + delz3*delz3; const int type1 = atom->type[i1]; const int type3 = atom->type[i3]; f13=0.0; e13=0.0; if (rsq3 < rminsq[type1][type3]) { const int ljt = lj_type[type1][type3]; const double r2inv = 1.0/rsq3; if (ljt == LJ12_4) { const double r4inv=r2inv*r2inv; f13 = r4inv*(lj1[type1][type3]*r4inv*r4inv - lj2[type1][type3]); if (eflag) e13 = r4inv*(lj3[type1][type3]*r4inv*r4inv - lj4[type1][type3]); } else if (ljt == LJ9_6) { const double r3inv = r2inv*sqrt(r2inv); const double r6inv = r3inv*r3inv; f13 = r6inv*(lj1[type1][type3]*r3inv - lj2[type1][type3]); if (eflag) e13 = r6inv*(lj3[type1][type3]*r3inv - lj4[type1][type3]); } else if (ljt == LJ12_6) { const double r6inv = r2inv*r2inv*r2inv; f13 = r6inv*(lj1[type1][type3]*r6inv - lj2[type1][type3]); if (eflag) e13 = r6inv*(lj3[type1][type3]*r6inv - lj4[type1][type3]); } // make sure energy is 0.0 at the cutoff. if (eflag) e13 -= emin[type1][type3]; f13 *= r2inv; } } // force & energy dtheta = acos(c) - theta0[type]; tk = k[type] * dtheta; if (eflag) eangle = tk*dtheta; a = -2.0 * tk * s; a11 = a*c / rsq1; a12 = -a / (r1*r2); a22 = a*c / rsq2; f1[0] = a11*delx1 + a12*delx2; f1[1] = a11*dely1 + a12*dely2; f1[2] = a11*delz1 + a12*delz2; f3[0] = a22*delx2 + a12*delx1; f3[1] = a22*dely2 + a12*dely1; f3[2] = a22*delz2 + a12*delz1; // apply force to each of the 3 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += f1[0] + f13*delx3; f[i1][1] += f1[1] + f13*dely3; f[i1][2] += f1[2] + f13*delz3; } if (newton_bond || i2 < nlocal) { f[i2][0] -= f1[0] + f3[0]; f[i2][1] -= f1[1] + f3[1]; f[i2][2] -= f1[2] + f3[2]; } if (newton_bond || i3 < nlocal) { f[i3][0] += f3[0] - f13*delx3; f[i3][1] += f3[1] - f13*dely3; f[i3][2] += f3[2] - f13*delz3; } if (evflag) { ev_tally(i1,i2,i3,nlocal,newton_bond,eangle,f1,f3, delx1,dely1,delz1,delx2,dely2,delz2); if (repflag) ev_tally13(i1,i3,nlocal,newton_bond,e13,f13,delx3,dely3,delz3); } } } /* ---------------------------------------------------------------------- */ void AngleSDK::allocate() { allocated = 1; int n = atom->nangletypes; memory->create(k,n+1,"angle:k"); memory->create(theta0,n+1,"angle:theta0"); memory->create(repscale,n+1,"angle:repscale"); memory->create(setflag,n+1,"angle:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one or more types ------------------------------------------------------------------------- */ void AngleSDK::coeff(int narg, char **arg) { if ((narg < 3) || (narg > 6)) error->all(FLERR,"Incorrect args for angle coefficients"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->nangletypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->nangletypes,ilo,ihi); double k_one = force->numeric(FLERR,arg[1]); double theta0_one = force->numeric(FLERR,arg[2]); double repscale_one=1.0; // backward compatibility with old cg/cmm style input: // this had // if epsilon is set to 0.0 we accept it as repscale 0.0 // otherwise assume repscale 1.0, since we were using // epsilon to turn repulsion on or off. if (narg == 6) { repscale_one = force->numeric(FLERR,arg[4]); if (repscale_one > 0.0) repscale_one = 1.0; } else if (narg == 4) repscale_one = force->numeric(FLERR,arg[3]); else if (narg == 3) repscale_one = 1.0; else error->all(FLERR,"Incorrect args for angle coefficients"); // convert theta0 from degrees to radians and store coefficients int count = 0; for (int i = ilo; i <= ihi; i++) { k[i] = k_one; theta0[i] = theta0_one/180.0 * MY_PI; repscale[i] = repscale_one; setflag[i] = 1; count++; } if (count == 0) error->all(FLERR,"Incorrect args for angle coefficients"); } /* ---------------------------------------------------------------------- error check and initialize all values needed for force computation ------------------------------------------------------------------------- */ void AngleSDK::init_style() { // make sure we use an SDK pair_style and that we need the 1-3 repulsion repflag = 0; for (int i = 1; i <= atom->nangletypes; i++) if (repscale[i] > 0.0) repflag = 1; // set up pointers to access SDK LJ parameters for 1-3 interactions if (repflag) { int itmp; if (force->pair == NULL) error->all(FLERR,"Angle style SDK requires use of a compatible with Pair style"); lj1 = (double **) force->pair->extract("lj1",itmp); lj2 = (double **) force->pair->extract("lj2",itmp); lj3 = (double **) force->pair->extract("lj3",itmp); lj4 = (double **) force->pair->extract("lj4",itmp); lj_type = (int **) force->pair->extract("lj_type",itmp); rminsq = (double **) force->pair->extract("rminsq",itmp); emin = (double **) force->pair->extract("emin",itmp); if (!lj1 || !lj2 || !lj3 || !lj4 || !lj_type || !rminsq || !emin) error->all(FLERR,"Angle style SDK is incompatible with Pair style"); } } /* ---------------------------------------------------------------------- */ double AngleSDK::equilibrium_angle(int i) { return theta0[i]; } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void AngleSDK::write_restart(FILE *fp) { fwrite(&k[1],sizeof(double),atom->nangletypes,fp); fwrite(&theta0[1],sizeof(double),atom->nangletypes,fp); fwrite(&repscale[1],sizeof(double),atom->nangletypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void AngleSDK::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&k[1],sizeof(double),atom->nangletypes,fp); fread(&theta0[1],sizeof(double),atom->nangletypes,fp); fread(&repscale[1],sizeof(double),atom->nangletypes,fp); } MPI_Bcast(&k[1],atom->nangletypes,MPI_DOUBLE,0,world); MPI_Bcast(&theta0[1],atom->nangletypes,MPI_DOUBLE,0,world); MPI_Bcast(&repscale[1],atom->nangletypes,MPI_DOUBLE,0,world); for (int i = 1; i <= atom->nangletypes; i++) setflag[i] = 1; } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void AngleSDK::write_data(FILE *fp) { for (int i = 1; i <= atom->nangletypes; i++) fprintf(fp,"%d %g %g\n",i,k[i],theta0[i]/MY_PI*180.0); } /* ---------------------------------------------------------------------- */ void AngleSDK::ev_tally13(int i, int j, int nlocal, int newton_bond, double evdwl, double fpair, double delx, double dely, double delz) { double v[6]; if (eflag_either) { if (eflag_global) { if (newton_bond) { energy += evdwl; } else { if (i < nlocal) energy += 0.5*evdwl; if (j < nlocal) energy += 0.5*evdwl; } } if (eflag_atom) { if (newton_bond || i < nlocal) eatom[i] += 0.5*evdwl; if (newton_bond || j < nlocal) eatom[j] += 0.5*evdwl; } } if (vflag_either) { v[0] = delx*delx*fpair; v[1] = dely*dely*fpair; v[2] = delz*delz*fpair; v[3] = delx*dely*fpair; v[4] = delx*delz*fpair; v[5] = dely*delz*fpair; if (vflag_global) { if (newton_bond) { virial[0] += v[0]; virial[1] += v[1]; virial[2] += v[2]; virial[3] += v[3]; virial[4] += v[4]; virial[5] += v[5]; } else { if (i < nlocal) { virial[0] += 0.5*v[0]; virial[1] += 0.5*v[1]; virial[2] += 0.5*v[2]; virial[3] += 0.5*v[3]; virial[4] += 0.5*v[4]; virial[5] += 0.5*v[5]; } if (j < nlocal) { virial[0] += 0.5*v[0]; virial[1] += 0.5*v[1]; virial[2] += 0.5*v[2]; virial[3] += 0.5*v[3]; virial[4] += 0.5*v[4]; virial[5] += 0.5*v[5]; } } } if (vflag_atom) { if (newton_bond || i < nlocal) { vatom[i][0] += 0.5*v[0]; vatom[i][1] += 0.5*v[1]; vatom[i][2] += 0.5*v[2]; vatom[i][3] += 0.5*v[3]; vatom[i][4] += 0.5*v[4]; vatom[i][5] += 0.5*v[5]; } if (newton_bond || j < nlocal) { vatom[j][0] += 0.5*v[0]; vatom[j][1] += 0.5*v[1]; vatom[j][2] += 0.5*v[2]; vatom[j][3] += 0.5*v[3]; vatom[j][4] += 0.5*v[4]; vatom[j][5] += 0.5*v[5]; } } } } /* ---------------------------------------------------------------------- */ double AngleSDK::single(int type, int i1, int i2, int i3) { double **x = atom->x; double delx1 = x[i1][0] - x[i2][0]; double dely1 = x[i1][1] - x[i2][1]; double delz1 = x[i1][2] - x[i2][2]; domain->minimum_image(delx1,dely1,delz1); double r1 = sqrt(delx1*delx1 + dely1*dely1 + delz1*delz1); double delx2 = x[i3][0] - x[i2][0]; double dely2 = x[i3][1] - x[i2][1]; double delz2 = x[i3][2] - x[i2][2]; domain->minimum_image(delx2,dely2,delz2); double r2 = sqrt(delx2*delx2 + dely2*dely2 + delz2*delz2); double c = delx1*delx2 + dely1*dely2 + delz1*delz2; c /= r1*r2; if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; double e13=0.0; if (repflag) { // 1-3 LJ interaction. double delx3 = x[i1][0] - x[i3][0]; double dely3 = x[i1][1] - x[i3][1]; double delz3 = x[i1][2] - x[i3][2]; domain->minimum_image(delx3,dely3,delz3); const int type1 = atom->type[i1]; const int type3 = atom->type[i3]; const double rsq3 = delx3*delx3 + dely3*dely3 + delz3*delz3; if (rsq3 < rminsq[type1][type3]) { const int ljt = lj_type[type1][type3]; const double r2inv = 1.0/rsq3; if (ljt == LJ12_4) { const double r4inv=r2inv*r2inv; e13 = r4inv*(lj3[type1][type3]*r4inv*r4inv - lj4[type1][type3]); } else if (ljt == LJ9_6) { const double r3inv = r2inv*sqrt(r2inv); const double r6inv = r3inv*r3inv; e13 = r6inv*(lj3[type1][type3]*r3inv - lj4[type1][type3]); } else if (ljt == LJ12_6) { const double r6inv = r2inv*r2inv*r2inv; e13 = r6inv*(lj3[type1][type3]*r6inv - lj4[type1][type3]); } // make sure energy is 0.0 at the cutoff. e13 -= emin[type1][type3]; } } double dtheta = acos(c) - theta0[type]; double tk = k[type] * dtheta; return tk*dtheta + e13; } diff --git a/src/USER-CG-CMM/pair_lj_sdk.cpp b/src/USER-CG-CMM/pair_lj_sdk.cpp index 1ab93447f..665f188ce 100644 --- a/src/USER-CG-CMM/pair_lj_sdk.cpp +++ b/src/USER-CG-CMM/pair_lj_sdk.cpp @@ -1,510 +1,510 @@ /* ---------------------------------------------------------------------- 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: Axel Kohlmeyer (Temple U) This style is a simplified re-implementation of the CG/CMM pair style ------------------------------------------------------------------------- */ #include #include #include #include #include "pair_lj_sdk.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 "math_const.h" #include "memory.h" #include "error.h" #include "lj_sdk_common.h" using namespace LAMMPS_NS; using namespace MathConst; using namespace LJSDKParms; /* ---------------------------------------------------------------------- */ PairLJSDK::PairLJSDK(LAMMPS *lmp) : Pair(lmp) { respa_enable = 0; single_enable = 1; writedata = 1; } /* ---------------------------------------------------------------------- */ PairLJSDK::~PairLJSDK() { if (allocated) { memory->destroy(setflag); memory->destroy(lj_type); 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); memory->destroy(rminsq); memory->destroy(emin); allocated = 0; } } /* ---------------------------------------------------------------------- */ void PairLJSDK::compute(int eflag, int vflag) { if (eflag || vflag) { ev_setup(eflag,vflag); } else evflag = vflag_fdotr = 0; if (evflag) { if (eflag) { if (force->newton_pair) eval<1,1,1>(); else eval<1,1,0>(); } else { if (force->newton_pair) eval<1,0,1>(); else eval<1,0,0>(); } } else { if (force->newton_pair) eval<0,0,1>(); else eval<0,0,0>(); } if (vflag_fdotr) virial_fdotr_compute(); } /* ---------------------------------------------------------------------- */ template void PairLJSDK::eval() { int i,j,ii,jj,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair; double rsq,r2inv,forcelj,factor_lj; evdwl = 0.0; const double * const * const x = atom->x; double * const * const f = atom->f; const int * const type = atom->type; const int nlocal = atom->nlocal; const double * const special_lj = force->special_lj; double fxtmp,fytmp,fztmp; const int inum = list->inum; const int * const ilist = list->ilist; const int * const numneigh = list->numneigh; const int * const * const 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]; fxtmp=fytmp=fztmp=0.0; const int itype = type[i]; const int * const jlist = firstneigh[i]; const int 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; const int ljt = lj_type[itype][jtype]; if (ljt == LJ12_4) { const double r4inv=r2inv*r2inv; forcelj = r4inv*(lj1[itype][jtype]*r4inv*r4inv - lj2[itype][jtype]); if (EFLAG) evdwl = r4inv*(lj3[itype][jtype]*r4inv*r4inv - lj4[itype][jtype]) - offset[itype][jtype]; } else if (ljt == LJ9_6) { const double r3inv = r2inv*sqrt(r2inv); const double r6inv = r3inv*r3inv; forcelj = r6inv*(lj1[itype][jtype]*r3inv - lj2[itype][jtype]); if (EFLAG) evdwl = r6inv*(lj3[itype][jtype]*r3inv - lj4[itype][jtype]) - offset[itype][jtype]; } else if (ljt == LJ12_6) { const double r6inv = r2inv*r2inv*r2inv; forcelj = r6inv*(lj1[itype][jtype]*r6inv - lj2[itype][jtype]); if (EFLAG) evdwl = r6inv*(lj3[itype][jtype]*r6inv - lj4[itype][jtype]) - offset[itype][jtype]; } else continue; fpair = factor_lj*forcelj*r2inv; fxtmp += delx*fpair; fytmp += dely*fpair; fztmp += 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; if (EVFLAG) ev_tally(i,j,nlocal,NEWTON_PAIR, evdwl,0.0,fpair,delx,dely,delz); } } f[i][0] += fxtmp; f[i][1] += fytmp; f[i][2] += fztmp; } } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairLJSDK::allocate() { allocated = 1; int n = atom->ntypes; memory->create(setflag,n+1,n+1,"pair:setflag"); memory->create(lj_type,n+1,n+1,"pair:lj_type"); for (int i = 1; i <= n; i++) { for (int j = i; j <= n; j++) { setflag[i][j] = 0; lj_type[i][j] = LJ_NOT_SET; } } memory->create(cut,n+1,n+1,"pair:cut"); 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(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"); memory->create(rminsq,n+1,n+1,"pair:rminsq"); memory->create(emin,n+1,n+1,"pair:emin"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairLJSDK::settings(int narg, char **arg) { if (narg != 1) error->all(FLERR,"Illegal pair_style command"); cut_global = force->numeric(FLERR,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 PairLJSDK::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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); int lj_type_one = find_lj_type(arg[2],lj_type_list); if (lj_type_one == LJ_NOT_SET) error->all(FLERR,"Cannot parse LJ type flag."); double epsilon_one = force->numeric(FLERR,arg[3]); double sigma_one = force->numeric(FLERR,arg[4]); double cut_one = cut_global; if (narg == 6) cut_one = force->numeric(FLERR,arg[5]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { lj_type[i][j] = lj_type_one; 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 for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairLJSDK::init_one(int i, int j) { if (setflag[i][j] == 0) error->all(FLERR,"No mixing support for lj/sdk. " "Coefficients for all pairs need to be set explicitly."); const int ljt = lj_type[i][j]; if (ljt == LJ_NOT_SET) error->all(FLERR,"unrecognized LJ parameter flag"); lj1[i][j] = lj_prefact[ljt] * lj_pow1[ljt] * epsilon[i][j] * pow(sigma[i][j],lj_pow1[ljt]); lj2[i][j] = lj_prefact[ljt] * lj_pow2[ljt] * epsilon[i][j] * pow(sigma[i][j],lj_pow2[ljt]); lj3[i][j] = lj_prefact[ljt] * epsilon[i][j] * pow(sigma[i][j],lj_pow1[ljt]); lj4[i][j] = lj_prefact[ljt] * epsilon[i][j] * pow(sigma[i][j],lj_pow2[ljt]); if (offset_flag) { double ratio = sigma[i][j] / cut[i][j]; offset[i][j] = lj_prefact[ljt] * epsilon[i][j] * (pow(ratio,lj_pow1[ljt]) - pow(ratio,lj_pow2[ljt])); } 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]; cut[j][i] = cut[i][j]; cutsq[j][i] = cutsq[i][j]; offset[j][i] = offset[i][j]; lj_type[j][i] = lj_type[i][j]; // compute derived parameters for SDK angle potential const double eps = epsilon[i][j]; const double sig = sigma[i][j]; const double rmin = sig*exp(1.0/(lj_pow1[ljt]-lj_pow2[ljt]) *log(lj_pow1[ljt]/lj_pow2[ljt]) ); rminsq[j][i] = rminsq[i][j] = rmin*rmin; const double ratio = sig/rmin; const double emin_one = lj_prefact[ljt] * eps * (pow(ratio,lj_pow1[ljt]) - pow(ratio,lj_pow2[ljt])); emin[j][i] = emin[i][j] = emin_one; // compute I,J contribution to long-range tail correction // count total # of atoms of type I and J via Allreduce if (tail_flag) error->all(FLERR,"Tail flag not supported by lj/sdk pair style"); return cut[i][j]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJSDK::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(&lj_type[i][j],sizeof(int),1,fp); 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 PairLJSDK::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(&lj_type[i][j],sizeof(int),1,fp); 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(&lj_type[i][j],1,MPI_INT,0,world); 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 PairLJSDK::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); fwrite(&tail_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJSDK::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); fread(&tail_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); MPI_Bcast(&tail_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- lj/sdk does not support per atom type output with mixing ------------------------------------------------------------------------- */ void PairLJSDK::write_data(FILE *) { error->one(FLERR, "Pair style lj/sdk requires using " "write_data with the 'pair ij' option"); } /* ---------------------------------------------------------------------- proc 0 writes all pairs to data file ------------------------------------------------------------------------- */ void PairLJSDK::write_data_all(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) fprintf(fp,"%d %d %s %g %g %g\n",i,j,lj_type_list[lj_type[i][j]], epsilon[i][j],sigma[i][j],cut[i][j]); } /* ---------------------------------------------------------------------- */ double PairLJSDK::single(int, int, int itype, int jtype, double rsq, double, double factor_lj, double &fforce) { if (rsq < cutsq[itype][jtype]) { const int ljt = lj_type[itype][jtype]; const double ljpow1 = lj_pow1[ljt]; const double ljpow2 = lj_pow2[ljt]; const double ljpref = lj_prefact[ljt]; const double ratio = sigma[itype][jtype]/sqrt(rsq); const double eps = epsilon[itype][jtype]; fforce = factor_lj * ljpref*eps * (ljpow1*pow(ratio,ljpow1) - ljpow2*pow(ratio,ljpow2))/rsq; return factor_lj * (ljpref*eps * (pow(ratio,ljpow1) - pow(ratio,ljpow2)) - offset[itype][jtype]); } else fforce=0.0; return 0.0; } /* ---------------------------------------------------------------------- */ void *PairLJSDK::extract(const char *str, int &dim) { dim = 2; if (strcmp(str,"epsilon") == 0) return (void *) epsilon; if (strcmp(str,"sigma") == 0) return (void *) sigma; if (strcmp(str,"lj_type") == 0) return (void *) lj_type; if (strcmp(str,"lj1") == 0) return (void *) lj1; if (strcmp(str,"lj2") == 0) return (void *) lj2; if (strcmp(str,"lj3") == 0) return (void *) lj3; if (strcmp(str,"lj4") == 0) return (void *) lj4; if (strcmp(str,"rminsq") == 0) return (void *) rminsq; if (strcmp(str,"emin") == 0) return (void *) emin; return NULL; } /* ---------------------------------------------------------------------- */ double PairLJSDK::memory_usage() { double bytes = Pair::memory_usage(); int n = atom->ntypes; // setflag/lj_type bytes += 2 * (n+1)*(n+1)*sizeof(int); // cut/cutsq/epsilon/sigma/offset/lj1/lj2/lj3/lj4/rminsq/emin bytes += 11 * (n+1)*(n+1)*sizeof(double); return bytes; } diff --git a/src/USER-CG-CMM/pair_lj_sdk_coul_long.cpp b/src/USER-CG-CMM/pair_lj_sdk_coul_long.cpp index 1549acfc2..5e4a0db31 100644 --- a/src/USER-CG-CMM/pair_lj_sdk_coul_long.cpp +++ b/src/USER-CG-CMM/pair_lj_sdk_coul_long.cpp @@ -1,658 +1,658 @@ /* ---------------------------------------------------------------------- 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: Axel Kohlmeyer (Temple U) This style is a simplified re-implementation of the CG/CMM pair style ------------------------------------------------------------------------- */ #include #include #include #include #include "pair_lj_sdk_coul_long.h" #include "atom.h" #include "comm.h" #include "force.h" #include "kspace.h" #include "neighbor.h" #include "neigh_list.h" #include "neigh_request.h" #include "update.h" #include "integrate.h" #include "math_const.h" #include "memory.h" #include "error.h" #include "lj_sdk_common.h" using namespace LAMMPS_NS; using namespace MathConst; using namespace LJSDKParms; #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 /* ---------------------------------------------------------------------- */ PairLJSDKCoulLong::PairLJSDKCoulLong(LAMMPS *lmp) : Pair(lmp) { ewaldflag = pppmflag = 1; respa_enable = 0; writedata = 1; ftable = NULL; } /* ---------------------------------------------------------------------- */ PairLJSDKCoulLong::~PairLJSDKCoulLong() { if (allocated) { memory->destroy(setflag); memory->destroy(lj_type); 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); memory->destroy(rminsq); memory->destroy(emin); allocated = 0; } if (ftable) free_tables(); } /* ---------------------------------------------------------------------- */ void PairLJSDKCoulLong::compute(int eflag, int vflag) { if (eflag || vflag) { ev_setup(eflag,vflag); } else evflag = vflag_fdotr = 0; if (evflag) { if (eflag) { if (force->newton_pair) eval<1,1,1>(); else eval<1,1,0>(); } else { if (force->newton_pair) eval<1,0,1>(); else eval<1,0,0>(); } } else { if (force->newton_pair) eval<0,0,1>(); else eval<0,0,0>(); } if (vflag_fdotr) virial_fdotr_compute(); } /* ---------------------------------------------------------------------- */ template void PairLJSDKCoulLong::eval() { int i,ii,j,jj,jtype,itable; double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair; double fraction,table; double r,rsq,r2inv,forcecoul,forcelj,factor_coul,factor_lj; double grij,expm2,prefactor,t,erfc; const double * const * const x = atom->x; double * const * const f = atom->f; const double * const q = atom->q; const int * const type = atom->type; const int nlocal = atom->nlocal; const double * const special_coul = force->special_coul; const double * const special_lj = force->special_lj; const double qqrd2e = force->qqrd2e; double fxtmp,fytmp,fztmp; const int inum = list->inum; const int * const ilist = list->ilist; const int * const numneigh = list->numneigh; const int * const * const 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]; fxtmp=fytmp=fztmp=0.0; const int itype = type[i]; const int * const jlist = firstneigh[i]; const int jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { forcecoul = forcelj = evdwl = ecoul = 0.0; 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; const int ljt = lj_type[itype][jtype]; 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 (EFLAG) ecoul = prefactor*erfc; if (factor_coul < 1.0) { forcecoul -= (1.0-factor_coul)*prefactor; if (EFLAG) ecoul -= (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 (EFLAG) ecoul = qtmp*q[j] * (etable[itable] + fraction*detable[itable]); if (factor_coul < 1.0) { table = ctable[itable] + fraction*dctable[itable]; prefactor = qtmp*q[j] * table; forcecoul -= (1.0-factor_coul)*prefactor; if (EFLAG) ecoul -= (1.0-factor_coul)*prefactor; } } } if (rsq < cut_ljsq[itype][jtype]) { if (ljt == LJ12_4) { const double r4inv=r2inv*r2inv; forcelj = r4inv*(lj1[itype][jtype]*r4inv*r4inv - lj2[itype][jtype]); if (EFLAG) evdwl = r4inv*(lj3[itype][jtype]*r4inv*r4inv - lj4[itype][jtype]) - offset[itype][jtype]; } else if (ljt == LJ9_6) { const double r3inv = r2inv*sqrt(r2inv); const double r6inv = r3inv*r3inv; forcelj = r6inv*(lj1[itype][jtype]*r3inv - lj2[itype][jtype]); if (EFLAG) evdwl = r6inv*(lj3[itype][jtype]*r3inv - lj4[itype][jtype]) - offset[itype][jtype]; } else if (ljt == LJ12_6) { const double r6inv = r2inv*r2inv*r2inv; forcelj = r6inv*(lj1[itype][jtype]*r6inv - lj2[itype][jtype]); if (EFLAG) evdwl = r6inv*(lj3[itype][jtype]*r6inv - lj4[itype][jtype]) - offset[itype][jtype]; } forcelj *= factor_lj; if (EFLAG) evdwl *= factor_lj; } fpair = (forcecoul + forcelj) * r2inv; fxtmp += delx*fpair; fytmp += dely*fpair; fztmp += delz*fpair; if (NEWTON_PAIR || j < nlocal) { f[j][0] -= delx*fpair; f[j][1] -= dely*fpair; f[j][2] -= delz*fpair; } if (EVFLAG) ev_tally(i,j,nlocal,NEWTON_PAIR, evdwl,ecoul,fpair,delx,dely,delz); } } f[i][0] += fxtmp; f[i][1] += fytmp; f[i][2] += fztmp; } } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairLJSDKCoulLong::allocate() { allocated = 1; int n = atom->ntypes; memory->create(setflag,n+1,n+1,"pair:setflag"); memory->create(lj_type,n+1,n+1,"pair:lj_type"); for (int i = 1; i <= n; i++) { for (int j = i; j <= n; j++) { setflag[i][j] = 0; lj_type[i][j] = LJ_NOT_SET; } } 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"); memory->create(rminsq,n+1,n+1,"pair:rminsq"); memory->create(emin,n+1,n+1,"pair:emin"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairLJSDKCoulLong::settings(int narg, char **arg) { if (narg < 1 || narg > 2) error->all(FLERR,"Illegal pair_style command"); cut_lj_global = force->numeric(FLERR,arg[0]); if (narg == 1) cut_coul = cut_lj_global; else cut_coul = force->numeric(FLERR,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 PairLJSDKCoulLong::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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); int lj_type_one = find_lj_type(arg[2],lj_type_list); if (lj_type_one == LJ_NOT_SET) error->all(FLERR,"Cannot parse LJ type flag."); double epsilon_one = force->numeric(FLERR,arg[3]); double sigma_one = force->numeric(FLERR,arg[4]); double cut_lj_one = cut_lj_global; if (narg == 6) cut_lj_one = force->numeric(FLERR,arg[5]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { lj_type[i][j] = lj_type_one; 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 PairLJSDKCoulLong::init_style() { if (!atom->q_flag) error->all(FLERR,"Pair style lj/cut/coul/long requires atom attribute q"); neighbor->request(this,instance_me); 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 requires a KSpace style"); g_ewald = force->kspace->g_ewald; // setup force tables (no rRESPA support yet) if (ncoultablebits) init_tables(cut_coul,NULL); } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairLJSDKCoulLong::init_one(int i, int j) { if (setflag[i][j] == 0) error->all(FLERR,"No mixing support for lj/sdk/coul/long. " "Coefficients for all pairs need to be set explicitly."); const int ljt = lj_type[i][j]; if (ljt == LJ_NOT_SET) error->all(FLERR,"unrecognized LJ parameter flag"); double cut = MAX(cut_lj[i][j],cut_coul); cut_ljsq[i][j] = cut_lj[i][j] * cut_lj[i][j]; lj1[i][j] = lj_prefact[ljt] * lj_pow1[ljt] * epsilon[i][j] * pow(sigma[i][j],lj_pow1[ljt]); lj2[i][j] = lj_prefact[ljt] * lj_pow2[ljt] * epsilon[i][j] * pow(sigma[i][j],lj_pow2[ljt]); lj3[i][j] = lj_prefact[ljt] * epsilon[i][j] * pow(sigma[i][j],lj_pow1[ljt]); lj4[i][j] = lj_prefact[ljt] * epsilon[i][j] * pow(sigma[i][j],lj_pow2[ljt]); if (offset_flag) { double ratio = sigma[i][j] / cut_lj[i][j]; offset[i][j] = lj_prefact[ljt] * epsilon[i][j] * (pow(ratio,lj_pow1[ljt]) - pow(ratio,lj_pow2[ljt])); } else offset[i][j] = 0.0; cut_ljsq[j][i] = cut_ljsq[i][j]; cut_lj[j][i] = cut_lj[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]; lj_type[j][i] = lj_type[i][j]; // compute LJ derived parameters for SDK angle potential (LJ only!) const double eps = epsilon[i][j]; const double sig = sigma[i][j]; const double rmin = sig*exp(1.0/(lj_pow1[ljt]-lj_pow2[ljt]) *log(lj_pow1[ljt]/lj_pow2[ljt]) ); rminsq[j][i] = rminsq[i][j] = rmin*rmin; const double ratio = sig/rmin; const double emin_one = lj_prefact[ljt] * eps * (pow(ratio,lj_pow1[ljt]) - pow(ratio,lj_pow2[ljt])); emin[j][i] = emin[i][j] = emin_one; // compute I,J contribution to long-range tail correction // count total # of atoms of type I and J via Allreduce if (tail_flag) error->all(FLERR,"Tail flag not supported by lj/sdk/coul/long pair style"); return cut; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJSDKCoulLong::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(&lj_type[i][j],sizeof(int),1,fp); 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 PairLJSDKCoulLong::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(&lj_type[i][j],sizeof(int),1,fp); 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(&lj_type[i][j],1,MPI_INT,0,world); 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 PairLJSDKCoulLong::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); fwrite(&tail_flag,sizeof(int),1,fp); fwrite(&ncoultablebits,sizeof(int),1,fp); fwrite(&tabinner,sizeof(double),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJSDKCoulLong::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); fread(&tail_flag,sizeof(int),1,fp); fread(&ncoultablebits,sizeof(int),1,fp); fread(&tabinner,sizeof(double),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); MPI_Bcast(&tail_flag,1,MPI_INT,0,world); MPI_Bcast(&ncoultablebits,1,MPI_INT,0,world); MPI_Bcast(&tabinner,1,MPI_DOUBLE,0,world); } /* ---------------------------------------------------------------------- lj/sdk does not support per atom type output with mixing ------------------------------------------------------------------------- */ void PairLJSDKCoulLong::write_data(FILE *) { error->one(FLERR, "Pair style lj/sdk/coul/* requires using " "write_data with the 'pair ij' option"); } /* ---------------------------------------------------------------------- proc 0 writes all pairs to data file ------------------------------------------------------------------------- */ void PairLJSDKCoulLong::write_data_all(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) fprintf(fp,"%d %d %s %g %g %g\n",i,j,lj_type_list[lj_type[i][j]], epsilon[i][j],sigma[i][j],cut_lj[i][j]); } /* ---------------------------------------------------------------------- */ double PairLJSDKCoulLong::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,forcelj,phicoul,philj; int itable; forcecoul = forcelj = phicoul = philj = 0.0; 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); phicoul = prefactor*erfc; if (factor_coul < 1.0) { forcecoul -= (1.0-factor_coul)*prefactor; phicoul -= (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; table = etable[itable] + fraction*detable[itable]; phicoul = 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; phicoul -= (1.0-factor_coul)*prefactor; } } } if (rsq < cut_ljsq[itype][jtype]) { const int ljt = lj_type[itype][jtype]; const double ljpow1 = lj_pow1[ljt]; const double ljpow2 = lj_pow2[ljt]; const double ljpref = lj_prefact[ljt]; const double ratio = sigma[itype][jtype]/sqrt(rsq); const double eps = epsilon[itype][jtype]; forcelj = factor_lj * ljpref*eps * (ljpow1*pow(ratio,ljpow1) - ljpow2*pow(ratio,ljpow2))/rsq; philj = factor_lj * (ljpref*eps * (pow(ratio,ljpow1) - pow(ratio,ljpow2)) - offset[itype][jtype]); } fforce = (forcecoul + forcelj) * r2inv; return phicoul + philj; } /* ---------------------------------------------------------------------- */ void *PairLJSDKCoulLong::extract(const char *str, int &dim) { dim = 2; if (strcmp(str,"epsilon") == 0) return (void *) epsilon; if (strcmp(str,"sigma") == 0) return (void *) sigma; if (strcmp(str,"lj_type") == 0) return (void *) lj_type; if (strcmp(str,"lj1") == 0) return (void *) lj1; if (strcmp(str,"lj2") == 0) return (void *) lj2; if (strcmp(str,"lj3") == 0) return (void *) lj3; if (strcmp(str,"lj4") == 0) return (void *) lj4; if (strcmp(str,"rminsq") == 0) return (void *) rminsq; if (strcmp(str,"emin") == 0) return (void *) emin; dim = 0; if (strcmp(str,"cut_coul") == 0) return (void *) &cut_coul; return NULL; } /* ---------------------------------------------------------------------- */ double PairLJSDKCoulLong::memory_usage() { double bytes = Pair::memory_usage(); int n = atom->ntypes; // setflag/lj_type bytes += 2 * (n+1)*(n+1)*sizeof(int); // lj_cut/lj_cutsq/epsilon/sigma/offset/lj1/lj2/lj3/lj4/rminsq/emin bytes += 11 * (n+1)*(n+1)*sizeof(double); if (ncoultablebits) { int ntable = 1< #include #include #include #include "atom.h" #include "atom_vec.h" #include "comm.h" #include "update.h" #include "fix.h" #include "force.h" #include "neighbor.h" #include "neigh_list.h" #include "neigh_request.h" #include "random_mars.h" #include "memory.h" #include "modify.h" #include "pair_dpd_fdt.h" #include "error.h" using namespace LAMMPS_NS; #define EPSILON 1.0e-10 /* ---------------------------------------------------------------------- */ PairDPDfdt::PairDPDfdt(LAMMPS *lmp) : Pair(lmp) { random = NULL; } /* ---------------------------------------------------------------------- */ PairDPDfdt::~PairDPDfdt() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut); memory->destroy(a0); memory->destroy(sigma); } if (random) delete random; } /* ---------------------------------------------------------------------- */ void PairDPDfdt::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair; double vxtmp,vytmp,vztmp,delvx,delvy,delvz; double rsq,r,rinv,dot,wd,wr,randnum,factor_dpd; int *ilist,*jlist,*numneigh,**firstneigh; double gamma_ij; evdwl = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; double **x = atom->x; double **v = atom->v; double **f = atom->f; int *type = atom->type; int nlocal = atom->nlocal; double *special_lj = force->special_lj; int newton_pair = force->newton_pair; double dtinvsqrt = 1.0/sqrt(update->dt); inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // loop over neighbors of my atoms if (splitFDT_flag) { 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_dpd = 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); if (r < EPSILON) continue; // r can be 0.0 in DPD systems rinv = 1.0/r; wr = 1.0 - r/cut[itype][jtype]; wd = wr*wr; // conservative force = a0 * wr fpair = a0[itype][jtype]*wr; fpair *= factor_dpd*rinv; 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) { // unshifted eng of conservative term: // evdwl = -a0[itype][jtype]*r * (1.0-0.5*r/cut[itype][jtype]); // eng shifted to 0.0 at cutoff evdwl = 0.5*a0[itype][jtype]*cut[itype][jtype] * wd; evdwl *= factor_dpd; } if (evflag) ev_tally(i,j,nlocal,newton_pair, evdwl,0.0,fpair,delx,dely,delz); } } } } else { for (ii = 0; ii < inum; ii++) { i = ilist[ii]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; vxtmp = v[i][0]; vytmp = v[i][1]; vztmp = v[i][2]; itype = type[i]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; factor_dpd = 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); if (r < EPSILON) continue; // r can be 0.0 in DPD systems rinv = 1.0/r; delvx = vxtmp - v[j][0]; delvy = vytmp - v[j][1]; delvz = vztmp - v[j][2]; dot = delx*delvx + dely*delvy + delz*delvz; wr = 1.0 - r/cut[itype][jtype]; wd = wr*wr; randnum = random->gaussian(); gamma_ij = sigma[itype][jtype]*sigma[itype][jtype] / (2.0*force->boltz*temperature); // conservative force = a0 * wd // drag force = -gamma * wd^2 * (delx dot delv) / r // random force = sigma * wd * rnd * dtinvsqrt; fpair = a0[itype][jtype]*wr; fpair -= gamma_ij*wd*dot*rinv; fpair += sigma[itype][jtype]*wr*randnum*dtinvsqrt; fpair *= factor_dpd*rinv; 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) { // unshifted eng of conservative term: // evdwl = -a0[itype][jtype]*r * (1.0-0.5*r/cut[itype][jtype]); // eng shifted to 0.0 at cutoff evdwl = 0.5*a0[itype][jtype]*cut[itype][jtype] * wd; evdwl *= factor_dpd; } 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 PairDPDfdt::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(a0,n+1,n+1,"pair:a0"); memory->create(sigma,n+1,n+1,"pair:sigma"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairDPDfdt::settings(int narg, char **arg) { // process keywords if (narg != 3) error->all(FLERR,"Illegal pair_style command"); temperature = force->numeric(FLERR,arg[0]); cut_global = force->numeric(FLERR,arg[1]); seed = force->inumeric(FLERR,arg[2]); // initialize Marsaglia RNG with processor-unique seed if (seed <= 0) error->all(FLERR,"Illegal pair_style command"); delete random; random = new RanMars(lmp,seed + comm->me); // 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 PairDPDfdt::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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double a0_one = force->numeric(FLERR,arg[2]); double sigma_one = force->numeric(FLERR,arg[3]); double cut_one = cut_global; if (narg == 5) cut_one = force->numeric(FLERR,arg[4]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { a0[i][j] = a0_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 PairDPDfdt::init_style() { if (comm->ghost_velocity == 0) error->all(FLERR,"Pair dpd/fdt requires ghost atoms store velocity"); // if newton off, forces between atoms ij will be double computed // using different random numbers if (force->newton_pair == 0 && comm->me == 0) error->warning(FLERR, "Pair dpd/fdt requires newton pair on"); splitFDT_flag = false; int irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->ssa = 0; for (int i = 0; i < modify->nfix; i++) if (strcmp(modify->fix[i]->style,"shardlow") == 0){ splitFDT_flag = true; neighbor->requests[irequest]->ssa = 1; } } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairDPDfdt::init_one(int i, int j) { if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set"); cut[j][i] = cut[i][j]; a0[j][i] = a0[i][j]; sigma[j][i] = sigma[i][j]; return cut[i][j]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairDPDfdt::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(&a0[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 PairDPDfdt::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(&a0[i][j],sizeof(double),1,fp); fread(&sigma[i][j],sizeof(double),1,fp); fread(&cut[i][j],sizeof(double),1,fp); } MPI_Bcast(&a0[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 PairDPDfdt::write_restart_settings(FILE *fp) { fwrite(&temperature,sizeof(double),1,fp); fwrite(&cut_global,sizeof(double),1,fp); fwrite(&seed,sizeof(int),1,fp); fwrite(&mix_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairDPDfdt::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&temperature,sizeof(double),1,fp); fread(&cut_global,sizeof(double),1,fp); fread(&seed,sizeof(int),1,fp); fread(&mix_flag,sizeof(int),1,fp); } MPI_Bcast(&temperature,1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world); MPI_Bcast(&seed,1,MPI_INT,0,world); MPI_Bcast(&mix_flag,1,MPI_INT,0,world); // initialize Marsaglia RNG with processor-unique seed // same seed that pair_style command initially specified if (random) delete random; random = new RanMars(lmp,seed + comm->me); } /* ---------------------------------------------------------------------- */ double PairDPDfdt::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_dpd, double &fforce) { double r,rinv,wr,wd,phi; r = sqrt(rsq); if (r < EPSILON) { fforce = 0.0; return 0.0; } rinv = 1.0/r; wr = 1.0 - r/cut[itype][jtype]; wd = wr*wr; fforce = a0[itype][jtype]*wr * factor_dpd*rinv; phi = 0.5*a0[itype][jtype]*cut[itype][jtype] * wd; return factor_dpd*phi; } diff --git a/src/USER-DPD/pair_dpd_fdt_energy.cpp b/src/USER-DPD/pair_dpd_fdt_energy.cpp index 902ca0052..84fa352a4 100644 --- a/src/USER-DPD/pair_dpd_fdt_energy.cpp +++ b/src/USER-DPD/pair_dpd_fdt_energy.cpp @@ -1,574 +1,574 @@ /* ---------------------------------------------------------------------- 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: James Larentzos (U.S. Army Research Laboratory) ------------------------------------------------------------------------- */ #include #include #include #include #include "atom.h" #include "atom_vec.h" #include "comm.h" #include "update.h" #include "fix.h" #include "force.h" #include "neighbor.h" #include "neigh_list.h" #include "neigh_request.h" #include "random_mars.h" #include "memory.h" #include "modify.h" #include "pair_dpd_fdt_energy.h" #include "error.h" using namespace LAMMPS_NS; #define EPSILON 1.0e-10 /* ---------------------------------------------------------------------- */ PairDPDfdtEnergy::PairDPDfdtEnergy(LAMMPS *lmp) : Pair(lmp) { random = NULL; comm_reverse = 2; } /* ---------------------------------------------------------------------- */ PairDPDfdtEnergy::~PairDPDfdtEnergy() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut); memory->destroy(a0); memory->destroy(sigma); memory->destroy(kappa); if (!splitFDT_flag) { memory->destroy(duCond); memory->destroy(duMech); } } if (random) delete random; } /* ---------------------------------------------------------------------- */ void PairDPDfdtEnergy::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair; double vxtmp,vytmp,vztmp,delvx,delvy,delvz; double rsq,r,rinv,wd,wr,factor_dpd,uTmp; double dot,randnum; 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 **v = atom->v; double **f = atom->f; int *type = atom->type; int nlocal = atom->nlocal; int nghost = atom->nghost; double *special_lj = force->special_lj; int newton_pair = force->newton_pair; double dtinvsqrt = 1.0/sqrt(update->dt); double *rmass = atom->rmass; double *mass = atom->mass; double *dpdTheta = atom->dpdTheta; double kappa_ij, alpha_ij, theta_ij, gamma_ij; double mass_i, mass_j; double massinv_i, massinv_j; double randPair, mu_ij; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // loop over neighbors of my atoms if (splitFDT_flag) { 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_dpd = 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); if (r < EPSILON) continue; // r can be 0.0 in DPD systems rinv = 1.0/r; wr = 1.0 - r/cut[itype][jtype]; wd = wr*wr; // conservative force = a0 * wr fpair = a0[itype][jtype]*wr; fpair *= factor_dpd*rinv; 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) { // unshifted eng of conservative term: // evdwl = -a0[itype][jtype]*r * (1.0-0.5*r/cut[itype][jtype]); // eng shifted to 0.0 at cutoff evdwl = 0.5*a0[itype][jtype]*cut[itype][jtype] * wd; evdwl *= factor_dpd; } if (evflag) ev_tally(i,j,nlocal,newton_pair, evdwl,0.0,fpair,delx,dely,delz); } } } } else { // Allocate memory for duCond and duMech if (allocated) { memory->destroy(duCond); memory->destroy(duMech); } memory->create(duCond,nlocal+nghost,"pair:duCond"); memory->create(duMech,nlocal+nghost,"pair:duMech"); for (int ii = 0; ii < nlocal+nghost; ii++) { duCond[ii] = 0.0; duMech[ii] = 0.0; } // loop over neighbors of my atoms for (int ii = 0; ii < inum; ii++) { i = ilist[ii]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; vxtmp = v[i][0]; vytmp = v[i][1]; vztmp = v[i][2]; itype = type[i]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; factor_dpd = 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); if (r < EPSILON) continue; // r can be 0.0 in DPD systems rinv = 1.0/r; wr = 1.0 - r/cut[itype][jtype]; wd = wr*wr; delvx = vxtmp - v[j][0]; delvy = vytmp - v[j][1]; delvz = vztmp - v[j][2]; dot = delx*delvx + dely*delvy + delz*delvz; randnum = random->gaussian(); // Compute the current temperature theta_ij = 0.5*(1.0/dpdTheta[i] + 1.0/dpdTheta[j]); theta_ij = 1.0/theta_ij; gamma_ij = sigma[itype][jtype]*sigma[itype][jtype] / (2.0*force->boltz*theta_ij); // conservative force = a0 * wr // drag force = -gamma * wr^2 * (delx dot delv) / r // random force = sigma * wr * rnd * dtinvsqrt; fpair = a0[itype][jtype]*wr; fpair -= gamma_ij*wd*dot*rinv; fpair += sigma[itype][jtype]*wr*randnum*dtinvsqrt; fpair *= factor_dpd*rinv; 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 (rmass) { mass_i = rmass[i]; mass_j = rmass[j]; } else { mass_i = mass[itype]; mass_j = mass[jtype]; } massinv_i = 1.0 / mass_i; massinv_j = 1.0 / mass_j; // Compute the mechanical and conductive energy, uMech and uCond mu_ij = massinv_i + massinv_j; mu_ij *= force->ftm2v; uTmp = gamma_ij*wd*rinv*rinv*dot*dot - 0.5*sigma[itype][jtype]*sigma[itype][jtype]*mu_ij*wd; uTmp -= sigma[itype][jtype]*wr*rinv*dot*randnum*dtinvsqrt; uTmp *= 0.5; duMech[i] += uTmp; if (newton_pair || j < nlocal) { duMech[j] += uTmp; } // Compute uCond randnum = random->gaussian(); kappa_ij = kappa[itype][jtype]; alpha_ij = sqrt(2.0*force->boltz*kappa_ij); randPair = alpha_ij*wr*randnum*dtinvsqrt; uTmp = kappa_ij*(1.0/dpdTheta[i] - 1.0/dpdTheta[j])*wd; uTmp += randPair; duCond[i] += uTmp; if (newton_pair || j < nlocal) { duCond[j] -= uTmp; } if (eflag) { // unshifted eng of conservative term: // evdwl = -a0[itype][jtype]*r * (1.0-0.5*r/cut[itype][jtype]); // eng shifted to 0.0 at cutoff evdwl = 0.5*a0[itype][jtype]*cut[itype][jtype] * wd; evdwl *= factor_dpd; } if (evflag) ev_tally(i,j,nlocal,newton_pair, evdwl,0.0,fpair,delx,dely,delz); } } } // Communicate the ghost delta energies to the locally owned atoms comm->reverse_comm_pair(this); } if (vflag_fdotr) virial_fdotr_compute(); } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairDPDfdtEnergy::allocate() { allocated = 1; int n = atom->ntypes; int nlocal = atom->nlocal; int nghost = atom->nghost; 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(a0,n+1,n+1,"pair:a0"); memory->create(sigma,n+1,n+1,"pair:sigma"); memory->create(kappa,n+1,n+1,"pair:kappa"); if (!splitFDT_flag) { memory->create(duCond,nlocal+nghost+1,"pair:duCond"); memory->create(duMech,nlocal+nghost+1,"pair:duMech"); } } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairDPDfdtEnergy::settings(int narg, char **arg) { // process keywords if (narg != 2) error->all(FLERR,"Illegal pair_style command"); cut_global = force->numeric(FLERR,arg[0]); seed = force->inumeric(FLERR,arg[1]); if (atom->dpd_flag != 1) error->all(FLERR,"pair_style dpd/fdt/energy requires atom_style with internal temperature and energies (e.g. dpd)"); // initialize Marsaglia RNG with processor-unique seed if (seed <= 0) error->all(FLERR,"Illegal pair_style command"); delete random; random = new RanMars(lmp,seed + comm->me); // 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 PairDPDfdtEnergy::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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double a0_one = force->numeric(FLERR,arg[2]); double sigma_one = force->numeric(FLERR,arg[3]); double cut_one = cut_global; double kappa_one; kappa_one = force->numeric(FLERR,arg[4]); if (narg == 6) cut_one = force->numeric(FLERR,arg[5]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { a0[i][j] = a0_one; sigma[i][j] = sigma_one; kappa[i][j] = kappa_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 PairDPDfdtEnergy::init_style() { if (comm->ghost_velocity == 0) error->all(FLERR,"Pair dpd/fdt/energy requires ghost atoms store velocity"); // if newton off, forces between atoms ij will be double computed // using different random numbers if (force->newton_pair == 0 && comm->me == 0) error->warning(FLERR, "Pair dpd/fdt/energy requires newton pair on"); splitFDT_flag = false; int irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->ssa = 0; for (int i = 0; i < modify->nfix; i++) if (strcmp(modify->fix[i]->style,"shardlow") == 0){ splitFDT_flag = true; neighbor->requests[irequest]->ssa = 1; } bool eos_flag = false; for (int i = 0; i < modify->nfix; i++) if (strncmp(modify->fix[i]->style,"eos",3) == 0) eos_flag = true; if(!eos_flag) error->all(FLERR,"pair_style dpd/fdt/energy requires an EOS to be specified"); } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairDPDfdtEnergy::init_one(int i, int j) { if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set"); cut[j][i] = cut[i][j]; a0[j][i] = a0[i][j]; sigma[j][i] = sigma[i][j]; kappa[j][i] = kappa[i][j]; return cut[i][j]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairDPDfdtEnergy::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(&a0[i][j],sizeof(double),1,fp); fwrite(&sigma[i][j],sizeof(double),1,fp); fwrite(&kappa[i][j],sizeof(double),1,fp); fwrite(&cut[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairDPDfdtEnergy::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(&a0[i][j],sizeof(double),1,fp); fread(&sigma[i][j],sizeof(double),1,fp); fread(&kappa[i][j],sizeof(double),1,fp); fread(&cut[i][j],sizeof(double),1,fp); } MPI_Bcast(&a0[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&kappa[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairDPDfdtEnergy::write_restart_settings(FILE *fp) { fwrite(&cut_global,sizeof(double),1,fp); fwrite(&seed,sizeof(int),1,fp); fwrite(&mix_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairDPDfdtEnergy::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&cut_global,sizeof(double),1,fp); fread(&seed,sizeof(int),1,fp); fread(&mix_flag,sizeof(int),1,fp); } MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world); MPI_Bcast(&seed,1,MPI_INT,0,world); MPI_Bcast(&mix_flag,1,MPI_INT,0,world); // initialize Marsaglia RNG with processor-unique seed // same seed that pair_style command initially specified if (random) delete random; random = new RanMars(lmp,seed + comm->me); } /* ---------------------------------------------------------------------- */ double PairDPDfdtEnergy::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_dpd, double &fforce) { double r,rinv,wr,wd,phi; r = sqrt(rsq); if (r < EPSILON) { fforce = 0.0; return 0.0; } rinv = 1.0/r; wr = 1.0 - r/cut[itype][jtype]; wd = wr*wr; fforce = a0[itype][jtype]*wr * factor_dpd*rinv; phi = 0.5*a0[itype][jtype]*cut[itype][jtype] * wd; return factor_dpd*phi; } /* ---------------------------------------------------------------------- */ int PairDPDfdtEnergy::pack_reverse_comm(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { buf[m++] = duCond[i]; buf[m++] = duMech[i]; } return m; } /* ---------------------------------------------------------------------- */ void PairDPDfdtEnergy::unpack_reverse_comm(int n, int *list, double *buf) { int i,j,m; m = 0; for (i = 0; i < n; i++) { j = list[i]; duCond[j] += buf[m++]; duMech[j] += buf[m++]; } } diff --git a/src/USER-DPD/pair_exp6_rx.cpp b/src/USER-DPD/pair_exp6_rx.cpp index ad2dbf146..9af28026a 100644 --- a/src/USER-DPD/pair_exp6_rx.cpp +++ b/src/USER-DPD/pair_exp6_rx.cpp @@ -1,1131 +1,1131 @@ /* ---------------------------------------------------------------------- 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 #include #include #include #include "pair_exp6_rx.h" #include "atom.h" #include "comm.h" #include "force.h" #include "neigh_list.h" #include "math_const.h" #include "math_special.h" #include "memory.h" #include "error.h" #include "modify.h" #include "fix.h" #include using namespace LAMMPS_NS; using namespace MathConst; using namespace MathSpecial; #define MAXLINE 1024 #define DELTA 4 #define oneFluidApproxParameter (-1) #define isOneFluidApprox(_site) ( (_site) == oneFluidApproxParameter ) #define exp6PotentialType (1) #define isExp6PotentialType(_type) ( (_type) == exp6PotentialType ) // Create a structure to hold the parameter data for all // local and neighbor particles. Pack inside this struct // to avoid any name clashes. struct PairExp6ParamDataType { int n; double *epsilon1, *alpha1, *rm1, *fraction1, *epsilon2, *alpha2, *rm2, *fraction2, *epsilonOld1, *alphaOld1, *rmOld1, *fractionOld1, *epsilonOld2, *alphaOld2, *rmOld2, *fractionOld2; // Default constructor -- nullify everything. PairExp6ParamDataType(void) : n(0), epsilon1(NULL), alpha1(NULL), rm1(NULL), fraction1(NULL), epsilon2(NULL), alpha2(NULL), rm2(NULL), fraction2(NULL), epsilonOld1(NULL), alphaOld1(NULL), rmOld1(NULL), fractionOld1(NULL), epsilonOld2(NULL), alphaOld2(NULL), rmOld2(NULL), fractionOld2(NULL) {} }; /* ---------------------------------------------------------------------- */ PairExp6rx::PairExp6rx(LAMMPS *lmp) : Pair(lmp) { writedata = 1; nspecies = 0; nparams = maxparam = 0; params = NULL; mol2param = NULL; } /* ---------------------------------------------------------------------- */ PairExp6rx::~PairExp6rx() { for (int i=0; i < nparams; ++i) { delete[] params[i].name; delete[] params[i].potential; } memory->destroy(params); memory->destroy(mol2param); if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut); } } /* ---------------------------------------------------------------------- */ void PairExp6rx::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,evdwlOld,fpair; double rsq,r2inv,r6inv,forceExp6,factor_lj; double rCut,rCutInv,rCut2inv,rCut6inv,rCutExp,urc,durc; double rm2ij,rm6ij; double r,rexp; int *ilist,*jlist,*numneigh,**firstneigh; evdwlOld = 0.0; 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; double alphaOld12_ij, rmOld12_ij, epsilonOld12_ij; double alphaOld21_ij, rmOld21_ij, epsilonOld21_ij; double alpha12_ij, rm12_ij, epsilon12_ij; double alpha21_ij, rm21_ij, epsilon21_ij; double rminv, buck1, buck2; double epsilonOld1_i,alphaOld1_i,rmOld1_i; double epsilonOld1_j,alphaOld1_j,rmOld1_j; double epsilonOld2_i,alphaOld2_i,rmOld2_i; double epsilonOld2_j,alphaOld2_j,rmOld2_j; double epsilon1_i,alpha1_i,rm1_i; double epsilon1_j,alpha1_j,rm1_j; double epsilon2_i,alpha2_i,rm2_i; double epsilon2_j,alpha2_j,rm2_j; double evdwlOldEXP6_12, evdwlOldEXP6_21, fpairOldEXP6_12, fpairOldEXP6_21; double evdwlEXP6_12, evdwlEXP6_21; double fractionOld1_i, fractionOld1_j; double fractionOld2_i, fractionOld2_j; double fraction1_i, fraction1_j; double fraction2_i, fraction2_j; double *uCG = atom->uCG; double *uCGnew = atom->uCGnew; const int nRep = 12; const double shift = 1.05; double rin1, aRep, uin1, win1, uin1rep, rin1exp, rin6, rin6inv; // Initialize the Exp6 parameter data for both the local // and ghost atoms. Make the parameter data persistent // and exchange like any other atom property later. PairExp6ParamDataType PairExp6ParamData; { const int np_total = nlocal + atom->nghost; memory->create( PairExp6ParamData.epsilon1 , np_total, "PairExp6ParamData.epsilon1"); memory->create( PairExp6ParamData.alpha1 , np_total, "PairExp6ParamData.alpha1"); memory->create( PairExp6ParamData.rm1 , np_total, "PairExp6ParamData.rm1"); memory->create( PairExp6ParamData.fraction1 , np_total, "PairExp6ParamData.fraction1"); memory->create( PairExp6ParamData.epsilon2 , np_total, "PairExp6ParamData.epsilon2"); memory->create( PairExp6ParamData.alpha2 , np_total, "PairExp6ParamData.alpha2"); memory->create( PairExp6ParamData.rm2 , np_total, "PairExp6ParamData.rm2"); memory->create( PairExp6ParamData.fraction2 , np_total, "PairExp6ParamData.fraction2"); memory->create( PairExp6ParamData.epsilonOld1 , np_total, "PairExp6ParamData.epsilonOld1"); memory->create( PairExp6ParamData.alphaOld1 , np_total, "PairExp6ParamData.alphaOld1"); memory->create( PairExp6ParamData.rmOld1 , np_total, "PairExp6ParamData.rmOld1"); memory->create( PairExp6ParamData.fractionOld1 , np_total, "PairExp6ParamData.fractionOld1"); memory->create( PairExp6ParamData.epsilonOld2 , np_total, "PairExp6ParamData.epsilonOld2"); memory->create( PairExp6ParamData.alphaOld2 , np_total, "PairExp6ParamData.alphaOld2"); memory->create( PairExp6ParamData.rmOld2 , np_total, "PairExp6ParamData.rmOld2"); memory->create( PairExp6ParamData.fractionOld2 , np_total, "PairExp6ParamData.fractionOld2"); for (i = 0; i < np_total; ++i) { getParamsEXP6 (i, PairExp6ParamData.epsilon1[i], PairExp6ParamData.alpha1[i], PairExp6ParamData.rm1[i], PairExp6ParamData.fraction1[i], PairExp6ParamData.epsilon2[i], PairExp6ParamData.alpha2[i], PairExp6ParamData.rm2[i], PairExp6ParamData.fraction2[i], PairExp6ParamData.epsilonOld1[i], PairExp6ParamData.alphaOld1[i], PairExp6ParamData.rmOld1[i], PairExp6ParamData.fractionOld1[i], PairExp6ParamData.epsilonOld2[i], PairExp6ParamData.alphaOld2[i], PairExp6ParamData.rmOld2[i], PairExp6ParamData.fractionOld2[i]); } } 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]; { epsilon1_i = PairExp6ParamData.epsilon1[i]; alpha1_i = PairExp6ParamData.alpha1[i]; rm1_i = PairExp6ParamData.rm1[i]; fraction1_i = PairExp6ParamData.fraction1[i]; epsilon2_i = PairExp6ParamData.epsilon2[i]; alpha2_i = PairExp6ParamData.alpha2[i]; rm2_i = PairExp6ParamData.rm2[i]; fraction2_i = PairExp6ParamData.fraction2[i]; epsilonOld1_i = PairExp6ParamData.epsilonOld1[i]; alphaOld1_i = PairExp6ParamData.alphaOld1[i]; rmOld1_i = PairExp6ParamData.rmOld1[i]; fractionOld1_i = PairExp6ParamData.fractionOld1[i]; epsilonOld2_i = PairExp6ParamData.epsilonOld2[i]; alphaOld2_i = PairExp6ParamData.alphaOld2[i]; rmOld2_i = PairExp6ParamData.rmOld2[i]; fractionOld2_i = PairExp6ParamData.fractionOld2[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); rCut2inv = 1.0/cutsq[itype][jtype]; rCut6inv = rCut2inv*rCut2inv*rCut2inv; rCut = sqrt(cutsq[itype][jtype]); rCutInv = 1.0/rCut; // // A. Compute the exp-6 potential // // A1. Get alpha, epsilon and rm for particle j { epsilon1_j = PairExp6ParamData.epsilon1[j]; alpha1_j = PairExp6ParamData.alpha1[j]; rm1_j = PairExp6ParamData.rm1[j]; fraction1_j = PairExp6ParamData.fraction1[j]; epsilon2_j = PairExp6ParamData.epsilon2[j]; alpha2_j = PairExp6ParamData.alpha2[j]; rm2_j = PairExp6ParamData.rm2[j]; fraction2_j = PairExp6ParamData.fraction2[j]; epsilonOld1_j = PairExp6ParamData.epsilonOld1[j]; alphaOld1_j = PairExp6ParamData.alphaOld1[j]; rmOld1_j = PairExp6ParamData.rmOld1[j]; fractionOld1_j = PairExp6ParamData.fractionOld1[j]; epsilonOld2_j = PairExp6ParamData.epsilonOld2[j]; alphaOld2_j = PairExp6ParamData.alphaOld2[j]; rmOld2_j = PairExp6ParamData.rmOld2[j]; fractionOld2_j = PairExp6ParamData.fractionOld2[j]; } // A2. Apply Lorentz-Berthelot mixing rules for the i-j pair alphaOld12_ij = sqrt(alphaOld1_i*alphaOld2_j); rmOld12_ij = 0.5*(rmOld1_i + rmOld2_j); epsilonOld12_ij = sqrt(epsilonOld1_i*epsilonOld2_j); alphaOld21_ij = sqrt(alphaOld2_i*alphaOld1_j); rmOld21_ij = 0.5*(rmOld2_i + rmOld1_j); epsilonOld21_ij = sqrt(epsilonOld2_i*epsilonOld1_j); alpha12_ij = sqrt(alpha1_i*alpha2_j); rm12_ij = 0.5*(rm1_i + rm2_j); epsilon12_ij = sqrt(epsilon1_i*epsilon2_j); alpha21_ij = sqrt(alpha2_i*alpha1_j); rm21_ij = 0.5*(rm2_i + rm1_j); epsilon21_ij = sqrt(epsilon2_i*epsilon1_j); if(rmOld12_ij!=0.0 && rmOld21_ij!=0.0){ if(alphaOld21_ij == 6.0 || alphaOld12_ij == 6.0) error->all(FLERR,"alpha_ij is 6.0 in pair exp6"); // A3. Compute some convenient quantities for evaluating the force rminv = 1.0/rmOld12_ij; buck1 = epsilonOld12_ij / (alphaOld12_ij - 6.0); rexp = expValue(alphaOld12_ij*(1.0-r*rminv)); rm2ij = rmOld12_ij*rmOld12_ij; rm6ij = rm2ij*rm2ij*rm2ij; // Compute the shifted potential rCutExp = expValue(alphaOld12_ij*(1.0-rCut*rminv)); buck2 = 6.0*alphaOld12_ij; urc = buck1*(6.0*rCutExp - alphaOld12_ij*rm6ij*rCut6inv); durc = -buck1*buck2*(rCutExp* rminv - rCutInv*rm6ij*rCut6inv); rin1 = shift*rmOld12_ij*func_rin(alphaOld12_ij); if(r < rin1){ rin6 = rin1*rin1*rin1*rin1*rin1*rin1; rin6inv = 1.0/rin6; rin1exp = expValue(alphaOld12_ij*(1.0-rin1*rminv)); uin1 = buck1*(6.0*rin1exp - alphaOld12_ij*rm6ij*rin6inv) - urc - durc*(rin1-rCut); win1 = -buck1*buck2*(rin1*rin1exp*rminv - rm6ij*rin6inv) - rin1*durc; aRep = -1.0*win1*powint(rin1,nRep)/nRep; uin1rep = aRep/powint(rin1,nRep); forceExp6 = -double(nRep)*aRep/powint(r,nRep); fpairOldEXP6_12 = factor_lj*forceExp6*r2inv; evdwlOldEXP6_12 = uin1 - uin1rep + aRep/powint(r,nRep); } else { forceExp6 = buck1*buck2*(r*rexp*rminv - rm6ij*r6inv) + r*durc; fpairOldEXP6_12 = factor_lj*forceExp6*r2inv; evdwlOldEXP6_12 = buck1*(6.0*rexp - alphaOld12_ij*rm6ij*r6inv) - urc - durc*(r-rCut); } // A3. Compute some convenient quantities for evaluating the force rminv = 1.0/rmOld21_ij; buck1 = epsilonOld21_ij / (alphaOld21_ij - 6.0); buck2 = 6.0*alphaOld21_ij; rexp = expValue(alphaOld21_ij*(1.0-r*rminv)); rm2ij = rmOld21_ij*rmOld21_ij; rm6ij = rm2ij*rm2ij*rm2ij; // Compute the shifted potential rCutExp = expValue(alphaOld21_ij*(1.0-rCut*rminv)); buck2 = 6.0*alphaOld21_ij; urc = buck1*(6.0*rCutExp - alphaOld21_ij*rm6ij*rCut6inv); durc = -buck1*buck2*(rCutExp* rminv - rCutInv*rm6ij*rCut6inv); rin1 = shift*rmOld21_ij*func_rin(alphaOld21_ij); if(r < rin1){ rin6 = rin1*rin1*rin1*rin1*rin1*rin1; rin6inv = 1.0/rin6; rin1exp = expValue(alphaOld21_ij*(1.0-rin1*rminv)); uin1 = buck1*(6.0*rin1exp - alphaOld21_ij*rm6ij*rin6inv) - urc - durc*(rin1-rCut); win1 = -buck1*buck2*(rin1*rin1exp*rminv - rm6ij*rin6inv) - rin1*durc; aRep = -1.0*win1*powint(rin1,nRep)/nRep; uin1rep = aRep/powint(rin1,nRep); forceExp6 = -double(nRep)*aRep/powint(r,nRep); fpairOldEXP6_21 = factor_lj*forceExp6*r2inv; evdwlOldEXP6_21 = uin1 - uin1rep + aRep/powint(r,nRep); } else { forceExp6 = buck1*buck2*(r*rexp*rminv - rm6ij*r6inv) + r*durc; fpairOldEXP6_21 = factor_lj*forceExp6*r2inv; evdwlOldEXP6_21 = buck1*(6.0*rexp - alphaOld21_ij*rm6ij*r6inv) - urc - durc*(r-rCut); } if (isite1 == isite2) evdwlOld = sqrt(fractionOld1_i*fractionOld2_j)*evdwlOldEXP6_12; else evdwlOld = sqrt(fractionOld1_i*fractionOld2_j)*evdwlOldEXP6_12 + sqrt(fractionOld2_i*fractionOld1_j)*evdwlOldEXP6_21; evdwlOld *= factor_lj; uCG[i] += 0.5*evdwlOld; if (newton_pair || j < nlocal) uCG[j] += 0.5*evdwlOld; } if(rm12_ij!=0.0 && rm21_ij!=0.0){ if(alpha21_ij == 6.0 || alpha12_ij == 6.0) error->all(FLERR,"alpha_ij is 6.0 in pair exp6"); // A3. Compute some convenient quantities for evaluating the force rminv = 1.0/rm12_ij; buck1 = epsilon12_ij / (alpha12_ij - 6.0); buck2 = 6.0*alpha12_ij; rexp = expValue(alpha12_ij*(1.0-r*rminv)); rm2ij = rm12_ij*rm12_ij; rm6ij = rm2ij*rm2ij*rm2ij; // Compute the shifted potential rCutExp = expValue(alpha12_ij*(1.0-rCut*rminv)); urc = buck1*(6.0*rCutExp - alpha12_ij*rm6ij*rCut6inv); durc = -buck1*buck2*(rCutExp*rminv - rCutInv*rm6ij*rCut6inv); rin1 = shift*rm12_ij*func_rin(alpha12_ij); if(r < rin1){ rin6 = rin1*rin1*rin1*rin1*rin1*rin1; rin6inv = 1.0/rin6; rin1exp = expValue(alpha12_ij*(1.0-rin1*rminv)); uin1 = buck1*(6.0*rin1exp - alpha12_ij*rm6ij*rin6inv) - urc - durc*(rin1-rCut); win1 = -buck1*buck2*(rin1*rin1exp*rminv - rm6ij*rin6inv) - rin1*durc; aRep = -1.0*win1*powint(rin1,nRep)/nRep; uin1rep = aRep/powint(rin1,nRep); evdwlEXP6_12 = uin1 - uin1rep + aRep/powint(r,nRep); } else { evdwlEXP6_12 = buck1*(6.0*rexp - alpha12_ij*rm6ij*r6inv) - urc - durc*(r-rCut); } rminv = 1.0/rm21_ij; buck1 = epsilon21_ij / (alpha21_ij - 6.0); buck2 = 6.0*alpha21_ij; rexp = expValue(alpha21_ij*(1.0-r*rminv)); rm2ij = rm21_ij*rm21_ij; rm6ij = rm2ij*rm2ij*rm2ij; // Compute the shifted potential rCutExp = expValue(alpha21_ij*(1.0-rCut*rminv)); urc = buck1*(6.0*rCutExp - alpha21_ij*rm6ij*rCut6inv); durc = -buck1*buck2*(rCutExp*rminv - rCutInv*rm6ij*rCut6inv); rin1 = shift*rm21_ij*func_rin(alpha21_ij); if(r < rin1){ rin6 = rin1*rin1*rin1*rin1*rin1*rin1; rin6inv = 1.0/rin6; rin1exp = expValue(alpha21_ij*(1.0-rin1*rminv)); uin1 = buck1*(6.0*rin1exp - alpha21_ij*rm6ij*rin6inv) - urc - durc*(rin1-rCut); win1 = -buck1*buck2*(rin1*rin1exp*rminv - rm6ij*rin6inv) - rin1*durc; aRep = -1.0*win1*powint(rin1,nRep)/nRep; uin1rep = aRep/powint(rin1,nRep); evdwlEXP6_21 = uin1 - uin1rep + aRep/powint(r,nRep); } else { evdwlEXP6_21 = buck1*(6.0*rexp - alpha21_ij*rm6ij*r6inv) - urc - durc*(r-rCut); } // // Apply Mixing Rule to get the overall force for the CG pair // if (isite1 == isite2) fpair = sqrt(fractionOld1_i*fractionOld2_j)*fpairOldEXP6_12; else fpair = sqrt(fractionOld1_i*fractionOld2_j)*fpairOldEXP6_12 + sqrt(fractionOld2_i*fractionOld1_j)*fpairOldEXP6_21; 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 (isite1 == isite2) evdwl = sqrt(fraction1_i*fraction2_j)*evdwlEXP6_12; else evdwl = sqrt(fraction1_i*fraction2_j)*evdwlEXP6_12 + sqrt(fraction2_i*fraction1_j)*evdwlEXP6_21; evdwl *= factor_lj; uCGnew[i] += 0.5*evdwl; if (newton_pair || j < nlocal) uCGnew[j] += 0.5*evdwl; evdwl = evdwlOld; if (evflag) ev_tally(i,j,nlocal,newton_pair, evdwl,0.0,fpair,delx,dely,delz); } } } } if (vflag_fdotr) virial_fdotr_compute(); // Release the local parameter data. { if (PairExp6ParamData.epsilon1 ) memory->destroy(PairExp6ParamData.epsilon1); if (PairExp6ParamData.alpha1 ) memory->destroy(PairExp6ParamData.alpha1); if (PairExp6ParamData.rm1 ) memory->destroy(PairExp6ParamData.rm1); if (PairExp6ParamData.fraction1 ) memory->destroy(PairExp6ParamData.fraction1); if (PairExp6ParamData.epsilon2 ) memory->destroy(PairExp6ParamData.epsilon2); if (PairExp6ParamData.alpha2 ) memory->destroy(PairExp6ParamData.alpha2); if (PairExp6ParamData.rm2 ) memory->destroy(PairExp6ParamData.rm2); if (PairExp6ParamData.fraction2 ) memory->destroy(PairExp6ParamData.fraction2); if (PairExp6ParamData.epsilonOld1 ) memory->destroy(PairExp6ParamData.epsilonOld1); if (PairExp6ParamData.alphaOld1 ) memory->destroy(PairExp6ParamData.alphaOld1); if (PairExp6ParamData.rmOld1 ) memory->destroy(PairExp6ParamData.rmOld1); if (PairExp6ParamData.fractionOld1) memory->destroy(PairExp6ParamData.fractionOld1); if (PairExp6ParamData.epsilonOld2 ) memory->destroy(PairExp6ParamData.epsilonOld2); if (PairExp6ParamData.alphaOld2 ) memory->destroy(PairExp6ParamData.alphaOld2); if (PairExp6ParamData.rmOld2 ) memory->destroy(PairExp6ParamData.rmOld2); if (PairExp6ParamData.fractionOld2) memory->destroy(PairExp6ParamData.fractionOld2); } } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairExp6rx::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"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairExp6rx::settings(int narg, char **arg) { if (narg != 1) error->all(FLERR,"Illegal pair_style command"); cut_global = force->numeric(FLERR,arg[0]); 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; } allocated = 0; } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairExp6rx::coeff(int narg, char **arg) { if (narg < 7 || narg > 8) error->all(FLERR,"Incorrect args for pair coefficients"); bool rx_flag = false; for (int i = 0; i < modify->nfix; i++) if (strncmp(modify->fix[i]->style,"rx",2) == 0) rx_flag = true; if (!rx_flag) error->all(FLERR,"PairExp6rx requires a fix rx command."); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; int n; - force->bounds(arg[0],atom->ntypes,ilo,ihi); - force->bounds(arg[1],atom->ntypes,jlo,jhi); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); nspecies = atom->nspecies_dpd; if(nspecies==0) error->all(FLERR,"There are no rx species specified."); read_file(arg[2]); n = strlen(arg[3]) + 1; site1 = new char[n]; strcpy(site1,arg[3]); int ispecies; for (ispecies = 0; ispecies < nspecies; ispecies++){ if (strcmp(site1,&atom->dname[ispecies][0]) == 0) break; } if (ispecies == nspecies && strcmp(site1,"1fluid") != 0) error->all(FLERR,"Site1 name not recognized in pair coefficients"); n = strlen(arg[4]) + 1; site2 = new char[n]; strcpy(site2,arg[4]); for (ispecies = 0; ispecies < nspecies; ispecies++){ if (strcmp(site2,&atom->dname[ispecies][0]) == 0) break; } if (ispecies == nspecies && strcmp(site2,"1fluid") != 0) error->all(FLERR,"Site2 name not recognized in pair coefficients"); { // Set isite1 and isite2 parameters based on site1 and site2 strings. if (strcmp(site1,"1fluid") == 0) isite1 = oneFluidApproxParameter; else { int isp; for (isp = 0; isp < nspecies; isp++) if (strcmp(site1, &atom->dname[isp][0]) == 0) break; if (isp == nspecies) error->all(FLERR,"Site1 name not recognized in pair coefficients"); else isite1 = isp; } if (strcmp(site2,"1fluid") == 0) isite2 = oneFluidApproxParameter; else { int isp; for (isp = 0; isp < nspecies; isp++) if (strcmp(site2, &atom->dname[isp][0]) == 0) break; if (isp == nspecies) error->all(FLERR,"Site2 name not recognized in pair coefficients"); else isite2 = isp; } // Set the interaction potential type to the enumerated type. for (int iparam = 0; iparam < nparams; ++iparam) { if (strcmp( params[iparam].potential, "exp6") == 0) params[iparam].potentialType = exp6PotentialType; else error->all(FLERR,"params[].potential type unknown"); //printf("params[%d].name= %s ispecies= %d potential= %s potentialType= %d\n", iparam, params[iparam].name, params[iparam].ispecies, params[iparam].potential, params[iparam].potentialType); } } delete[] site1; delete[] site2; site1 = site2 = NULL; fuchslinR = force->numeric(FLERR,arg[5]); fuchslinEpsilon = force->numeric(FLERR,arg[6]); setup(); double cut_one = cut_global; if (narg == 8) cut_one = force->numeric(FLERR,arg[7]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { 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 PairExp6rx::init_one(int i, int j) { if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set"); return cut[i][j]; } /* ---------------------------------------------------------------------- */ void PairExp6rx::read_file(char *file) { int params_per_line = 5; char **words = new char*[params_per_line+1]; memory->sfree(params); params = NULL; nparams = maxparam = 0; // open file on proc 0 FILE *fp; fp = NULL; if (comm->me == 0) { fp = force->open_potential(file); if (fp == NULL) { char str[128]; sprintf(str,"Cannot open exp6/rx potential file %s",file); error->one(FLERR,str); } } // read each set of params from potential file // one set of params can span multiple lines int n,nwords,ispecies; char line[MAXLINE],*ptr; int 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'; 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 exp6/rx potential file"); // words = ptrs to all words in line nwords = 0; words[nwords++] = strtok(line," \t\n\r\f"); while ((words[nwords++] = strtok(NULL," \t\n\r\f"))) continue; for (ispecies = 0; ispecies < nspecies; ispecies++) if (strcmp(words[0],&atom->dname[ispecies][0]) == 0) break; if (ispecies == nspecies) continue; // load up parameter settings and error check their values if (nparams == maxparam) { maxparam += DELTA; params = (Param *) memory->srealloc(params,maxparam*sizeof(Param), "pair:params"); } params[nparams].ispecies = ispecies; n = strlen(&atom->dname[ispecies][0]) + 1; params[nparams].name = new char[n]; strcpy(params[nparams].name,&atom->dname[ispecies][0]); n = strlen(words[1]) + 1; params[nparams].potential = new char[n]; strcpy(params[nparams].potential,words[1]); if (strcmp(params[nparams].potential,"exp6") == 0){ params[nparams].alpha = atof(words[2]); params[nparams].epsilon = atof(words[3]); params[nparams].rm = atof(words[4]); if (params[nparams].epsilon <= 0.0 || params[nparams].rm <= 0.0 || params[nparams].alpha < 0.0) error->all(FLERR,"Illegal exp6/rx parameters. Rm and Epsilon must be greater than zero. Alpha cannot be negative."); } else { error->all(FLERR,"Illegal exp6/rx parameters. Interaction potential does not exist."); } nparams++; } delete [] words; } /* ---------------------------------------------------------------------- */ void PairExp6rx::setup() { int i,j,n; // set mol2param for all combinations // must be a single exact match to lines read from file memory->destroy(mol2param); memory->create(mol2param,nspecies,"pair:mol2param"); for (i = 0; i < nspecies; i++) { n = -1; for (j = 0; j < nparams; j++) { if (i == params[j].ispecies) { if (n >= 0) error->all(FLERR,"Potential file has duplicate entry"); n = j; } } mol2param[i] = n; } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairExp6rx::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 PairExp6rx::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 PairExp6rx::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); fwrite(&tail_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairExp6rx::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); fread(&tail_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); MPI_Bcast(&tail_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- */ void PairExp6rx::getParamsEXP6(int id,double &epsilon1,double &alpha1,double &rm1, double &fraction1,double &epsilon2,double &alpha2,double &rm2,double &fraction2,double &epsilon1_old,double &alpha1_old,double &rm1_old, double &fraction1_old,double &epsilon2_old,double &alpha2_old,double &rm2_old,double &fraction2_old) const { int iparam, jparam; double rmi, rmj, rmij, rm3ij; double epsiloni, epsilonj, epsilonij; double alphai, alphaj, alphaij; double epsilon_old, rm3_old, alpha_old; double epsilon, rm3, alpha; double fractionOFA, fractionOFA_old; double nTotalOFA, nTotalOFA_old; double nTotal, nTotal_old; double xMolei, xMolej, xMolei_old, xMolej_old; rm3 = 0.0; epsilon = 0.0; alpha = 0.0; epsilon_old = 0.0; rm3_old = 0.0; alpha_old = 0.0; fractionOFA = 0.0; fractionOFA_old = 0.0; nTotalOFA = 0.0; nTotalOFA_old = 0.0; nTotal = 0.0; nTotal_old = 0.0; // Compute the total number of molecules in the old and new CG particle as well as the total number of molecules in the fluid portion of the old and new CG particle for (int ispecies = 0; ispecies < nspecies; ispecies++){ nTotal += atom->dvector[ispecies][id]; nTotal_old += atom->dvector[ispecies+nspecies][id]; iparam = mol2param[ispecies]; if (iparam < 0 || params[iparam].potentialType != exp6PotentialType ) continue; if (isOneFluidApprox(isite1) || isOneFluidApprox(isite2)) { if (isite1 == params[iparam].ispecies || isite2 == params[iparam].ispecies) continue; nTotalOFA_old += atom->dvector[ispecies+nspecies][id]; nTotalOFA += atom->dvector[ispecies][id]; } } if(nTotal < 1e-8 || nTotal_old < 1e-8) error->all(FLERR,"The number of molecules in CG particle is less than 1e-8."); // Compute the mole fraction of molecules within the fluid portion of the particle (One Fluid Approximation) fractionOFA_old = nTotalOFA_old / nTotal_old; fractionOFA = nTotalOFA / nTotal; for (int ispecies = 0; ispecies < nspecies; ispecies++) { iparam = mol2param[ispecies]; if (iparam < 0 || params[iparam].potentialType != exp6PotentialType ) continue; // If Site1 matches a pure species, then grab the parameters if (isite1 == params[iparam].ispecies){ rm1_old = params[iparam].rm; rm1 = params[iparam].rm; epsilon1_old = params[iparam].epsilon; epsilon1 = params[iparam].epsilon; alpha1_old = params[iparam].alpha; alpha1 = params[iparam].alpha; // Compute the mole fraction of Site1 fraction1_old = atom->dvector[ispecies+nspecies][id]/nTotal_old; fraction1 = atom->dvector[ispecies][id]/nTotal; } // If Site2 matches a pure species, then grab the parameters if (isite2 == params[iparam].ispecies){ rm2_old = params[iparam].rm; rm2 = params[iparam].rm; epsilon2_old = params[iparam].epsilon; epsilon2 = params[iparam].epsilon; alpha2_old = params[iparam].alpha; alpha2 = params[iparam].alpha; // Compute the mole fraction of Site2 fraction2_old = atom->dvector[ispecies+nspecies][id]/nTotal_old; fraction2 = atom->dvector[ispecies][id]/nTotal; } // If Site1 or Site2 matches is a fluid, then compute the paramters if (isOneFluidApprox(isite1) || isOneFluidApprox(isite2)) { if (isite1 == params[iparam].ispecies || isite2 == params[iparam].ispecies) continue; rmi = params[iparam].rm; epsiloni = params[iparam].epsilon; alphai = params[iparam].alpha; xMolei = atom->dvector[ispecies][id]/nTotalOFA; xMolei_old = atom->dvector[ispecies+nspecies][id]/nTotalOFA_old; for (int jspecies = 0; jspecies < nspecies; jspecies++) { jparam = mol2param[jspecies]; if (jparam < 0 || params[jparam].potentialType != exp6PotentialType ) continue; if (isite1 == params[jparam].ispecies || isite2 == params[jparam].ispecies) continue; rmj = params[jparam].rm; epsilonj = params[jparam].epsilon; alphaj = params[jparam].alpha; xMolej = atom->dvector[jspecies][id]/nTotalOFA; xMolej_old = atom->dvector[jspecies+nspecies][id]/nTotalOFA_old; rmij = (rmi+rmj)/2.0; rm3ij = rmij*rmij*rmij; epsilonij = sqrt(epsiloni*epsilonj); alphaij = sqrt(alphai*alphaj); if(fractionOFA_old > 0.0){ rm3_old += xMolei_old*xMolej_old*rm3ij; epsilon_old += xMolei_old*xMolej_old*rm3ij*epsilonij; alpha_old += xMolei_old*xMolej_old*rm3ij*epsilonij*alphaij; } if(fractionOFA > 0.0){ rm3 += xMolei*xMolej*rm3ij; epsilon += xMolei*xMolej*rm3ij*epsilonij; alpha += xMolei*xMolej*rm3ij*epsilonij*alphaij; } } } } if (isOneFluidApprox(isite1)){ rm1 = cbrt(rm3); if(rm1 < 1e-16) { rm1 = 0.0; epsilon1 = 0.0; alpha1 = 0.0; } else { epsilon1 = epsilon / rm3; alpha1 = alpha / epsilon1 / rm3; } fraction1 = fractionOFA; rm1_old = cbrt(rm3_old); if(rm1_old < 1e-16) { rm1_old = 0.0; epsilon1_old = 0.0; alpha1_old = 0.0; } else { epsilon1_old = epsilon_old / rm3_old; alpha1_old = alpha_old / epsilon1_old / rm3_old; } fraction1_old = fractionOFA_old; // Fuchslin-Like Exp-6 Scaling double powfuch = 0.0; if(fuchslinEpsilon < 0.0){ powfuch = pow(nTotalOFA,-fuchslinEpsilon); if(powfuch<1e-15) epsilon1 = 0.0; else epsilon1 *= 1.0/powfuch; powfuch = pow(nTotalOFA_old,-fuchslinEpsilon); if(powfuch<1e-15) epsilon1_old = 0.0; else epsilon1_old *= 1.0/powfuch; } else { epsilon1 *= pow(nTotalOFA,fuchslinEpsilon); epsilon1_old *= pow(nTotalOFA_old,fuchslinEpsilon); } if(fuchslinR < 0.0){ powfuch = pow(nTotalOFA,-fuchslinR); if(powfuch<1e-15) rm1 = 0.0; else rm1 *= 1.0/powfuch; powfuch = pow(nTotalOFA_old,-fuchslinR); if(powfuch<1e-15) rm1_old = 0.0; else rm1_old *= 1.0/powfuch; } else { rm1 *= pow(nTotalOFA,fuchslinR); rm1_old *= pow(nTotalOFA_old,fuchslinR); } } if (isOneFluidApprox(isite2)){ rm2 = cbrt(rm3); if(rm2 < 1e-16) { rm2 = 0.0; epsilon2 = 0.0; alpha2 = 0.0; } else { epsilon2 = epsilon / rm3; alpha2 = alpha / epsilon2 / rm3; } fraction2 = fractionOFA; rm2_old = cbrt(rm3_old); if(rm2_old < 1e-16) { rm2_old = 0.0; epsilon2_old = 0.0; alpha2_old = 0.0; } else { epsilon2_old = epsilon_old / rm3_old; alpha2_old = alpha_old / epsilon2_old / rm3_old; } fraction2_old = fractionOFA_old; // Fuchslin-Like Exp-6 Scaling double powfuch = 0.0; if(fuchslinEpsilon < 0.0){ powfuch = pow(nTotalOFA,-fuchslinEpsilon); if(powfuch<1e-15) epsilon2 = 0.0; else epsilon2 *= 1.0/powfuch; powfuch = pow(nTotalOFA_old,-fuchslinEpsilon); if(powfuch<1e-15) epsilon2_old = 0.0; else epsilon2_old *= 1.0/powfuch; } else { epsilon2 *= pow(nTotalOFA,fuchslinEpsilon); epsilon2_old *= pow(nTotalOFA_old,fuchslinEpsilon); } if(fuchslinR < 0.0){ powfuch = pow(nTotalOFA,-fuchslinR); if(powfuch<1e-15) rm2 = 0.0; else rm2 *= 1.0/powfuch; powfuch = pow(nTotalOFA_old,-fuchslinR); if(powfuch<1e-15) rm2_old = 0.0; else rm2_old *= 1.0/powfuch; } else { rm2 *= pow(nTotalOFA,fuchslinR); rm2_old *= pow(nTotalOFA_old,fuchslinR); } } } /* ---------------------------------------------------------------------- */ inline double PairExp6rx::func_rin(const double &alpha) const { double function; const double a = 3.7682065; const double b = -1.4308614; function = a+b*sqrt(alpha); function = expValue(function); return function; } /* ---------------------------------------------------------------------- */ inline double PairExp6rx::expValue(double value) const { double returnValue; if(value < DBL_MIN_EXP) returnValue = 0.0; else returnValue = exp(value); return returnValue; } diff --git a/src/USER-DPD/pair_multi_lucy.cpp b/src/USER-DPD/pair_multi_lucy.cpp index a063eff19..a4ea8cad2 100644 --- a/src/USER-DPD/pair_multi_lucy.cpp +++ b/src/USER-DPD/pair_multi_lucy.cpp @@ -1,833 +1,833 @@ /* ---------------------------------------------------------------------- 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: James Larentzos and Joshua Moore (U.S. Army Research Laboratory) Please cite the related publications: J.D. Moore, B.C. Barnes, S. Izvekov, M. Lisal, M.S. Sellers, D.E. Taylor & J.K. Brennan "A coarse-grain force field for RDX: Density dependent and energy conserving" The Journal of Chemical Physics, 2016, 144, 104501. ------------------------------------------------------------------------------------------- */ #include #include #include "math_const.h" #include #include #include "pair_multi_lucy.h" #include "atom.h" #include "force.h" #include "comm.h" #include "neigh_list.h" #include "memory.h" #include "error.h" #include "citeme.h" using namespace LAMMPS_NS; enum{NONE,RLINEAR,RSQ}; #define MAXLINE 1024 static const char cite_pair_multi_lucy[] = "pair_style multi/lucy command:\n\n" "@Article{Moore16,\n" " author = {J.D. Moore, B.C. Barnes, S. Izvekov, M. Lisal, M.S. Sellers, D.E. Taylor and J. K. Brennan},\n" " title = {A coarse-grain force field for RDX: Density dependent and energy conserving},\n" " journal = {J. Chem. Phys.},\n" " year = 2016,\n" " volume = 144\n" " pages = {104501}\n" "}\n\n"; /* ---------------------------------------------------------------------- */ PairMultiLucy::PairMultiLucy(LAMMPS *lmp) : Pair(lmp) { if (lmp->citeme) lmp->citeme->add(cite_pair_multi_lucy); if (atom->rho_flag != 1) error->all(FLERR,"Pair multi/lucy command requires atom_style with density (e.g. dpd, meso)"); ntables = 0; tables = NULL; comm_forward = 1; comm_reverse = 1; } /* ---------------------------------------------------------------------- */ PairMultiLucy::~PairMultiLucy() { 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 PairMultiLucy::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype,itable; double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair,rsq; int *ilist,*jlist,*numneigh,**firstneigh; Table *tb; 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; int newton_pair = force->newton_pair; double pi = MathConst::MY_PI; double A_i; double A_j; double fraction_i,fraction_j; int jtable; double *rho = atom->rho; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; computeLocalDensity(); // 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]; if (rsq < cutsq[itype][jtype]) { tb = &tables[tabindex[itype][jtype]]; if (rho[i]*rho[i] < tb->innersq || rho[j]*rho[j] < tb->innersq) error->one(FLERR,"Density < table inner cutoff"); if (tabstyle == LOOKUP) { itable = static_cast (((rho[i]*rho[i]) - tb->innersq) * tb->invdelta); jtable = static_cast (((rho[j]*rho[j]) - tb->innersq) * tb->invdelta); if (itable >= tlm1 || jtable >= tlm1) error->one(FLERR,"Density > table outer cutoff"); A_i = tb->f[itable]; A_j = tb->f[jtable]; fpair = 0.5*(A_i + A_j)*(1.0+3.0*sqrt(rsq)/sqrt(cutsq[itype][jtype]))*(1.0 - sqrt(rsq)/sqrt(cutsq[itype][jtype]))*(1.0 - sqrt(rsq)/sqrt(cutsq[itype][jtype]))*(1.0 - sqrt(rsq)/sqrt(cutsq[itype][jtype])); fpair = fpair/sqrt(rsq); } else if (tabstyle == LINEAR) { itable = static_cast ((rho[i]*rho[i] - tb->innersq) * tb->invdelta); jtable = static_cast (((rho[j]*rho[j]) - tb->innersq) * tb->invdelta); if (itable >= tlm1 || jtable >= tlm1) error->one(FLERR,"Density > table outer cutoff"); fraction_i = (((rho[i]*rho[i]) - tb->rsq[itable]) * tb->invdelta); fraction_j = (((rho[j]*rho[j]) - tb->rsq[jtable]) * tb->invdelta); A_i = tb->f[itable] + fraction_i*tb->df[itable]; A_j = tb->f[jtable] + fraction_j*tb->df[jtable]; fpair = 0.5*(A_i + A_j)*(1.0+3.0*sqrt(rsq)/sqrt(cutsq[itype][jtype]))*(1.0 - sqrt(rsq)/sqrt(cutsq[itype][jtype]))*(1.0 - sqrt(rsq)/sqrt(cutsq[itype][jtype]))*(1.0 - sqrt(rsq)/sqrt(cutsq[itype][jtype])); fpair = fpair / sqrt(rsq); } else error->one(FLERR,"Only LOOKUP and LINEAR table styles have been implemented for pair multi/lucy"); 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 (evflag) ev_tally(i,j,nlocal,newton_pair, 0.0,0.0,fpair,delx,dely,delz); } } tb = &tables[tabindex[itype][itype]]; if (rho[i]*rho[i] < tb->innersq || rho[j]*rho[j] < tb->innersq) error->one(FLERR,"Density < table inner cutoff"); itable = static_cast (((rho[i]*rho[i]) - tb->innersq) * tb->invdelta); if (tabstyle == LOOKUP) evdwl = tb->e[itable]; else if (tabstyle == LINEAR){ if (itable >= tlm1) error->one(FLERR,"Density > table outer cutoff"); if(itable==0) fraction_i=0.0; else fraction_i = (((rho[i]*rho[i]) - tb->rsq[itable]) * tb->invdelta); evdwl = tb->e[itable] + fraction_i*tb->de[itable]; } else error->one(FLERR,"Only LOOKUP and LINEAR table styles have been implemented for pair multi/lucy"); evdwl *=(pi*cutsq[itype][itype]*cutsq[itype][itype])/84.0; if (evflag) ev_tally(0,0,nlocal,newton_pair, evdwl,0.0,0.0,0.0,0.0,0.0); } if (vflag_fdotr) virial_fdotr_compute(); } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairMultiLucy::allocate() { allocated = 1; const int nt = atom->ntypes + 1; memory->create(setflag,nt,nt,"pair:setflag"); memory->create(cutsq,nt,nt,"pair:cutsq"); memory->create(tabindex,nt,nt,"pair:tabindex"); memset(&setflag[0][0],0,nt*nt*sizeof(int)); memset(&cutsq[0][0],0,nt*nt*sizeof(double)); memset(&tabindex[0][0],0,nt*nt*sizeof(int)); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairMultiLucy::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 error->all(FLERR,"Unknown table style in pair_style command"); tablength = force->inumeric(FLERR,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 PairMultiLucy::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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,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(FLERR,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 if (tb->ninput <= 1) error->one(FLERR,"Invalid pair table length"); double rlo; if (tb->rflag == 0) { rlo = tb->rfile[0]; } else { rlo = tb->rlo; } rho_0 = rlo; tb->match = 0; if (tabstyle == LINEAR && tb->ninput == tablength && tb->rflag == RSQ) tb->match = 1; // 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 PairMultiLucy::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 ------------------------------------------------------------------------- */ void PairMultiLucy::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 char *word = strtok(line," \t\n\r"); if (strcmp(word,keyword) == 0) 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"); // 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; 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 == RLINEAR) 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); } 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 PairMultiLucy::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 PairMultiLucy::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 lo hi FP fplo fphi N is required, other params are optional ------------------------------------------------------------------------- */ void PairMultiLucy::param_extract(Table *tb, char *line) { tb->ninput = 0; tb->rflag = NONE; 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) { if (strcmp(word,"R") == 0) tb->rflag = RLINEAR; else if (strcmp(word,"RSQ") == 0) tb->rflag = RSQ; 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 PairMultiLucy::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->rhi*tb->rhi - 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); } } // 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]; } 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); } } 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]; } } } /* ---------------------------------------------------------------------- set all ptrs in a table to NULL, so can be freed safely ------------------------------------------------------------------------- */ void PairMultiLucy::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 PairMultiLucy::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 PairMultiLucy::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 PairMultiLucy::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 PairMultiLucy::write_restart(FILE *fp) { write_restart_settings(fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairMultiLucy::read_restart(FILE *fp) { read_restart_settings(fp); allocate(); } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairMultiLucy::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 PairMultiLucy::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_INT,0,world); MPI_Bcast(&tablength,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- */ void PairMultiLucy::computeLocalDensity() { int i,j,m,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz; double rsq; int *ilist,*jlist,*numneigh,**firstneigh; double **x = atom->x; int *type = atom->type; int nlocal = atom->nlocal; int newton_pair = force->newton_pair; double factor; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; double pi = MathConst::MY_PI; double *rho = atom->rho; // zero out density if (newton_pair) { m = nlocal + atom->nghost; for (i = 0; i < m; i++) rho[i] = 0.0; } else for (i = 0; i < nlocal; i++) rho[i] = 0.0; // rho = density at each atom // 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; jtype = type[j]; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; if (rsq < cutsq[itype][jtype]) { double rcut = sqrt(cutsq[itype][jtype]); factor= (84.0/(5.0*pi*rcut*rcut*rcut))*(1.0+3.0*sqrt(rsq)/(2.0*rcut))*(1.0-sqrt(rsq)/rcut)*(1.0-sqrt(rsq)/rcut)*(1.0-sqrt(rsq)/rcut)*(1.0-sqrt(rsq)/rcut); rho[i] += factor; if (newton_pair || j < nlocal) { rho[j] += factor; } } } } if (newton_pair) comm->reverse_comm_pair(this); comm->forward_comm_pair(this); } /* ---------------------------------------------------------------------- */ int PairMultiLucy::pack_forward_comm(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; double *rho = atom->rho; m = 0; for (i = 0; i < n; i++) { j = list[i]; buf[m++] = rho[j]; } return m; } /* ---------------------------------------------------------------------- */ void PairMultiLucy::unpack_forward_comm(int n, int first, double *buf) { int i,m,last; double *rho = atom->rho; m = 0; last = first + n; for (i = first; i < last; i++) rho[i] = buf[m++]; } /* ---------------------------------------------------------------------- */ int PairMultiLucy::pack_reverse_comm(int n, int first, double *buf) { int i,m,last; double *rho = atom->rho; m = 0; last = first + n; for (i = first; i < last; i++) buf[m++] = rho[i]; return m; } /* ---------------------------------------------------------------------- */ void PairMultiLucy::unpack_reverse_comm(int n, int *list, double *buf) { int i,j,m; double *rho = atom->rho; m = 0; for (i = 0; i < n; i++) { j = list[i]; rho[j] += buf[m++]; } } diff --git a/src/USER-DPD/pair_multi_lucy_rx.cpp b/src/USER-DPD/pair_multi_lucy_rx.cpp index cf10a7075..586e58908 100644 --- a/src/USER-DPD/pair_multi_lucy_rx.cpp +++ b/src/USER-DPD/pair_multi_lucy_rx.cpp @@ -1,1023 +1,1023 @@ /* ---------------------------------------------------------------------- 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: James Larentzos and Joshua Moore (U.S. Army Research Laboratory) Please cite the related publications: J.D. Moore, B.C. Barnes, S. Izvekov, M. Lisal, M.S. Sellers, D.E. Taylor & J.K. Brennan "A coarse-grain force field for RDX: Density dependent and energy conserving" The Journal of Chemical Physics, 2016, 144, 104501. ------------------------------------------------------------------------------------------- */ #include #include #include "math_const.h" #include #include #include "pair_multi_lucy_rx.h" #include "atom.h" #include "force.h" #include "comm.h" #include "neigh_list.h" #include "memory.h" #include "error.h" #include "citeme.h" #include "modify.h" #include "fix.h" using namespace LAMMPS_NS; enum{NONE,RLINEAR,RSQ}; #define MAXLINE 1024 #define oneFluidParameter (-1) #define isOneFluid(_site) ( (_site) == oneFluidParameter ) static const char cite_pair_multi_lucy_rx[] = "pair_style multi/lucy/rx command:\n\n" "@Article{Moore16,\n" " author = {J.D. Moore, B.C. Barnes, S. Izvekov, M. Lisal, M.S. Sellers, D.E. Taylor and J. K. Brennan},\n" " title = {A coarse-grain force field for RDX: Density dependent and energy conserving},\n" " journal = {J. Chem. Phys.},\n" " year = 2016,\n" " volume = 144\n" " pages = {104501}\n" "}\n\n"; /* ---------------------------------------------------------------------- */ PairMultiLucyRX::PairMultiLucyRX(LAMMPS *lmp) : Pair(lmp) { if (lmp->citeme) lmp->citeme->add(cite_pair_multi_lucy_rx); if (atom->rho_flag != 1) error->all(FLERR,"Pair multi/lucy/rx command requires atom_style with density (e.g. dpd, meso)"); ntables = 0; tables = NULL; comm_forward = 1; comm_reverse = 1; } /* ---------------------------------------------------------------------- */ PairMultiLucyRX::~PairMultiLucyRX() { 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 PairMultiLucyRX::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype,itable; double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,evdwlOld,fpair; double rsq; int *ilist,*jlist,*numneigh,**firstneigh; Table *tb; int tlm1 = tablength - 1; evdwlOld = 0.0; 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; int nghost = atom->nghost; int newton_pair = force->newton_pair; double fractionOld1_i,fractionOld1_j; double fractionOld2_i,fractionOld2_j; double fraction1_i; double *uCG = atom->uCG; double *uCGnew = atom->uCGnew; double pi = MathConst::MY_PI; double A_i, A_j; double fraction_i,fraction_j; int jtable; double *rho = atom->rho; double *fractionOld1 = NULL; double *fractionOld2 = NULL; double *fraction1 = NULL; double *fraction2 = NULL; { const int ntotal = nlocal + nghost; memory->create(fractionOld1, ntotal, "PairMultiLucyRX::fractionOld1"); memory->create(fractionOld2, ntotal, "PairMultiLucyRX::fractionOld2"); memory->create(fraction1, ntotal, "PairMultiLucyRX::fraction1"); memory->create(fraction2, ntotal, "PairMultiLucyRX::fraction2"); for (int i = 0; i < ntotal; ++i) getParams(i, fractionOld1[i], fractionOld2[i], fraction1[i], fraction2[i]); } inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; computeLocalDensity(); // 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]; double fx_i = 0.0; double fy_i = 0.0; double fz_i = 0.0; fractionOld1_i = fractionOld1[i]; fractionOld2_i = fractionOld2[i]; fraction1_i = fraction1[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]; if (rsq < cutsq[itype][jtype]) { fpair = 0.0; fractionOld1_j = fractionOld1[j]; fractionOld2_j = fractionOld2[j]; tb = &tables[tabindex[itype][jtype]]; if (rho[i]*rho[i] < tb->innersq || rho[j]*rho[j] < tb->innersq){ printf("Table inner cutoff = %lf\n",sqrt(tb->innersq)); printf("rho[%d]=%lf\n",i,rho[i]); printf("rho[%d]=%lf\n",j,rho[j]); error->one(FLERR,"Density < table inner cutoff"); } if (tabstyle == LOOKUP) { itable = static_cast (((rho[i]*rho[i]) - tb->innersq) * tb->invdelta); jtable = static_cast (((rho[j]*rho[j]) - tb->innersq) * tb->invdelta); if (itable >= tlm1 || jtable >= tlm1){ printf("Table outer index = %d\n",tlm1); printf("itableIndex=%d rho[%d]=%lf\n",itable,i,rho[i]); printf("jtableIndex=%d rho[%d]=%lf\n",jtable,j,rho[j]); error->one(FLERR,"Density > table outer cutoff"); } A_i = tb->f[itable]; A_j = tb->f[jtable]; const double rfactor = 1.0-sqrt(rsq/cutsq[itype][jtype]); fpair = 0.5*(A_i + A_j)*(4.0-3.0*rfactor)*rfactor*rfactor*rfactor; fpair /= sqrt(rsq); } else if (tabstyle == LINEAR) { itable = static_cast ((rho[i]*rho[i] - tb->innersq) * tb->invdelta); jtable = static_cast (((rho[j]*rho[j]) - tb->innersq) * tb->invdelta); if (itable >= tlm1 || jtable >= tlm1){ printf("Table outer index = %d\n",tlm1); printf("itableIndex=%d rho[%d]=%lf\n",itable,i,rho[i]); printf("jtableIndex=%d rho[%d]=%lf\n",jtable,j,rho[j]); error->one(FLERR,"Density > table outer cutoff"); } if(itable<0) itable=0; if(itable>=tlm1) itable=tlm1; if(jtable<0) jtable=0; if(jtable>=tlm1)jtable=tlm1; fraction_i = (((rho[i]*rho[i]) - tb->rsq[itable]) * tb->invdelta); fraction_j = (((rho[j]*rho[j]) - tb->rsq[jtable]) * tb->invdelta); if(itable==0) fraction_i=0.0; if(itable==tlm1) fraction_i=0.0; if(jtable==0) fraction_j=0.0; if(jtable==tlm1) fraction_j=0.0; A_i = tb->f[itable] + fraction_i*tb->df[itable]; A_j = tb->f[jtable] + fraction_j*tb->df[jtable]; const double rfactor = 1.0-sqrt(rsq/cutsq[itype][jtype]); fpair = 0.5*(A_i + A_j)*(4.0-3.0*rfactor)*rfactor*rfactor*rfactor; fpair /= sqrt(rsq); } else error->one(FLERR,"Only LOOKUP and LINEAR table styles have been implemented for pair multi/lucy/rx"); if (isite1 == isite2) fpair = sqrt(fractionOld1_i*fractionOld2_j)*fpair; else fpair = (sqrt(fractionOld1_i*fractionOld2_j) + sqrt(fractionOld2_i*fractionOld1_j))*fpair; fx_i += delx*fpair; fy_i += dely*fpair; fz_i += delz*fpair; if (newton_pair || j < nlocal) { f[j][0] -= delx*fpair; f[j][1] -= dely*fpair; f[j][2] -= delz*fpair; } if (evflag) ev_tally(i,j,nlocal,newton_pair,0.0,0.0,fpair,delx,dely,delz); } } f[i][0] += fx_i; f[i][1] += fy_i; f[i][2] += fz_i; tb = &tables[tabindex[itype][itype]]; itable = static_cast (((rho[i]*rho[i]) - tb->innersq) * tb->invdelta); if (tabstyle == LOOKUP) evdwl = tb->e[itable]; else if (tabstyle == LINEAR){ if (itable >= tlm1){ printf("itableIndex=%d rho[%d]=%lf\n",itable,i,rho[i]); error->one(FLERR,"Density > table outer cutoff"); } if(itable==0) fraction_i=0.0; else fraction_i = (((rho[i]*rho[i]) - tb->rsq[itable]) * tb->invdelta); evdwl = tb->e[itable] + fraction_i*tb->de[itable]; } else error->one(FLERR,"Only LOOKUP and LINEAR table styles have been implemented for pair multi/lucy/rx"); evdwl *=(pi*cutsq[itype][itype]*cutsq[itype][itype])/84.0; evdwlOld = fractionOld1_i*evdwl; evdwl = fraction1_i*evdwl; uCG[i] += evdwlOld; uCGnew[i] += evdwl; evdwl = evdwlOld; if (evflag) ev_tally(0,0,nlocal,newton_pair,evdwl,0.0,0.0,0.0,0.0,0.0); } if (vflag_fdotr) virial_fdotr_compute(); memory->destroy(fractionOld1); memory->destroy(fractionOld2); memory->destroy(fraction1); memory->destroy(fraction2); } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairMultiLucyRX::allocate() { allocated = 1; const int nt = atom->ntypes + 1; memory->create(setflag,nt,nt,"pair:setflag"); memory->create(cutsq,nt,nt,"pair:cutsq"); memory->create(tabindex,nt,nt,"pair:tabindex"); memset(&setflag[0][0],0,nt*nt*sizeof(int)); memset(&cutsq[0][0],0,nt*nt*sizeof(double)); memset(&tabindex[0][0],0,nt*nt*sizeof(int)); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairMultiLucyRX::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 error->all(FLERR,"Unknown table style in pair_style command"); tablength = force->inumeric(FLERR,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 PairMultiLucyRX::coeff(int narg, char **arg) { if (narg != 6 && narg != 7) error->all(FLERR,"Illegal pair_coeff command"); bool rx_flag = false; for (int i = 0; i < modify->nfix; i++) if (strncmp(modify->fix[i]->style,"rx",2) == 0) rx_flag = true; if (!rx_flag) error->all(FLERR,"PairMultiLucyRX requires a fix rx 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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,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); nspecies = atom->nspecies_dpd; int n; n = strlen(arg[3]) + 1; site1 = new char[n]; strcpy(site1,arg[4]); n = strlen(arg[4]) + 1; site2 = new char[n]; strcpy(site2,arg[5]); // set table cutoff if (narg == 7) tb->cut = force->numeric(FLERR,arg[6]); 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 if (tb->ninput <= 1) error->one(FLERR,"Invalid pair table length"); if (tb->rflag == 0) { rho_0 = tb->rfile[0]; } else { rho_0 = tb->rlo; } tb->match = 0; if (tabstyle == LINEAR && tb->ninput == tablength && tb->rflag == RSQ) tb->match = 1; // 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++; // Match site* to isite values. if (strcmp(site1, "1fluid") == 0) isite1 = oneFluidParameter; else { isite1 = nspecies; for (int ispecies = 0; ispecies < nspecies; ++ispecies) if (strcmp(site1, atom->dname[ispecies]) == 0){ isite1 = ispecies; break; } if (isite1 == nspecies) error->all(FLERR,"Pair_multi_lucy_rx site1 is invalid."); } if (strcmp(site2, "1fluid") == 0) isite2 = oneFluidParameter; else { isite2 = nspecies; for (int ispecies = 0; ispecies < nspecies; ++ispecies) if (strcmp(site2, atom->dname[ispecies]) == 0){ isite2 = ispecies; break; } if (isite2 == nspecies) error->all(FLERR,"Pair_multi_lucy_rx site2 is invalid."); } } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairMultiLucyRX::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 ------------------------------------------------------------------------- */ void PairMultiLucyRX::read_table(Table *tb, char *file, char *keyword) { char line[MAXLINE]; // open file FILE *fp = force->open_potential(file); 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 char *word = strtok(line," \t\n\r"); if (strcmp(word,keyword) == 0) 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"); // 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; 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 == RLINEAR) 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); } 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 PairMultiLucyRX::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 PairMultiLucyRX::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 lo hi FP fplo fphi N is required, other params are optional ------------------------------------------------------------------------- */ void PairMultiLucyRX::param_extract(Table *tb, char *line) { tb->ninput = 0; tb->rflag = NONE; 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) { if (strcmp(word,"R") == 0) tb->rflag = RLINEAR; else if (strcmp(word,"RSQ") == 0) tb->rflag = RSQ; 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 PairMultiLucyRX::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->rhi*tb->rhi - 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); } } // 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]; } 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); } } 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]; } } } /* ---------------------------------------------------------------------- set all ptrs in a table to NULL, so can be freed safely ------------------------------------------------------------------------- */ void PairMultiLucyRX::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 PairMultiLucyRX::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 PairMultiLucyRX::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 PairMultiLucyRX::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 PairMultiLucyRX::write_restart(FILE *fp) { write_restart_settings(fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairMultiLucyRX::read_restart(FILE *fp) { read_restart_settings(fp); allocate(); } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairMultiLucyRX::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 PairMultiLucyRX::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_INT,0,world); MPI_Bcast(&tablength,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- */ void PairMultiLucyRX::computeLocalDensity() { double **x = atom->x; const int *type = atom->type; const int nlocal = atom->nlocal; const int inum = list->inum; const int *ilist = list->ilist; const int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; const double pi = MathConst::MY_PI; const bool newton_pair = force->newton_pair; const bool one_type = (atom->ntypes == 1); // Special cut-off values for when there's only one type. const double cutsq_type11 = cutsq[1][1]; const double rcut_type11 = sqrt(cutsq_type11); const double factor_type11 = 84.0/(5.0*pi*rcut_type11*rcut_type11*rcut_type11); double *rho = atom->rho; // zero out density if (newton_pair) { const int m = nlocal + atom->nghost; for (int i = 0; i < m; i++) rho[i] = 0.0; } else for (int i = 0; i < nlocal; i++) rho[i] = 0.0; // rho = density at each atom // loop over neighbors of my atoms for (int ii = 0; ii < inum; ii++){ const int i = ilist[ii]; const double xtmp = x[i][0]; const double ytmp = x[i][1]; const double ztmp = x[i][2]; double rho_i = rho[i]; const int itype = type[i]; const int *jlist = firstneigh[i]; const int jnum = numneigh[i]; for (int jj = 0; jj < jnum; jj++){ const int j = (jlist[jj] & NEIGHMASK); const int jtype = type[j]; const double delx = xtmp - x[j][0]; const double dely = ytmp - x[j][1]; const double delz = ztmp - x[j][2]; const double rsq = delx*delx + dely*dely + delz*delz; if (one_type) { if (rsq < cutsq_type11) { const double rcut = rcut_type11; const double r_over_rcut = sqrt(rsq) / rcut; const double tmpFactor = 1.0 - r_over_rcut; const double tmpFactor4 = tmpFactor*tmpFactor*tmpFactor*tmpFactor; const double factor = factor_type11*(1.0 + 1.5*r_over_rcut)*tmpFactor4; rho_i += factor; if (newton_pair || j < nlocal) rho[j] += factor; } else if (rsq < cutsq[itype][jtype]) { const double rcut = sqrt(cutsq[itype][jtype]); const double tmpFactor = 1.0-sqrt(rsq)/rcut; const double tmpFactor4 = tmpFactor*tmpFactor*tmpFactor*tmpFactor; const double factor = (84.0/(5.0*pi*rcut*rcut*rcut))*(1.0+3.0*sqrt(rsq)/(2.0*rcut))*tmpFactor4; rho_i += factor; if (newton_pair || j < nlocal) rho[j] += factor; } } } rho[i] = rho_i; } if (newton_pair) comm->reverse_comm_pair(this); comm->forward_comm_pair(this); } /* ---------------------------------------------------------------------- */ void PairMultiLucyRX::getParams(int id, double &fractionOld1, double &fractionOld2, double &fraction1, double &fraction2) { double fractionOld, fraction; double nTotal, nTotalOld; nTotal = 0.0; nTotalOld = 0.0; for (int ispecies = 0; ispecies < nspecies; ispecies++){ nTotal += atom->dvector[ispecies][id]; nTotalOld += atom->dvector[ispecies+nspecies][id]; } if (isOneFluid(isite1) == false){ fractionOld1 = atom->dvector[isite1+nspecies][id]/nTotalOld; fraction1 = atom->dvector[isite1][id]/nTotal; } if (isOneFluid(isite2) == false){ fractionOld2 = atom->dvector[isite2+nspecies][id]/nTotalOld; fraction2 = atom->dvector[isite2][id]/nTotal; } if (isOneFluid(isite1) || isOneFluid(isite2)){ fractionOld = 0.0; fraction = 0.0; for (int ispecies = 0; ispecies < nspecies; ispecies++){ if (isite1 == ispecies || isite2 == ispecies) continue; fractionOld += atom->dvector[ispecies+nspecies][id] / nTotalOld; fraction += atom->dvector[ispecies][id] / nTotal; } if (isOneFluid(isite1)){ fractionOld1 = fractionOld; fraction1 = fraction; } if (isOneFluid(isite2)){ fractionOld2 = fractionOld; fraction2 = fraction; } } } /* ---------------------------------------------------------------------- */ int PairMultiLucyRX::pack_forward_comm(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; double *rho = atom->rho; m = 0; for (i = 0; i < n; i++) { j = list[i]; buf[m++] = rho[j]; } return m; } /* ---------------------------------------------------------------------- */ void PairMultiLucyRX::unpack_forward_comm(int n, int first, double *buf) { int i,m,last; double *rho = atom->rho; m = 0; last = first + n; for (i = first; i < last; i++) rho[i] = buf[m++]; } /* ---------------------------------------------------------------------- */ int PairMultiLucyRX::pack_reverse_comm(int n, int first, double *buf) { int i,m,last; double *rho = atom->rho; m = 0; last = first + n; for (i = first; i < last; i++) buf[m++] = rho[i]; return m; } /* ---------------------------------------------------------------------- */ void PairMultiLucyRX::unpack_reverse_comm(int n, int *list, double *buf) { int i,j,m; double *rho = atom->rho; m = 0; for (i = 0; i < n; i++) { j = list[i]; rho[j] += buf[m++]; } } diff --git a/src/USER-DPD/pair_table_rx.cpp b/src/USER-DPD/pair_table_rx.cpp index 74b9222a0..902d0e5bb 100644 --- a/src/USER-DPD/pair_table_rx.cpp +++ b/src/USER-DPD/pair_table_rx.cpp @@ -1,1186 +1,1186 @@ /* ---------------------------------------------------------------------- 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 #include #include #include #include "pair_table_rx.h" #include "atom.h" #include "force.h" #include "comm.h" #include "neigh_list.h" #include "memory.h" #include "error.h" #include "modify.h" #include "fix.h" using namespace LAMMPS_NS; enum{NONE,RLINEAR,RSQ,BMP}; #define MAXLINE 1024 #define OneFluidValue (-1) #define isOneFluid(_site_) ( (_site_) == OneFluidValue ) /* ---------------------------------------------------------------------- */ PairTableRX::PairTableRX(LAMMPS *lmp) : Pair(lmp) { ntables = 0; tables = NULL; } /* ---------------------------------------------------------------------- */ PairTableRX::~PairTableRX() { 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 PairTableRX::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype,itable; double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,evdwlOld,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; fraction = 0.0; a = 0.0; b = 0.0; evdwlOld = 0.0; evdwl = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; double *fractionOld1, *fractionOld2; double *fraction1, *fraction2; { const int ntotal = atom->nlocal + atom->nghost; memory->create(fractionOld1, ntotal, "PairTableRx::compute::fractionOld1"); memory->create(fractionOld2, ntotal, "PairTableRx::compute::fractionOld2"); memory->create(fraction1, ntotal, "PairTableRx::compute::fraction1"); memory->create(fraction2, ntotal, "PairTableRx::compute::fraction2"); for (int i = 0; i < ntotal; ++i) getParams(i, fractionOld1[i], fractionOld2[i], fraction1[i], fraction2[i]); } 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; double fractionOld1_i, fractionOld1_j; double fractionOld2_i, fractionOld2_j; double fraction1_i, fraction1_j; double fraction2_i, fraction2_j; double *uCG = atom->uCG; double *uCGnew = atom->uCGnew; 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]; double uCG_i = 0.0; double uCGnew_i = 0.0; double fx_i = 0.0, fy_i = 0.0, fz_i = 0.0; fractionOld1_i = fractionOld1[i]; fractionOld2_i = fractionOld2[i]; fraction1_i = fraction1[i]; fraction2_i = fraction2[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]) { fractionOld1_j = fractionOld1[j]; fractionOld2_j = fractionOld2[j]; fraction1_j = fraction1[j]; fraction2_j = fraction2[j]; 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; } if (isite1 == isite2) fpair = sqrt(fractionOld1_i*fractionOld2_j)*fpair; else fpair = (sqrt(fractionOld1_i*fractionOld2_j) + sqrt(fractionOld2_i*fractionOld1_j))*fpair; fx_i += delx*fpair; fy_i += dely*fpair; fz_i += delz*fpair; if (newton_pair || j < nlocal) { f[j][0] -= delx*fpair; f[j][1] -= dely*fpair; f[j][2] -= delz*fpair; } 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; if (isite1 == isite2){ evdwlOld = sqrt(fractionOld1_i*fractionOld2_j)*evdwl; evdwl = sqrt(fraction1_i*fraction2_j)*evdwl; } else { evdwlOld = (sqrt(fractionOld1_i*fractionOld2_j) + sqrt(fractionOld2_i*fractionOld1_j))*evdwl; evdwl = (sqrt(fraction1_i*fraction2_j) + sqrt(fraction2_i*fraction1_j))*evdwl; } evdwlOld *= factor_lj; evdwl *= factor_lj; uCG_i += 0.5*evdwlOld; uCG[j] += 0.5*evdwlOld; uCGnew_i += 0.5*evdwl; uCGnew[j] += 0.5*evdwl; evdwl = evdwlOld; if (evflag) ev_tally(i,j,nlocal,newton_pair, evdwl,0.0,fpair,delx,dely,delz); } } uCG[i] += uCG_i; uCGnew[i] += uCGnew_i; f[i][0] += fx_i; f[i][1] += fy_i; f[i][2] += fz_i; } if (vflag_fdotr) virial_fdotr_compute(); memory->destroy(fractionOld1); memory->destroy(fractionOld2); memory->destroy(fraction1); memory->destroy(fraction2); } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairTableRX::allocate() { allocated = 1; const int nt = atom->ntypes + 1; memory->create(setflag,nt,nt,"pair:setflag"); memory->create(cutsq,nt,nt,"pair:cutsq"); memory->create(tabindex,nt,nt,"pair:tabindex"); memset(&setflag[0][0],0,nt*nt*sizeof(int)); memset(&cutsq[0][0],0,nt*nt*sizeof(double)); memset(&tabindex[0][0],0,nt*nt*sizeof(int)); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairTableRX::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(FLERR,arg[1]); if (tablength < 2) error->all(FLERR,"Illegal number of pair table entries"); // optional keywords // assert the tabulation is compatible with a specific long-range solver int iarg = 2; while (iarg < narg) { if (strcmp(arg[iarg],"ewald") == 0) ewaldflag = 1; else if (strcmp(arg[iarg],"pppm") == 0) pppmflag = 1; else if (strcmp(arg[iarg],"msm") == 0) msmflag = 1; else if (strcmp(arg[iarg],"dispersion") == 0) dispersionflag = 1; else if (strcmp(arg[iarg],"tip4p") == 0) tip4pflag = 1; else error->all(FLERR,"Illegal pair_style command"); iarg++; } // 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 PairTableRX::coeff(int narg, char **arg) { if (narg != 6 && narg != 7) error->all(FLERR,"Illegal pair_coeff command"); if (!allocated) allocate(); bool rx_flag = false; for (int i = 0; i < modify->nfix; i++) if (strncmp(modify->fix[i]->style,"rx",2) == 0) rx_flag = true; if (!rx_flag) error->all(FLERR,"PairTableRX requires a fix rx command."); int ilo,ihi,jlo,jhi; - force->bounds(arg[0],atom->ntypes,ilo,ihi); - force->bounds(arg[1],atom->ntypes,jlo,jhi); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,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); nspecies = atom->nspecies_dpd; if(nspecies==0) error->all(FLERR,"There are no rx species specified."); int n; n = strlen(arg[3]) + 1; site1 = new char[n]; strcpy(site1,arg[4]); int ispecies; for (ispecies = 0; ispecies < nspecies; ispecies++){ if (strcmp(site1,&atom->dname[ispecies][0]) == 0) break; } if (ispecies == nspecies && strcmp(site1,"1fluid") != 0) error->all(FLERR,"Site1 name not recognized in pair coefficients"); n = strlen(arg[4]) + 1; site2 = new char[n]; strcpy(site2,arg[5]); for (ispecies = 0; ispecies < nspecies; ispecies++){ if (strcmp(site2,&atom->dname[ispecies][0]) == 0) break; } if (ispecies == nspecies && strcmp(site2,"1fluid") != 0) error->all(FLERR,"Site2 name not recognized in pair coefficients"); // set table cutoff if (narg == 7) tb->cut = force->numeric(FLERR,arg[6]); 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++; { if ( strcmp(site1,"1fluid") == 0 ) isite1 = OneFluidValue; else { isite1 = nspecies; for (int k = 0; k < nspecies; k++){ if (strcmp(site1, atom->dname[k]) == 0){ isite1 = k; break; } } if (isite1 == nspecies) error->all(FLERR,"isite1 == nspecies"); } if ( strcmp(site2,"1fluid") == 0 ) isite2 = OneFluidValue; else { isite2 = nspecies; for (int k = 0; k < nspecies; k++){ if (strcmp(site2, atom->dname[k]) == 0){ isite2 = ispecies; break; } } if (isite2 == nspecies) error->all(FLERR,"isite2 == nspecies"); } } } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairTableRX::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 PairTableRX::read_table(Table *tb, char *file, char *keyword) { char line[MAXLINE]; // open file FILE *fp = force->open_potential(file); 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 char *word = strtok(line," \t\n\r"); if (strcmp(word,keyword) == 0) 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 == RLINEAR) 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 PairTableRX::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 PairTableRX::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 PairTableRX::param_extract(Table *tb, char *line) { tb->ninput = 0; tb->rflag = NONE; 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 = RLINEAR; 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 PairTableRX::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 = double(inner)*double(inner); tb->delta = double(tb->cut*tb->cut - double(tb->innersq)) / double(tlm1); tb->invdelta = 1.0/double(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 = dh/dg at inner and at cut // h(r) = e(r) and g(r) = r^2 // dh/dg = (de/dr) / 2r = -f/2r double ep0 = - tb->f[0] / (2.0 * sqrt(tb->innersq)); double epn = - tb->f[tlm1] / (2.0 * tb->cut); 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 PairTableRX::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 PairTableRX::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 PairTableRX::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 PairTableRX::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 PairTableRX::write_restart(FILE *fp) { write_restart_settings(fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairTableRX::read_restart(FILE *fp) { read_restart_settings(fp); allocate(); } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairTableRX::write_restart_settings(FILE *fp) { fwrite(&tabstyle,sizeof(int),1,fp); fwrite(&tablength,sizeof(int),1,fp); fwrite(&ewaldflag,sizeof(int),1,fp); fwrite(&pppmflag,sizeof(int),1,fp); fwrite(&msmflag,sizeof(int),1,fp); fwrite(&dispersionflag,sizeof(int),1,fp); fwrite(&tip4pflag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairTableRX::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&tabstyle,sizeof(int),1,fp); fread(&tablength,sizeof(int),1,fp); fread(&ewaldflag,sizeof(int),1,fp); fread(&pppmflag,sizeof(int),1,fp); fread(&msmflag,sizeof(int),1,fp); fread(&dispersionflag,sizeof(int),1,fp); fread(&tip4pflag,sizeof(int),1,fp); } MPI_Bcast(&tabstyle,1,MPI_INT,0,world); MPI_Bcast(&tablength,1,MPI_INT,0,world); MPI_Bcast(&ewaldflag,1,MPI_INT,0,world); MPI_Bcast(&pppmflag,1,MPI_INT,0,world); MPI_Bcast(&msmflag,1,MPI_INT,0,world); MPI_Bcast(&dispersionflag,1,MPI_INT,0,world); MPI_Bcast(&tip4pflag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- */ double PairTableRX::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]]; double fraction1_i, fraction1_j; double fraction2_i, fraction2_j; double fractionOld1_i, fractionOld1_j; double fractionOld2_i, fractionOld2_j; fraction = 0.0; a = 0.0; b = 0.0; getParams(i,fractionOld1_i,fractionOld2_i,fraction1_i,fraction2_i); getParams(j,fractionOld1_j,fractionOld2_j,fraction1_j,fraction2_j); 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 (isite1 == isite2) fforce = sqrt(fraction1_i*fraction2_j)*fforce; else fforce = (sqrt(fraction1_i*fraction2_j) + sqrt(fraction2_i*fraction1_j))*fforce; 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; if (isite1 == isite2) phi = sqrt(fraction1_i*fraction2_j)*phi; else phi = (sqrt(fraction1_i*fraction2_j) + sqrt(fraction2_i*fraction1_j))*phi; 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 *PairTableRX::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"); dim = 0; return &tables[0].cut; } /* ---------------------------------------------------------------------- */ void PairTableRX::getParams(int id, double &fractionOld1, double &fractionOld2, double &fraction1, double &fraction2) { double nTotal = 0.0; double nTotalOld = 0.0; for (int ispecies = 0; ispecies < nspecies; ++ispecies){ nTotal += atom->dvector[ispecies][id]; nTotalOld += atom->dvector[ispecies+nspecies][id]; } if(nTotal < 1e-8 || nTotalOld < 1e-8) error->all(FLERR,"The number of molecules in CG particle is less than 1e-8."); if (isOneFluid(isite1) == false){ fractionOld1 = atom->dvector[isite1+nspecies][id]/nTotalOld; fraction1 = atom->dvector[isite1][id]/nTotal; } if (isOneFluid(isite2) == false){ fractionOld2 = atom->dvector[isite2+nspecies][id]/nTotalOld; fraction2 = atom->dvector[isite2][id]/nTotal; } if (isOneFluid(isite1) || isOneFluid(isite2)){ double fractionOld = 0.0; double fraction = 0.0; for (int ispecies = 0; ispecies < nspecies; ispecies++){ if (isite1 == ispecies || isite2 == ispecies) continue; fractionOld += atom->dvector[ispecies+nspecies][id]/nTotalOld; fraction += atom->dvector[ispecies][id]/nTotal; } if(isOneFluid(isite1)){ fractionOld1 = fractionOld; fraction1 = fraction; } if(isOneFluid(isite2)){ fractionOld2 = fractionOld; fraction2 = fraction; } } } diff --git a/src/USER-DRUDE/pair_lj_cut_thole_long.cpp b/src/USER-DRUDE/pair_lj_cut_thole_long.cpp index efa11c6c5..726baae24 100644 --- a/src/USER-DRUDE/pair_lj_cut_thole_long.cpp +++ b/src/USER-DRUDE/pair_lj_cut_thole_long.cpp @@ -1,703 +1,703 @@ /* ---------------------------------------------------------------------- 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 #include #include #include #include "pair_lj_cut_thole_long.h" #include "atom.h" #include "comm.h" #include "force.h" #include "kspace.h" #include "update.h" #include "integrate.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 9.95473818e-1 #define B0 -0.1335096380159268 #define B1 -2.57839507e-1 #define B2 -1.37203639e-1 #define B3 -8.88822059e-3 #define B4 -5.80844129e-3 #define B5 1.14652755e-1 /* ---------------------------------------------------------------------- */ PairLJCutTholeLong::PairLJCutTholeLong(LAMMPS *lmp) : Pair(lmp) { ewaldflag = pppmflag = 1; writedata = 1; ftable = NULL; qdist = 0.0; fix_drude = NULL; } /* ---------------------------------------------------------------------- */ PairLJCutTholeLong::~PairLJCutTholeLong() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(polar); memory->destroy(thole); memory->destroy(ascreen); memory->destroy(cut_lj); memory->destroy(cut_ljsq); memory->destroy(scale); 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 PairLJCutTholeLong::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype,itable; double qi,qj,xtmp,ytmp,ztmp,delx,dely,delz,ecoul,fpair,evdwl; double r,rsq,r2inv,forcecoul,factor_coul,forcelj,factor_lj,r6inv; double fraction,table; double grij,expm2,prefactor,t,erfc,u; int *ilist,*jlist,*numneigh,**firstneigh; double factor_f,factor_e; int di,dj; double dqi,dqj,dcoul,asr,exp_asr; int di_closest; 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; int *drudetype = fix_drude->drudetype; tagint *drudeid = fix_drude->drudeid; 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]; qi = q[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; jlist = firstneigh[i]; jnum = numneigh[i]; if (drudetype[type[i]] != NOPOL_TYPE){ di = atom->map(drudeid[i]); if (di < 0) error->all(FLERR, "Drude partner not found"); di_closest = domain->closest_image(i, di); if (drudetype[type[i]] == CORE_TYPE) dqi = -q[di]; else dqi = qi; } 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) { qj = q[j]; r = sqrt(rsq); if (!ncoultablebits || rsq <= tabinnersq) { grij = g_ewald * r; expm2 = exp(-grij*grij); t = 1.0 / (1.0 + EWALD_P*grij); u = 1. - t; erfc = t * (1.+u*(B0+u*(B1+u*(B2+u*(B3+u*(B4+u*B5)))))) * expm2; prefactor = qqrd2e * qi*qj/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 = qi*qj * table; if (factor_coul < 1.0) { table = ctable[itable] + fraction*dctable[itable]; prefactor = qi*qj * table; forcecoul -= (1.0-factor_coul)*prefactor; } } if (drudetype[type[i]] != NOPOL_TYPE && drudetype[type[j]] != NOPOL_TYPE){ if (j != di_closest){ if (drudetype[type[j]] == CORE_TYPE){ dj = atom->map(drudeid[j]); dqj = -q[dj]; } else dqj = qj; asr = ascreen[type[i]][type[j]] * r; exp_asr = exp(-asr); dcoul = qqrd2e * dqi * dqj / r; factor_f = 0.5*(2. + (exp_asr * (-2. - asr * (2. + asr)))) - factor_coul; if (eflag) factor_e = 0.5*(2. - (exp_asr * (2. + asr))) - factor_coul; forcecoul += factor_f * dcoul; } } } 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 = qi*qj * table; } if (factor_coul < 1.0) ecoul -= (1.0-factor_coul)*prefactor; if (drudetype[type[i]] != NOPOL_TYPE && drudetype[type[j]] != NOPOL_TYPE && j != di_closest){ ecoul += factor_e * dcoul; } } 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(); } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairLJCutTholeLong::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(scale,n+1,n+1,"pair:scale"); memory->create(ascreen,n+1,n+1,"pair:ascreen"); memory->create(thole,n+1,n+1,"pair:thole"); memory->create(polar,n+1,n+1,"pair:polar"); 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 PairLJCutTholeLong::settings(int narg, char **arg) { if (narg < 2 || narg > 3) error->all(FLERR,"Illegal pair_style command"); thole_global = force->numeric(FLERR,arg[0]); cut_lj_global = force->numeric(FLERR,arg[1]); if (narg == 2) cut_coul = cut_lj_global; else cut_coul = force->numeric(FLERR,arg[2]); // 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]) { thole[i][j] = thole_global; cut_lj[i][j] = cut_lj_global; } } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairLJCutTholeLong::coeff(int narg, char **arg) { if (narg < 5 || narg > 7) 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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(FLERR,arg[2]); double sigma_one = force->numeric(FLERR,arg[3]); double polar_one = force->numeric(FLERR,arg[4]); double thole_one = thole_global; if (narg >=6) thole_one = force->numeric(FLERR,arg[5]); double cut_lj_one = cut_lj_global; if (narg == 7) cut_lj_one = force->numeric(FLERR,arg[6]); 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; polar[i][j] = polar_one; thole[i][j] = thole_one; ascreen[i][j] = thole[i][j] / pow(polar[i][j], 1./3.); cut_lj[i][j] = cut_lj_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 PairLJCutTholeLong::init_style() { if (!atom->q_flag) error->all(FLERR,"Pair style lj/cut/thole/long requires atom attribute q"); int ifix; for (ifix = 0; ifix < modify->nfix; ifix++) if (strcmp(modify->fix[ifix]->style,"drude") == 0) break; if (ifix == modify->nfix) error->all(FLERR, "Pair style lj/cut/thole/long requires fix drude"); fix_drude = (FixDrude *) modify->fix[ifix]; int irequest = neighbor->request(this,instance_me); cut_coulsq = cut_coul * cut_coul; // set rRESPA cutoffs cut_respa = NULL; // insure use of KSpace long-range solver, set g_ewald if (force->kspace == NULL) error->all(FLERR,"Pair style requires a KSpace style"); g_ewald = force->kspace->g_ewald; // setup force tables if (ncoultablebits) init_tables(cut_coul,cut_respa); } /* ---------------------------------------------------------------------- neighbor callback to inform pair style of neighbor list to use regular or rRESPA ------------------------------------------------------------------------- */ void PairLJCutTholeLong::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 PairLJCutTholeLong::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]); polar[i][j] = sqrt(polar[i][i] * polar[j][j]); thole[i][j] = 0.5 * (thole[i][i] + thole[j][j]); ascreen[i][j] = thole[i][j] / pow(polar[i][j], 1./3.); } // include TIP4P qdist in full cutoff, qdist = 0.0 if not TIP4P double cut = MAX(cut_lj[i][j],cut_coul+2.0*qdist); 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]; polar[j][i] = polar[i][j]; thole[j][i] = thole[i][j]; ascreen[j][i] = ascreen[i][j]; scale[j][i] = scale[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; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJCutTholeLong::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(&polar[i][j],sizeof(double),1,fp); fwrite(&thole[i][j],sizeof(double),1,fp); fwrite(&cut_lj[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJCutTholeLong::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(&polar[i][j],sizeof(double),1,fp); fread(&thole[i][j],sizeof(double),1,fp); ascreen[i][j] = thole[i][j] / pow(polar[i][j], 1./3.); 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(&polar[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&thole[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&ascreen[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 PairLJCutTholeLong::write_restart_settings(FILE *fp) { fwrite(&cut_lj_global,sizeof(double),1,fp); fwrite(&cut_coul,sizeof(double),1,fp); fwrite(&thole_global,sizeof(double),1,fp); fwrite(&cut_global,sizeof(double),1,fp); fwrite(&offset_flag,sizeof(int),1,fp); fwrite(&mix_flag,sizeof(int),1,fp); fwrite(&tail_flag,sizeof(int),1,fp); fwrite(&ncoultablebits,sizeof(int),1,fp); fwrite(&tabinner,sizeof(double),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJCutTholeLong::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(&thole_global,sizeof(double),1,fp); fread(&cut_global,sizeof(double),1,fp); fread(&offset_flag,sizeof(int),1,fp); fread(&mix_flag,sizeof(int),1,fp); fread(&tail_flag,sizeof(int),1,fp); fread(&ncoultablebits,sizeof(int),1,fp); fread(&tabinner,sizeof(double),1,fp); } MPI_Bcast(&cut_lj_global,1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_coul,1,MPI_DOUBLE,0,world); MPI_Bcast(&thole_global,1,MPI_DOUBLE,0,world); 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); MPI_Bcast(&tail_flag,1,MPI_INT,0,world); MPI_Bcast(&ncoultablebits,1,MPI_INT,0,world); MPI_Bcast(&tabinner,1,MPI_DOUBLE,0,world); } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void PairLJCutTholeLong::write_data(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) fprintf(fp,"%d %g %g %g %g\n",i,epsilon[i][i],sigma[i][i],polar[i][i],thole[i][i]); } /* ---------------------------------------------------------------------- proc 0 writes all pairs to data file ------------------------------------------------------------------------- */ void PairLJCutTholeLong::write_data_all(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) fprintf(fp,"%d %d %g %g %g %g %g\n",i,j,epsilon[i][j],sigma[i][j],polar[i][j],thole[i][j],cut_lj[i][j]); } /* ---------------------------------------------------------------------- */ double PairLJCutTholeLong::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,u; double fraction,table,forcecoul,forcelj,phicoul,philj; int itable; double factor_f,factor_e; double dqi,dqj,dcoul,asr,exp_asr; int di, dj, di_closest; int *drudetype = fix_drude->drudetype; tagint *drudeid = fix_drude->drudeid; int *type = atom->type; r2inv = 1.0/rsq; if (rsq < cut_coulsq) { r = sqrt(rsq); if (!ncoultablebits || rsq <= tabinnersq) { grij = g_ewald * r; expm2 = exp(-grij*grij); t = 1.0 / (1.0 + EWALD_P*grij); u = 1. - t; erfc = t * (1.+u*(B0+u*(B1+u*(B2+u*(B3+u*(B4+u*B5)))))) * 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; } } if (drudetype[type[i]] != NOPOL_TYPE && drudetype[type[j]] != NOPOL_TYPE) { di = atom->map(drudeid[i]); di_closest = domain->closest_image(i, di); if (j != di_closest){ if (drudetype[i] == CORE_TYPE) dqi = -atom->q[di]; else if (drudetype[i] == DRUDE_TYPE) dqi = atom->q[i]; if (drudetype[j] == CORE_TYPE) { dj = atom->map(drudeid[j]); dqj = -atom->q[dj]; } else if (drudetype[j] == DRUDE_TYPE) dqj = atom->q[j]; asr = ascreen[itype][jtype] * r; exp_asr = exp(-asr); dcoul = force->qqrd2e * dqi * dqj / r; factor_f = 0.5*(2. + (exp_asr * (-2. - asr * (2. + asr)))) - factor_coul; forcecoul += factor_f * dcoul; factor_e = 0.5*(2. - (exp_asr * (2. + asr))) - factor_coul; } } } 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; if (drudetype[type[i]] != NOPOL_TYPE && drudetype[type[j]] != NOPOL_TYPE && di_closest != j) phicoul += factor_e * dcoul; 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 *PairLJCutTholeLong::extract(const char *str, int &dim) { dim = 0; if (strcmp(str,"cut_coul") == 0) return (void *) &cut_coul; dim = 6; if (strcmp(str,"epsilon") == 0) return (void *) epsilon; if (strcmp(str,"sigma") == 0) return (void *) sigma; if (strcmp(str,"scale") == 0) return (void *) scale; if (strcmp(str,"polar") == 0) return (void *) polar; if (strcmp(str,"thole") == 0) return (void *) thole; if (strcmp(str,"ascreen") == 0) return (void *) ascreen; return NULL; } diff --git a/src/USER-DRUDE/pair_thole.cpp b/src/USER-DRUDE/pair_thole.cpp index 13b1265a7..0ed94ebbc 100644 --- a/src/USER-DRUDE/pair_thole.cpp +++ b/src/USER-DRUDE/pair_thole.cpp @@ -1,421 +1,421 @@ /* ---------------------------------------------------------------------- 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 #include #include #include #include "pair_thole.h" #include "atom.h" #include "comm.h" #include "force.h" #include "neighbor.h" #include "neigh_list.h" #include "memory.h" #include "error.h" #include "fix.h" #include "fix_store.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ PairThole::PairThole(LAMMPS *lmp) : Pair(lmp) { fix_drude = NULL; } /* ---------------------------------------------------------------------- */ PairThole::~PairThole() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(polar); memory->destroy(thole); memory->destroy(ascreen); memory->destroy(cut); memory->destroy(scale); } } /* ---------------------------------------------------------------------- */ void PairThole::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double qi,qj,xtmp,ytmp,ztmp,delx,dely,delz,ecoul,fpair; double r,rsq,r2inv,rinv,factor_coul; int *ilist,*jlist,*numneigh,**firstneigh; double factor_f,factor_e; int di,dj; double dcoul,asr,exp_asr; 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; int *drudetype = fix_drude->drudetype; tagint *drudeid = fix_drude->drudeid; 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]; // only on core-drude pair if (drudetype[type[i]] == NOPOL_TYPE) continue; di = domain->closest_image(i, atom->map(drudeid[i])); // get dq of the core via the drude charge if (drudetype[type[i]] == DRUDE_TYPE) qi = q[i]; else qi = -q[di]; 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; // only on core-drude pair, but not into the same pair if (drudetype[type[j]] == NOPOL_TYPE || j == di) continue; // get dq of the core via the drude charge if (drudetype[type[j]] == DRUDE_TYPE) qj = q[j]; else { dj = domain->closest_image(j, atom->map(drudeid[j])); qj = -q[dj]; } 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); r = sqrt(rsq); asr = ascreen[itype][jtype] * r; exp_asr = exp(-asr); dcoul = qqrd2e * qi * qj *scale[itype][jtype] * rinv; factor_f = 0.5*(2. + (exp_asr * (-2. - asr * (2. + asr)))) - factor_coul; if(eflag) factor_e = 0.5*(2. - (exp_asr * (2. + asr))) - factor_coul; fpair = factor_f * dcoul * 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_e * dcoul; 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 PairThole::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"); memory->create(ascreen,n+1,n+1,"pair:ascreen"); memory->create(thole,n+1,n+1,"pair:thole"); memory->create(polar,n+1,n+1,"pair:polar"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairThole::settings(int narg, char **arg) { if (narg != 2) error->all(FLERR,"Illegal pair_style command"); thole_global = force->numeric(FLERR,arg[0]); cut_global = force->numeric(FLERR,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]) { thole[i][j] = thole_global; cut[i][j] = cut_global; } } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairThole::coeff(int narg, char **arg) { if (narg < 3 || 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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double polar_one = force->numeric(FLERR,arg[2]); double thole_one = thole_global; double cut_one = cut_global; if (narg >=4) thole_one = force->numeric(FLERR,arg[3]); if (narg == 5) cut_one = force->numeric(FLERR,arg[4]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { polar[i][j] = polar_one; thole[i][j] = thole_one; ascreen[i][j] = thole[i][j] / pow(polar[i][j], 1./3.); 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 PairThole::init_style() { if (!atom->q_flag) error->all(FLERR,"Pair style thole requires atom attribute q"); int ifix; for (ifix = 0; ifix < modify->nfix; ifix++) if (strcmp(modify->fix[ifix]->style,"drude") == 0) break; if (ifix == modify->nfix) error->all(FLERR, "Pair thole requires fix drude"); fix_drude = (FixDrude *) modify->fix[ifix]; neighbor->request(this,instance_me); } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairThole::init_one(int i, int j) { if (setflag[i][j] == 0) cut[i][j] = mix_distance(cut[i][i],cut[j][j]); polar[j][i] = polar[i][j]; thole[j][i] = thole[i][j]; ascreen[j][i] = ascreen[i][j]; scale[j][i] = scale[i][j]; return cut[i][j]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairThole::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(&polar[i][j],sizeof(double),1,fp); fwrite(&thole[i][j],sizeof(double),1,fp); fwrite(&cut[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairThole::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(&polar[i][j],sizeof(double),1,fp); fread(&thole[i][j],sizeof(double),1,fp); fread(&cut[i][j],sizeof(double),1,fp); ascreen[i][j] = thole[i][j] / pow(polar[i][j], 1./3.); } MPI_Bcast(&polar[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&thole[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&ascreen[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairThole::write_restart_settings(FILE *fp) { fwrite(&thole_global,sizeof(double),1,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 PairThole::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&thole_global,sizeof(double),1,fp); fread(&cut_global,sizeof(double),1,fp); fread(&offset_flag,sizeof(int),1,fp); fread(&mix_flag,sizeof(int),1,fp); } MPI_Bcast(&thole_global,1,MPI_DOUBLE,0,world); 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 PairThole::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r2inv,rinv,r,phicoul; double qi,qj,factor_f,factor_e,dcoul,asr,exp_asr; int di, dj; int *drudetype = fix_drude->drudetype; tagint *drudeid = fix_drude->drudeid; int *type = atom->type; // only on core-drude pair, but not on the same pair if (drudetype[type[i]] == NOPOL_TYPE || drudetype[type[j]] == NOPOL_TYPE || j == i) return 0.0; // get dq of the core via the drude charge if (drudetype[type[i]] == DRUDE_TYPE) qi = atom->q[i]; else { di = domain->closest_image(i, atom->map(drudeid[i])); qi = -atom->q[di]; } if (drudetype[type[j]] == DRUDE_TYPE) qj = atom->q[j]; else { dj = domain->closest_image(j, atom->map(drudeid[j])); qj = -atom->q[dj]; } r2inv = 1.0/rsq; fforce = phicoul = 0.0; if (rsq < cutsq[itype][jtype]) { rinv = sqrt(r2inv); r = sqrt(rsq); asr = ascreen[itype][jtype] * r; exp_asr = exp(-asr); dcoul = force->qqrd2e * qi * qj * scale[itype][jtype] * rinv; factor_f = 0.5*(2. + (exp_asr * (-2. - asr * (2. + asr)))) - factor_coul; fforce = factor_f * dcoul * r2inv; factor_e = 0.5*(2. - (exp_asr * (2. + asr))) - factor_coul; phicoul = factor_e * dcoul; } return phicoul; } /* ---------------------------------------------------------------------- */ void *PairThole::extract(const char *str, int &dim) { dim = 4; if (strcmp(str,"scale") == 0) return (void *) scale; if (strcmp(str,"polar") == 0) return (void *) polar; if (strcmp(str,"thole") == 0) return (void *) thole; if (strcmp(str,"ascreen") == 0) return (void *) ascreen; return NULL; } diff --git a/src/USER-EFF/pair_eff_cut.cpp b/src/USER-EFF/pair_eff_cut.cpp index b12e1f43b..66f59c86c 100644 --- a/src/USER-EFF/pair_eff_cut.cpp +++ b/src/USER-EFF/pair_eff_cut.cpp @@ -1,1073 +1,1073 @@ /* ---------------------------------------------------------------------- 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: Andres Jaramillo-Botero ------------------------------------------------------------------------- */ #include #include #include #include #include "pair_eff_cut.h" #include "pair_eff_inline.h" #include "atom.h" #include "update.h" #include "min.h" #include "domain.h" #include "comm.h" #include "force.h" #include "neighbor.h" #include "neigh_list.h" #include "memory.h" #include "error.h" #include "atom_vec_electron.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ PairEffCut::PairEffCut(LAMMPS *lmp) : Pair(lmp) { single_enable = 0; nmax = 0; min_eradius = NULL; min_erforce = NULL; nextra = 4; pvector = new double[nextra]; } /* ---------------------------------------------------------------------- */ PairEffCut::~PairEffCut() { delete [] pvector; memory->destroy(min_eradius); memory->destroy(min_erforce); if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut); } } /* ---------------------------------------------------------------------- */ void PairEffCut::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,energy; double eke,ecoul,epauli,errestrain,halfcoul,halfpauli; double fpair,fx,fy,fz; double e1rforce,e2rforce,e1rvirial,e2rvirial; double s_fpair, s_e1rforce, s_e2rforce; double ecp_epauli, ecp_fpair, ecp_e1rforce, ecp_e2rforce; double rsq,rc; int *ilist,*jlist,*numneigh,**firstneigh; energy = eke = epauli = ecp_epauli = ecoul = errestrain = 0.0; // pvector = [KE, Pauli, ecoul, radial_restraint] for (i=0; i<4; i++) pvector[i] = 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; double *erforce = atom->erforce; double *eradius = atom->eradius; int *spin = atom->spin; int *type = atom->type; int nlocal = atom->nlocal; 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]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; jlist = firstneigh[i]; jnum = numneigh[i]; // add electron wavefuntion kinetic energy (not pairwise) if (abs(spin[i])==1 || spin[i]==2) { // reset energy and force temp variables eke = epauli = ecoul = 0.0; fpair = e1rforce = e2rforce = 0.0; s_fpair = 0.0; KinElec(eradius[i],&eke,&e1rforce); // Fixed-core if (spin[i] == 2) { // KE(2s)+Coul(1s-1s)+Coul(2s-nuclei)+Pauli(2s) eke *= 2; ElecNucElec(q[i],0.0,eradius[i],&ecoul,&fpair,&e1rforce); ElecNucElec(q[i],0.0,eradius[i],&ecoul,&fpair,&e1rforce); ElecElecElec(0.0,eradius[i],eradius[i],&ecoul,&fpair,&e1rforce,&e2rforce); // opposite spin electron interactions PauliElecElec(0,0.0,eradius[i],eradius[i], &epauli,&s_fpair,&e1rforce,&e2rforce); // fix core electron size, i.e. don't contribute to ervirial e2rforce = e1rforce = 0.0; } // apply unit conversion factors eke *= hhmss2e; ecoul *= qqrd2e; fpair *= qqrd2e; epauli *= hhmss2e; s_fpair *= hhmss2e; e1rforce *= hhmss2e; // Sum up contributions energy = eke + epauli + ecoul; fpair = fpair + s_fpair; erforce[i] += e1rforce; // Tally energy and compute radial atomic virial contribution if (evflag) { ev_tally_eff(i,i,nlocal,newton_pair,energy,0.0); if (pressure_with_evirials_flag) // iff flexible pressure flag on ev_tally_eff(i,i,nlocal,newton_pair,0.0,e1rforce*eradius[i]); } if (eflag_global) { pvector[0] += eke; pvector[1] += epauli; pvector[2] += ecoul; } } 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; rc = sqrt(rsq); jtype = type[j]; if (rsq < cutsq[itype][jtype]) { energy = ecoul = epauli = ecp_epauli = 0.0; fx = fy = fz = fpair = s_fpair = ecp_fpair = 0.0; double taper = sqrt(cutsq[itype][jtype]); double dist = rc / taper; double spline = cutoff(dist); double dspline = dcutoff(dist) / taper; // nucleus (i) - nucleus (j) Coul interaction if (spin[i] == 0 && spin[j] == 0) { double qxq = q[i]*q[j]; ElecNucNuc(qxq, rc, &ecoul, &fpair); } // fixed-core (i) - nucleus (j) nuclear Coul interaction else if (spin[i] == 2 && spin[j] == 0) { double qxq = q[i]*q[j]; e1rforce = 0.0; ElecNucNuc(qxq, rc, &ecoul, &fpair); ElecNucElec(q[j],rc,eradius[i],&ecoul,&fpair,&e1rforce); ElecNucElec(q[j],rc,eradius[i],&ecoul,&fpair,&e1rforce); } // nucleus (i) - fixed-core (j) nuclear Coul interaction else if (spin[i] == 0 && spin[j] == 2) { double qxq = q[i]*q[j]; e1rforce = 0.0; ElecNucNuc(qxq, rc, &ecoul, &fpair); ElecNucElec(q[i],rc,eradius[j],&ecoul,&fpair,&e1rforce); ElecNucElec(q[i],rc,eradius[j],&ecoul,&fpair,&e1rforce); } // pseudo-core nucleus (i) - nucleus (j) interaction else if (spin[i] == 3 && spin[j] == 0) { double qxq = q[i]*q[j]; ElecCoreNuc(qxq, rc, eradius[i], &ecoul, &fpair); } else if (spin[i] == 4 && spin[j] == 0) { double qxq = q[i]*q[j]; ElecCoreNuc(qxq, rc, eradius[i], &ecoul, &fpair); } // nucleus (i) - pseudo-core nucleus (j) interaction else if (spin[i] == 0 && spin[j] == 3) { double qxq = q[i]*q[j]; ElecCoreNuc(qxq, rc, eradius[j], &ecoul, &fpair); } else if (spin[i] == 0 && spin[j] == 4) { double qxq = q[i]*q[j]; ElecCoreNuc(qxq, rc, eradius[j], &ecoul, &fpair); } // nucleus (i) - electron (j) Coul interaction else if (spin[i] == 0 && abs(spin[j]) == 1) { e1rforce = 0.0; ElecNucElec(q[i],rc,eradius[j],&ecoul,&fpair,&e1rforce); e1rforce = spline * qqrd2e * e1rforce; erforce[j] += e1rforce; // Radial electron virial, iff flexible pressure flag set if (evflag && pressure_with_evirials_flag) { e1rvirial = eradius[j] * e1rforce; ev_tally_eff(j,j,nlocal,newton_pair,0.0,e1rvirial); } } // electron (i) - nucleus (j) Coul interaction else if (abs(spin[i]) == 1 && spin[j] == 0) { e1rforce = 0.0; ElecNucElec(q[j],rc,eradius[i],&ecoul,&fpair,&e1rforce); e1rforce = spline * qqrd2e * e1rforce; erforce[i] += e1rforce; // Radial electron virial, iff flexible pressure flag set if (evflag && pressure_with_evirials_flag) { e1rvirial = eradius[i] * e1rforce; ev_tally_eff(i,i,nlocal,newton_pair,0.0,e1rvirial); } } // electron (i) - electron (j) interactions else if (abs(spin[i]) == 1 && abs(spin[j]) == 1) { e1rforce = e2rforce = 0.0; s_e1rforce = s_e2rforce = 0.0; ElecElecElec(rc,eradius[i],eradius[j],&ecoul,&fpair, &e1rforce,&e2rforce); PauliElecElec(spin[i] == spin[j],rc,eradius[i],eradius[j], &epauli,&s_fpair,&s_e1rforce,&s_e2rforce); // Apply conversion factor epauli *= hhmss2e; s_fpair *= hhmss2e; e1rforce = spline * (qqrd2e * e1rforce + hhmss2e * s_e1rforce); erforce[i] += e1rforce; e2rforce = spline * (qqrd2e * e2rforce + hhmss2e * s_e2rforce); erforce[j] += e2rforce; // Radial electron virial, iff flexible pressure flag set if (evflag && pressure_with_evirials_flag) { e1rvirial = eradius[i] * e1rforce; e2rvirial = eradius[j] * e2rforce; ev_tally_eff(i,j,nlocal,newton_pair,0.0,e1rvirial+e2rvirial); } } // fixed-core (i) - electron (j) interactions else if (spin[i] == 2 && abs(spin[j]) == 1) { e1rforce = e2rforce = 0.0; s_e1rforce = s_e2rforce = 0.0; ElecNucElec(q[i],rc,eradius[j],&ecoul,&fpair,&e2rforce); ElecElecElec(rc,eradius[i],eradius[j],&ecoul,&fpair, &e1rforce,&e2rforce); ElecElecElec(rc,eradius[i],eradius[j],&ecoul,&fpair, &e1rforce,&e2rforce); PauliElecElec(0,rc,eradius[i],eradius[j],&epauli, &s_fpair,&s_e1rforce,&s_e2rforce); PauliElecElec(1,rc,eradius[i],eradius[j],&epauli, &s_fpair,&s_e1rforce,&s_e2rforce); // Apply conversion factor epauli *= hhmss2e; s_fpair *= hhmss2e; // only update virial for j electron e2rforce = spline * (qqrd2e * e2rforce + hhmss2e * s_e2rforce); erforce[j] += e2rforce; // Radial electron virial, iff flexible pressure flag set if (evflag && pressure_with_evirials_flag) { e2rvirial = eradius[j] * e2rforce; ev_tally_eff(j,j,nlocal,newton_pair,0.0,e2rvirial); } } // electron (i) - fixed-core (j) interactions else if (abs(spin[i]) == 1 && spin[j] == 2) { e1rforce = e2rforce = 0.0; s_e1rforce = s_e2rforce = 0.0; ElecNucElec(q[j],rc,eradius[i],&ecoul,&fpair,&e2rforce); ElecElecElec(rc,eradius[j],eradius[i],&ecoul,&fpair, &e1rforce,&e2rforce); ElecElecElec(rc,eradius[j],eradius[i],&ecoul,&fpair, &e1rforce,&e2rforce); PauliElecElec(0,rc,eradius[j],eradius[i],&epauli, &s_fpair,&s_e1rforce,&s_e2rforce); PauliElecElec(1,rc,eradius[j],eradius[i],&epauli, &s_fpair,&s_e1rforce,&s_e2rforce); // Apply conversion factor epauli *= hhmss2e; s_fpair *= hhmss2e; // only update virial for i electron e2rforce = spline * (qqrd2e * e2rforce + hhmss2e * s_e2rforce); erforce[i] += e2rforce; // add radial atomic virial, iff flexible pressure flag set if (evflag && pressure_with_evirials_flag) { e2rvirial = eradius[i] * e2rforce; ev_tally_eff(i,i,nlocal,newton_pair,0.0,e2rvirial); } } // fixed-core (i) - fixed-core (j) interactions else if (spin[i] == 2 && spin[j] == 2) { e1rforce = e2rforce = 0.0; s_e1rforce = s_e2rforce = 0.0; double qxq = q[i]*q[j]; ElecNucNuc(qxq, rc, &ecoul, &fpair); ElecNucElec(q[i],rc,eradius[j],&ecoul,&fpair,&e1rforce); ElecNucElec(q[i],rc,eradius[j],&ecoul,&fpair,&e1rforce); ElecNucElec(q[j],rc,eradius[i],&ecoul,&fpair,&e1rforce); ElecNucElec(q[j],rc,eradius[i],&ecoul,&fpair,&e1rforce); ElecElecElec(rc,eradius[i],eradius[j],&ecoul,&fpair, &e1rforce,&e2rforce); ElecElecElec(rc,eradius[i],eradius[j],&ecoul,&fpair, &e1rforce,&e2rforce); ElecElecElec(rc,eradius[i],eradius[j],&ecoul,&fpair, &e1rforce,&e2rforce); ElecElecElec(rc,eradius[i],eradius[j],&ecoul,&fpair, &e1rforce,&e2rforce); PauliElecElec(0,rc,eradius[i],eradius[j],&epauli, &s_fpair,&s_e1rforce,&s_e2rforce); PauliElecElec(1,rc,eradius[i],eradius[j],&epauli, &s_fpair,&s_e1rforce,&s_e2rforce); epauli *= 2; s_fpair *= 2; // Apply conversion factor epauli *= hhmss2e; s_fpair *= hhmss2e; } // pseudo-core (i) - electron/fixed-core electrons (j) interactions else if (spin[i] == 3 && (abs(spin[j]) == 1 || spin[j] == 2)) { e2rforce = ecp_e2rforce = 0.0; if (((PAULI_CORE_D[ecp_type[itype]]) == 0.0) && ((PAULI_CORE_E[ecp_type[itype]]) == 0.0)) { if (abs(spin[j]) == 1) { ElecCoreElec(q[i],rc,eradius[i],eradius[j],&ecoul, &fpair,&e2rforce); PauliCoreElec(rc,eradius[j],&ecp_epauli,&ecp_fpair, &ecp_e2rforce,PAULI_CORE_A[ecp_type[itype]], PAULI_CORE_B[ecp_type[itype]], PAULI_CORE_C[ecp_type[itype]]); } else { // add second s electron contribution from fixed-core double qxq = q[i]*q[j]; ElecCoreNuc(qxq, rc, eradius[j], &ecoul, &fpair); ElecCoreElec(q[i],rc,eradius[i],eradius[j],&ecoul, &fpair,&e2rforce); ElecCoreElec(q[i],rc,eradius[i],eradius[j],&ecoul, &fpair,&e2rforce); PauliCoreElec(rc,eradius[j],&ecp_epauli,&ecp_fpair, &ecp_e2rforce,PAULI_CORE_A[ecp_type[itype]], PAULI_CORE_B[ecp_type[itype]], PAULI_CORE_C[ecp_type[itype]]); PauliCoreElec(rc,eradius[j],&ecp_epauli,&ecp_fpair, &ecp_e2rforce,PAULI_CORE_A[ecp_type[itype]], PAULI_CORE_B[ecp_type[itype]], PAULI_CORE_C[ecp_type[itype]]); } } else { if (abs(spin[j]) == 1) { ElecCoreElec(q[i],rc,eradius[i],eradius[j],&ecoul, &fpair,&e2rforce); PauliCorePElec(rc,eradius[j],&ecp_epauli,&ecp_fpair, &ecp_e2rforce,PAULI_CORE_A[ecp_type[itype]],PAULI_CORE_B[ecp_type[itype]], PAULI_CORE_C[ecp_type[itype]],PAULI_CORE_D[ecp_type[itype]],PAULI_CORE_E[ecp_type[itype]]); } else { // add second s electron contribution from fixed-core double qxq = q[i]*q[j]; ElecCoreNuc(qxq, rc, eradius[j], &ecoul, &fpair); ElecCoreElec(q[i],rc,eradius[i],eradius[j],&ecoul, &fpair,&e2rforce); ElecCoreElec(q[i],rc,eradius[i],eradius[j],&ecoul, &fpair,&e2rforce); PauliCorePElec(rc,eradius[j],&ecp_epauli,&ecp_fpair, &ecp_e2rforce,PAULI_CORE_A[ecp_type[itype]], PAULI_CORE_B[ecp_type[itype]], PAULI_CORE_C[ecp_type[itype]],PAULI_CORE_D[ecp_type[itype]],PAULI_CORE_E[ecp_type[itype]]); PauliCorePElec(rc,eradius[j],&ecp_epauli,&ecp_fpair, &ecp_e2rforce,PAULI_CORE_A[ecp_type[itype]], PAULI_CORE_B[ecp_type[itype]], PAULI_CORE_C[ecp_type[itype]],PAULI_CORE_D[ecp_type[itype]],PAULI_CORE_E[ecp_type[itype]]); } } // Apply conversion factor from Hartree to kcal/mol ecp_epauli *= h2e; ecp_fpair *= h2e; // only update virial for j electron e2rforce = spline * (qqrd2e * e2rforce + h2e * ecp_e2rforce); erforce[j] += e2rforce; // add radial atomic virial, iff flexible pressure flag set if (evflag && pressure_with_evirials_flag) { e2rvirial = eradius[j] * e2rforce; ev_tally_eff(j,j,nlocal,newton_pair,0.0,e2rvirial); } } // electron/fixed-core electrons (i) - pseudo-core (j) interactions else if ((abs(spin[i]) == 1 || spin[i] == 2) && spin[j] == 3) { e1rforce = ecp_e1rforce = 0.0; if (((PAULI_CORE_D[ecp_type[jtype]]) == 0.0) && ((PAULI_CORE_E[ecp_type[jtype]]) == 0.0)) { if (abs(spin[i]) == 1) { ElecCoreElec(q[j],rc,eradius[j],eradius[i],&ecoul, &fpair,&e1rforce); PauliCoreElec(rc,eradius[i],&ecp_epauli,&ecp_fpair, &ecp_e1rforce,PAULI_CORE_A[ecp_type[jtype]],PAULI_CORE_B[ecp_type[jtype]], PAULI_CORE_C[ecp_type[jtype]]); } else { double qxq = q[i]*q[j]; ElecCoreNuc(qxq,rc,eradius[i],&ecoul,&fpair); ElecCoreElec(q[j],rc,eradius[j],eradius[i],&ecoul, &fpair,&e1rforce); ElecCoreElec(q[j],rc,eradius[j],eradius[i],&ecoul, &fpair,&e1rforce); PauliCoreElec(rc,eradius[i],&ecp_epauli,&ecp_fpair, &ecp_e1rforce,PAULI_CORE_A[ecp_type[jtype]], PAULI_CORE_B[ecp_type[jtype]], PAULI_CORE_C[ecp_type[jtype]]); PauliCoreElec(rc,eradius[i],&ecp_epauli,&ecp_fpair, &ecp_e1rforce,PAULI_CORE_A[ecp_type[jtype]], PAULI_CORE_B[ecp_type[jtype]], PAULI_CORE_C[ecp_type[jtype]]); } } else { if (abs(spin[i]) == 1) { ElecCoreElec(q[j],rc,eradius[j],eradius[i],&ecoul, &fpair,&e1rforce); PauliCorePElec(rc,eradius[i],&ecp_epauli,&ecp_fpair, &ecp_e1rforce,PAULI_CORE_A[ecp_type[jtype]],PAULI_CORE_B[ecp_type[jtype]], PAULI_CORE_C[ecp_type[jtype]],PAULI_CORE_D[ecp_type[jtype]],PAULI_CORE_E[ecp_type[jtype]]); } else { double qxq = q[i]*q[j]; ElecCoreNuc(qxq,rc,eradius[i],&ecoul,&fpair); ElecCoreElec(q[j],rc,eradius[j],eradius[i],&ecoul, &fpair,&e1rforce); ElecCoreElec(q[j],rc,eradius[j],eradius[i],&ecoul, &fpair,&e1rforce); PauliCorePElec(rc,eradius[i],&ecp_epauli,&ecp_fpair, &ecp_e1rforce,PAULI_CORE_A[ecp_type[jtype]], PAULI_CORE_B[ecp_type[jtype]], PAULI_CORE_C[ecp_type[jtype]],PAULI_CORE_D[ecp_type[jtype]],PAULI_CORE_E[ecp_type[jtype]]); PauliCorePElec(rc,eradius[i],&ecp_epauli,&ecp_fpair, &ecp_e1rforce,PAULI_CORE_A[ecp_type[jtype]], PAULI_CORE_B[ecp_type[jtype]], PAULI_CORE_C[ecp_type[jtype]],PAULI_CORE_D[ecp_type[jtype]],PAULI_CORE_E[ecp_type[jtype]]); } } // Apply conversion factor from Hartree to kcal/mol ecp_epauli *= h2e; ecp_fpair *= h2e; // only update virial for j electron e1rforce = spline * (qqrd2e * e1rforce + h2e * ecp_e1rforce); erforce[i] += e1rforce; // add radial atomic virial, iff flexible pressure flag set if (evflag && pressure_with_evirials_flag) { e1rvirial = eradius[i] * e1rforce; ev_tally_eff(i,i,nlocal,newton_pair,0.0,e1rvirial); } } // pseudo-core (i) - pseudo-core (j) interactions else if (spin[i] == 3 && spin[j] == 3) { double qxq = q[i]*q[j]; ElecCoreCore(qxq,rc,eradius[i],eradius[j],&ecoul,&fpair); } // Apply Coulomb conversion factor for all cases ecoul *= qqrd2e; fpair *= qqrd2e; // Sum up energy and force contributions epauli += ecp_epauli; energy = ecoul + epauli; fpair = fpair + s_fpair + ecp_fpair; // Apply cutoff spline fpair = fpair * spline - energy * dspline; energy = spline * energy; // Tally cartesian forces SmallRForce(delx,dely,delz,rc,fpair,&fx,&fy,&fz); f[i][0] += fx; f[i][1] += fy; f[i][2] += fz; if (newton_pair || j < nlocal) { f[j][0] -= fx; f[j][1] -= fy; f[j][2] -= fz; } // Tally energy (in ecoul) and compute normal pressure virials if (evflag) ev_tally_xyz(i,j,nlocal,newton_pair,0.0, energy,fx,fy,fz,delx,dely,delz); if (eflag_global) { if (newton_pair) { pvector[1] += spline * epauli; pvector[2] += spline * ecoul; } else { halfpauli = 0.5 * spline * epauli; halfcoul = 0.5 * spline * ecoul; if (i < nlocal) { pvector[1] += halfpauli; pvector[2] += halfcoul; } if (j < nlocal) { pvector[1] += halfpauli; pvector[2] += halfcoul; } } } } } // limit electron stifness (size) for periodic systems, to max=half-box-size if (abs(spin[i]) == 1 && limit_eradius_flag) { double half_box_length=0, dr, kfactor=hhmss2e*1.0; e1rforce = errestrain = 0.0; if (domain->xperiodic == 1 || domain->yperiodic == 1 || domain->zperiodic == 1) { delx = domain->boxhi[0]-domain->boxlo[0]; dely = domain->boxhi[1]-domain->boxlo[1]; delz = domain->boxhi[2]-domain->boxlo[2]; half_box_length = 0.5 * MIN(delx, MIN(dely, delz)); if (eradius[i] > half_box_length) { dr = eradius[i]-half_box_length; errestrain=0.5*kfactor*dr*dr; e1rforce=-kfactor*dr; if (eflag_global) pvector[3] += errestrain; erforce[i] += e1rforce; // Tally radial restrain energy and add radial restrain virial if (evflag) { ev_tally_eff(i,i,nlocal,newton_pair,errestrain,0.0); if (pressure_with_evirials_flag) // flexible electron pressure ev_tally_eff(i,i,nlocal,newton_pair,0.0,eradius[i]*e1rforce); } } } } } if (vflag_fdotr) { virial_fdotr_compute(); if (pressure_with_evirials_flag) virial_eff_compute(); } } /* ---------------------------------------------------------------------- eff-specific contribution to global virial ------------------------------------------------------------------------- */ void PairEffCut::virial_eff_compute() { double *eradius = atom->eradius; double *erforce = atom->erforce; double e_virial; int *spin = atom->spin; // sum over force on all particles including ghosts if (neighbor->includegroup == 0) { int nall = atom->nlocal + atom->nghost; for (int i = 0; i < nall; i++) { if (spin[i]) { e_virial = erforce[i]*eradius[i]/3; virial[0] += e_virial; virial[1] += e_virial; virial[2] += e_virial; } } // neighbor includegroup flag is set // sum over force on initial nfirst particles and ghosts } else { int nall = atom->nfirst; for (int i = 0; i < nall; i++) { if (spin[i]) { e_virial = erforce[i]*eradius[i]/3; virial[0] += e_virial; virial[1] += e_virial; virial[2] += e_virial; } } nall = atom->nlocal + atom->nghost; for (int i = atom->nlocal; i < nall; i++) { if (spin[i]) { e_virial = erforce[i]*eradius[i]/3; virial[0] += e_virial; virial[1] += e_virial; virial[2] += e_virial; } } } } /* ---------------------------------------------------------------------- tally eng_vdwl and virial into per-atom accumulators for virial radial electronic contributions ------------------------------------------------------------------------- */ void PairEffCut::ev_tally_eff(int i, int j, int nlocal, int newton_pair, double energy, double e_virial) { double energyhalf; double partial_evirial = e_virial/3.0; double half_partial_evirial = partial_evirial/2; int *spin = atom->spin; if (eflag_either) { if (eflag_global) { if (newton_pair) eng_coul += energy; else { energyhalf = 0.5*energy; if (i < nlocal) eng_coul += energyhalf; if (j < nlocal) eng_coul += energyhalf; } } if (eflag_atom) { if (newton_pair || i < nlocal) eatom[i] += 0.5 * energy; if (newton_pair || j < nlocal) eatom[j] += 0.5 * energy; } } if (vflag_either) { if (vflag_global) { if (spin[i] && i < nlocal) { virial[0] += half_partial_evirial; virial[1] += half_partial_evirial; virial[2] += half_partial_evirial; } if (spin[j] && j < nlocal) { virial[0] += half_partial_evirial; virial[1] += half_partial_evirial; virial[2] += half_partial_evirial; } } if (vflag_atom) { if (spin[i]) { if (newton_pair || i < nlocal) { vatom[i][0] += half_partial_evirial; vatom[i][1] += half_partial_evirial; vatom[i][2] += half_partial_evirial; } } if (spin[j]) { if (newton_pair || j < nlocal) { vatom[j][0] += half_partial_evirial; vatom[j][1] += half_partial_evirial; vatom[j][2] += half_partial_evirial; } } } } } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairEffCut::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"); } /* --------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairEffCut::settings(int narg, char **arg) { if (narg < 1) error->all(FLERR,"Illegal pair_style command"); // Defaults ECP parameters for C (radius=0.154) PAULI_CORE_A[6] = 22.721015; PAULI_CORE_B[6] = 0.728733; PAULI_CORE_C[6] = 1.103199; PAULI_CORE_D[6] = 17.695345; PAULI_CORE_E[6] = 6.693621; // Defaults ECP parameters for N (radius=0.394732) PAULI_CORE_A[7] = 16.242367; PAULI_CORE_B[7] = 0.602818; PAULI_CORE_C[7] = 1.081856; PAULI_CORE_D[7] = 7.150803; PAULI_CORE_E[7] = 5.351936; // Defaults p-element ECP parameters for Oxygen (radius=0.15) PAULI_CORE_A[8] = 29.5185; PAULI_CORE_B[8] = 0.32995; PAULI_CORE_C[8] = 1.21676; PAULI_CORE_D[8] = 11.98757; PAULI_CORE_E[8] = 3.073417; // Defaults ECP parameters for Al (radius=1.660) PAULI_CORE_A[13] = 0.486; PAULI_CORE_B[13] = 1.049; PAULI_CORE_C[13] = 0.207; PAULI_CORE_D[13] = 0.0; PAULI_CORE_E[13] = 0.0; // Defaults ECP parameters for Si (radius=1.691) PAULI_CORE_A[14] = 0.320852; PAULI_CORE_B[14] = 2.283269; PAULI_CORE_C[14] = 0.814857; PAULI_CORE_D[14] = 0.0; PAULI_CORE_E[14] = 0.0; cut_global = force->numeric(FLERR,arg[0]); limit_eradius_flag = 0; pressure_with_evirials_flag = 0; int atype; int iarg = 1; int ecp_found = 0; while (iarg < narg) { if (strcmp(arg[iarg],"limit/eradius") == 0) { limit_eradius_flag = 1; iarg += 1; } else if (strcmp(arg[iarg],"pressure/evirials") == 0) { pressure_with_evirials_flag = 1; iarg += 1; } else if (strcmp(arg[iarg],"ecp") == 0) { iarg += 1; while (iarg < narg) { atype = force->inumeric(FLERR,arg[iarg]); if (strcmp(arg[iarg+1],"C") == 0) ecp_type[atype] = 6; else if (strcmp(arg[iarg+1],"N") == 0) ecp_type[atype] = 7; else if (strcmp(arg[iarg+1],"O") == 0) ecp_type[atype] = 8; else if (strcmp(arg[iarg+1],"Al") == 0) ecp_type[atype] = 13; else if (strcmp(arg[iarg+1],"Si") == 0) ecp_type[atype] = 14; else error->all(FLERR, "Note: there are no default parameters for this atom ECP\n"); iarg += 2; ecp_found = 1; } } } if (!ecp_found && atom->ecp_flag) error->all(FLERR,"Need to specify ECP type on pair_style command"); // Need to introduce 2 new constants w/out changing update.cpp if (force->qqr2e==332.06371) { // i.e. Real units chosen h2e = 627.509; // hartree->kcal/mol hhmss2e = 175.72044219620075; // hartree->kcal/mol * (Bohr->Angstrom)^2 } else if (force->qqr2e==1.0) { // electron units h2e = 1.0; hhmss2e = 1.0; } else error->all(FLERR,"Check your units"); // 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; } } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairEffCut::init_style() { // error and warning checks if (!atom->q_flag || !atom->spin_flag || !atom->eradius_flag || !atom->erforce_flag) error->all(FLERR,"Pair eff/cut requires atom attributes " "q, spin, eradius, erforce"); // add hook to minimizer for eradius and erforce if (update->whichflag == 2) update->minimize->request(this,1,0.01); // make sure to use the appropriate timestep when using real units if (update->whichflag == 1) { if (force->qqr2e == 332.06371 && update->dt == 1.0) error->all(FLERR,"You must lower the default real units timestep for pEFF "); } // need a half neigh list and optionally a granular history neigh list neighbor->request(this,instance_me); } /* ---------------------------------------------------------------------- set coeffs for one or more type electron pairs (ECP-only) ------------------------------------------------------------------------- */ void PairEffCut::coeff(int narg, char **arg) { if (!allocated) allocate(); if ((strcmp(arg[0],"*") == 0) || (strcmp(arg[1],"*") == 0)) { int ilo,ihi,jlo,jhi; - force->bounds(arg[0],atom->ntypes,ilo,ihi); - force->bounds(arg[1],atom->ntypes,jlo,jhi); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double cut_one = cut_global; if (narg == 3) cut_one = force->numeric(FLERR,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; setflag[i][j] = 1; count++; } } if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); } else { int ecp; ecp = force->inumeric(FLERR,arg[0]); if (strcmp(arg[1],"s") ==0) { PAULI_CORE_A[ecp_type[ecp]] = force->numeric(FLERR,arg[2]); PAULI_CORE_B[ecp_type[ecp]] = force->numeric(FLERR,arg[3]); PAULI_CORE_C[ecp_type[ecp]] = force->numeric(FLERR,arg[4]); PAULI_CORE_D[ecp_type[ecp]] = 0.0; PAULI_CORE_E[ecp_type[ecp]] = 0.0; } else if (strcmp(arg[1],"p") ==0) { PAULI_CORE_A[ecp_type[ecp]] = force->numeric(FLERR,arg[2]); PAULI_CORE_B[ecp_type[ecp]] = force->numeric(FLERR,arg[3]); PAULI_CORE_C[ecp_type[ecp]] = force->numeric(FLERR,arg[4]); PAULI_CORE_D[ecp_type[ecp]] = force->numeric(FLERR,arg[5]); PAULI_CORE_E[ecp_type[ecp]] = force->numeric(FLERR,arg[6]); } else error->all(FLERR,"Illegal pair_coeff command"); } } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairEffCut::init_one(int i, int j) { if (setflag[i][j] == 0) cut[i][j] = mix_distance(cut[i][i],cut[j][j]); return cut[i][j]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairEffCut::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 PairEffCut::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 PairEffCut::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 PairEffCut::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); } /* ---------------------------------------------------------------------- returns pointers to the log() of electron radius and corresponding force minimizer operates on log(radius) so radius never goes negative these arrays are stored locally by pair style ------------------------------------------------------------------------- */ void PairEffCut::min_xf_pointers(int ignore, double **xextra, double **fextra) { // grow arrays if necessary // need to be atom->nmax in length if (atom->nmax > nmax) { memory->destroy(min_eradius); memory->destroy(min_erforce); nmax = atom->nmax; memory->create(min_eradius,nmax,"pair:min_eradius"); memory->create(min_erforce,nmax,"pair:min_erforce"); } *xextra = min_eradius; *fextra = min_erforce; } /* ---------------------------------------------------------------------- minimizer requests the log() of electron radius and corresponding force calculate and store in min_eradius and min_erforce ------------------------------------------------------------------------- */ void PairEffCut::min_xf_get(int ignore) { double *eradius = atom->eradius; double *erforce = atom->erforce; int *spin = atom->spin; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (spin[i]) { min_eradius[i] = log(eradius[i]); min_erforce[i] = eradius[i]*erforce[i]; } else min_eradius[i] = min_erforce[i] = 0.0; } /* ---------------------------------------------------------------------- minimizer has changed the log() of electron radius propagate the change back to eradius ------------------------------------------------------------------------- */ void PairEffCut::min_x_set(int ignore) { double *eradius = atom->eradius; int *spin = atom->spin; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (spin[i]) eradius[i] = exp(min_eradius[i]); } /* ---------------------------------------------------------------------- memory usage of local atom-based arrays ------------------------------------------------------------------------- */ double PairEffCut::memory_usage() { double bytes = maxeatom * sizeof(double); bytes += maxvatom*6 * sizeof(double); bytes += 2 * nmax * sizeof(double); return bytes; } diff --git a/src/USER-FEP/compute_fep.cpp b/src/USER-FEP/compute_fep.cpp index d3c3bf940..bfa3bf7e2 100644 --- a/src/USER-FEP/compute_fep.cpp +++ b/src/USER-FEP/compute_fep.cpp @@ -1,666 +1,666 @@ /* ---------------------------------------------------------------------- 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: Agilio Padua (Univ Blaise Pascal & CNRS) ------------------------------------------------------------------------- */ #include #include #include #include #include "comm.h" #include "update.h" #include "atom.h" #include "domain.h" #include "force.h" #include "pair.h" #include "pair_hybrid.h" #include "kspace.h" #include "input.h" #include "fix.h" #include "modify.h" #include "variable.h" #include "timer.h" #include "memory.h" #include "error.h" #include "compute_fep.h" using namespace LAMMPS_NS; enum{PAIR,ATOM}; enum{CHARGE}; /* ---------------------------------------------------------------------- */ ComputeFEP::ComputeFEP(LAMMPS *lmp, int narg, char **arg) : Compute(lmp, narg, arg) { if (narg < 5) error->all(FLERR,"Illegal number of arguments in compute fep"); scalar_flag = 0; vector_flag = 1; size_vector = 3; extvector = 0; vector = new double[3]; fepinitflag = 0; // avoid init to run entirely when called by write_data temp_fep = force->numeric(FLERR,arg[3]); // count # of perturbations npert = 0; int iarg = 4; while (iarg < narg) { if (strcmp(arg[iarg],"pair") == 0) { if (iarg+6 > narg) error->all(FLERR, "Illegal pair attribute in compute fep"); npert++; iarg += 6; } else if (strcmp(arg[iarg],"atom") == 0) { if (iarg+4 > narg) error->all(FLERR, "Illegal atom attribute in compute fep"); npert++; iarg += 4; } else break; } if (npert == 0) error->all(FLERR,"Illegal syntax in compute fep"); perturb = new Perturb[npert]; // parse keywords npert = 0; chgflag = 0; iarg = 4; while (iarg < narg) { if (strcmp(arg[iarg],"pair") == 0) { perturb[npert].which = PAIR; int n = strlen(arg[iarg+1]) + 1; perturb[npert].pstyle = new char[n]; strcpy(perturb[npert].pstyle,arg[iarg+1]); n = strlen(arg[iarg+2]) + 1; perturb[npert].pparam = new char[n]; strcpy(perturb[npert].pparam,arg[iarg+2]); - force->bounds(arg[iarg+3],atom->ntypes, + force->bounds(FLERR,arg[iarg+3],atom->ntypes, perturb[npert].ilo,perturb[npert].ihi); - force->bounds(arg[iarg+4],atom->ntypes, + force->bounds(FLERR,arg[iarg+4],atom->ntypes, perturb[npert].jlo,perturb[npert].jhi); if (strstr(arg[iarg+5],"v_") == arg[iarg+5]) { n = strlen(&arg[iarg+5][2]) + 1; perturb[npert].var = new char[n]; strcpy(perturb[npert].var,&arg[iarg+5][2]); } else error->all(FLERR,"Illegal variable in compute fep"); npert++; iarg += 6; } else if (strcmp(arg[iarg],"atom") == 0) { perturb[npert].which = ATOM; if (strcmp(arg[iarg+1],"charge") == 0) { perturb[npert].aparam = CHARGE; chgflag = 1; } else error->all(FLERR,"Illegal atom argument in compute fep"); - force->bounds(arg[iarg+2],atom->ntypes, + force->bounds(FLERR,arg[iarg+2],atom->ntypes, perturb[npert].ilo,perturb[npert].ihi); if (strstr(arg[iarg+3],"v_") == arg[iarg+3]) { int n = strlen(&arg[iarg+3][2]) + 1; perturb[npert].var = new char[n]; strcpy(perturb[npert].var,&arg[iarg+3][2]); } else error->all(FLERR,"Illegal variable in compute fep"); npert++; iarg += 4; } else break; } // optional keywords tailflag = 0; volumeflag = 0; while (iarg < narg) { if (strcmp(arg[iarg],"tail") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal optional keyword " "in compute fep"); if (strcmp(arg[iarg+1],"no") == 0) tailflag = 0; else if (strcmp(arg[iarg+1],"yes") == 0) tailflag = 1; else error->all(FLERR,"Illegal optional keyword in compute fep"); iarg += 2; } else if (strcmp(arg[iarg],"volume") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal optional keyword " "in compute fep"); if (strcmp(arg[iarg+1],"no") == 0) volumeflag = 0; else if (strcmp(arg[iarg+1],"yes") == 0) volumeflag = 1; else error->all(FLERR,"Illegal optional keyword in compute fep"); iarg += 2; } else error->all(FLERR,"Illegal optional keyword in compute fep"); } // allocate pair style arrays int ntype = atom->ntypes; for (int m = 0; m < npert; m++) { if (perturb[m].which == PAIR) memory->create(perturb[m].array_orig,ntype+1,ntype+1,"fep:array_orig"); } // allocate space for charge, force, energy, virial arrays f_orig = NULL; q_orig = NULL; peatom_orig = keatom_orig = NULL; pvatom_orig = kvatom_orig = NULL; allocate_storage(); fixgpu = NULL; } /* ---------------------------------------------------------------------- */ ComputeFEP::~ComputeFEP() { delete [] vector; for (int m = 0; m < npert; m++) { delete [] perturb[m].var; if (perturb[m].which == PAIR) { delete [] perturb[m].pstyle; delete [] perturb[m].pparam; memory->destroy(perturb[m].array_orig); } } delete [] perturb; deallocate_storage(); } /* ---------------------------------------------------------------------- */ void ComputeFEP::init() { int i,j; if (!fepinitflag) // avoid init to run entirely when called by write_data fepinitflag = 1; else return; // setup and error checks pairflag = 0; for (int m = 0; m < npert; m++) { Perturb *pert = &perturb[m]; pert->ivar = input->variable->find(pert->var); if (pert->ivar < 0) error->all(FLERR,"Variable name for compute fep does not exist"); if (!input->variable->equalstyle(pert->ivar)) error->all(FLERR,"Variable for compute fep is of invalid style"); if (force->pair == NULL) error->all(FLERR,"compute fep pair requires pair interactions"); if (pert->which == PAIR) { pairflag = 1; Pair *pair = force->pair_match(pert->pstyle,1); if (pair == NULL) error->all(FLERR,"compute fep pair style " "does not exist"); void *ptr = pair->extract(pert->pparam,pert->pdim); if (ptr == NULL) error->all(FLERR,"compute fep pair style param not supported"); pert->array = (double **) ptr; // if pair hybrid, test that ilo,ihi,jlo,jhi are valid for sub-style if ((strcmp(force->pair_style,"hybrid") == 0 || strcmp(force->pair_style,"hybrid/overlay") == 0)) { PairHybrid *pair = (PairHybrid *) force->pair; for (i = pert->ilo; i <= pert->ihi; i++) for (j = MAX(pert->jlo,i); j <= pert->jhi; j++) if (!pair->check_ijtype(i,j,pert->pstyle)) error->all(FLERR,"compute fep type pair range is not valid for " "pair hybrid sub-style"); } } else if (pert->which == ATOM) { if (pert->aparam == CHARGE) { if (!atom->q_flag) error->all(FLERR,"compute fep requires atom attribute charge"); } } } if (tailflag) { if (force->pair->tail_flag == 0) error->all(FLERR,"Compute fep tail when pair style does not " "compute tail corrections"); } // detect if package gpu is present int ifixgpu = modify->find_fix("package_gpu"); if (ifixgpu >= 0) fixgpu = modify->fix[ifixgpu]; if (comm->me == 0) { if (screen) { fprintf(screen, "FEP settings ...\n"); fprintf(screen, " temperature = %f\n", temp_fep); fprintf(screen, " tail %s\n", (tailflag ? "yes":"no")); for (int m = 0; m < npert; m++) { Perturb *pert = &perturb[m]; if (pert->which == PAIR) fprintf(screen, " %s %s %d-%d %d-%d\n", pert->pstyle, pert->pparam, pert->ilo, pert->ihi, pert->jlo, pert->jhi); else if (pert->which == ATOM) fprintf(screen, " %d-%d charge\n", pert->ilo, pert->ihi); } } if (logfile) { fprintf(logfile, "FEP settings ...\n"); fprintf(logfile, " temperature = %f\n", temp_fep); fprintf(logfile, " tail %s\n", (tailflag ? "yes":"no")); for (int m = 0; m < npert; m++) { Perturb *pert = &perturb[m]; if (pert->which == PAIR) fprintf(logfile, " %s %s %d-%d %d-%d\n", pert->pstyle, pert->pparam, pert->ilo, pert->ihi, pert->jlo, pert->jhi); else if (pert->which == ATOM) fprintf(logfile, " %d-%d charge\n", pert->ilo, pert->ihi); } } } } /* ---------------------------------------------------------------------- */ void ComputeFEP::compute_vector() { double pe0,pe1; eflag = 1; vflag = 0; invoked_vector = update->ntimestep; if (atom->nmax > nmax) { // reallocate working arrays if necessary deallocate_storage(); allocate_storage(); } backup_qfev(); // backup charge, force, energy, virial array values backup_params(); // backup pair parameters timer->stamp(); if (force->pair && force->pair->compute_flag) { force->pair->compute(eflag,vflag); timer->stamp(Timer::PAIR); } if (chgflag && force->kspace && force->kspace->compute_flag) { force->kspace->compute(eflag,vflag); timer->stamp(Timer::KSPACE); } // accumulate force/energy/virial from /gpu pair styles if (fixgpu) fixgpu->post_force(vflag); pe0 = compute_epair(); perturb_params(); timer->stamp(); if (force->pair && force->pair->compute_flag) { force->pair->compute(eflag,vflag); timer->stamp(Timer::PAIR); } if (chgflag && force->kspace && force->kspace->compute_flag) { force->kspace->compute(eflag,vflag); timer->stamp(Timer::KSPACE); } // accumulate force/energy/virial from /gpu pair styles // this is required as to empty the answer queue, // otherwise the force compute on the GPU in the next step would be incorrect if (fixgpu) fixgpu->post_force(vflag); pe1 = compute_epair(); restore_qfev(); // restore charge, force, energy, virial array values restore_params(); // restore pair parameters vector[0] = pe1-pe0; vector[1] = exp(-(pe1-pe0)/(force->boltz*temp_fep)); vector[2] = domain->xprd * domain->yprd * domain->zprd; if (volumeflag) vector[1] *= vector[2]; } /* ---------------------------------------------------------------------- obtain pair energy from lammps accumulators ------------------------------------------------------------------------- */ double ComputeFEP::compute_epair() { double eng, eng_pair; eng = 0.0; if (force->pair) eng = force->pair->eng_vdwl + force->pair->eng_coul; MPI_Allreduce(&eng,&eng_pair,1,MPI_DOUBLE,MPI_SUM,world); if (tailflag) { double volume = domain->xprd * domain->yprd * domain->zprd; eng_pair += force->pair->etail / volume; } if (chgflag && force->kspace) eng_pair += force->kspace->energy; return eng_pair; } /* ---------------------------------------------------------------------- apply perturbation to pair, atom parameters based on variable evaluation ------------------------------------------------------------------------- */ void ComputeFEP::perturb_params() { int i,j; for (int m = 0; m < npert; m++) { Perturb *pert = &perturb[m]; double delta = input->variable->compute_equal(pert->ivar); if (pert->which == PAIR) { // modify pair parameters for (i = pert->ilo; i <= pert->ihi; i++) for (j = MAX(pert->jlo,i); j <= pert->jhi; j++) pert->array[i][j] = pert->array_orig[i][j] + delta; } else if (pert->which == ATOM) { if (pert->aparam == CHARGE) { // modify charges int *atype = atom->type; double *q = atom->q; int *mask = atom->mask; int natom = atom->nlocal + atom->nghost; for (i = 0; i < natom; i++) if (atype[i] >= pert->ilo && atype[i] <= pert->ihi) if (mask[i] & groupbit) q[i] += delta; } } } // re-initialize pair styles if any PAIR settings were changed // this resets other coeffs that may depend on changed values, // and also offset and tail corrections if (pairflag) force->pair->reinit(); // reset KSpace charges if charges have changed if (chgflag && force->kspace) force->kspace->qsum_qsq(); } /* ---------------------------------------------------------------------- backup pair parameters ------------------------------------------------------------------------- */ void ComputeFEP::backup_params() { int i,j; for (int m = 0; m < npert; m++) { Perturb *pert = &perturb[m]; if (pert->which == PAIR) { for (i = pert->ilo; i <= pert->ihi; i++) for (j = MAX(pert->jlo,i); j <= pert->jhi; j++) pert->array_orig[i][j] = pert->array[i][j]; } } } /* ---------------------------------------------------------------------- restore pair parameters to original values ------------------------------------------------------------------------- */ void ComputeFEP::restore_params() { int i,j; for (int m = 0; m < npert; m++) { Perturb *pert = &perturb[m]; if (pert->which == PAIR) { for (i = pert->ilo; i <= pert->ihi; i++) for (j = MAX(pert->jlo,i); j <= pert->jhi; j++) pert->array[i][j] = pert->array_orig[i][j]; } } if (pairflag) force->pair->reinit(); // reset KSpace charges if charges have changed if (chgflag && force->kspace) force->kspace->qsum_qsq(); } /* ---------------------------------------------------------------------- manage storage for charge, force, energy, virial arrays ------------------------------------------------------------------------- */ void ComputeFEP::allocate_storage() { nmax = atom->nmax; memory->create(f_orig,nmax,3,"fep:f_orig"); memory->create(peatom_orig,nmax,"fep:peatom_orig"); memory->create(pvatom_orig,nmax,6,"fep:pvatom_orig"); if (chgflag) { memory->create(q_orig,nmax,"fep:q_orig"); if (force->kspace) { memory->create(keatom_orig,nmax,"fep:keatom_orig"); memory->create(kvatom_orig,nmax,6,"fep:kvatom_orig"); } } } /* ---------------------------------------------------------------------- */ void ComputeFEP::deallocate_storage() { memory->destroy(f_orig); memory->destroy(peatom_orig); memory->destroy(pvatom_orig); memory->destroy(q_orig); memory->destroy(keatom_orig); memory->destroy(kvatom_orig); f_orig = NULL; q_orig = NULL; peatom_orig = keatom_orig = NULL; pvatom_orig = kvatom_orig = NULL; } /* ---------------------------------------------------------------------- backup and restore arrays with charge, force, energy, virial ------------------------------------------------------------------------- */ void ComputeFEP::backup_qfev() { int i; int nall = atom->nlocal + atom->nghost; int natom = atom->nlocal; if (force->newton || force->kspace->tip4pflag) natom += atom->nghost; double **f = atom->f; for (i = 0; i < natom; i++) { f_orig[i][0] = f[i][0]; f_orig[i][1] = f[i][1]; f_orig[i][2] = f[i][2]; } eng_vdwl_orig = force->pair->eng_vdwl; eng_coul_orig = force->pair->eng_coul; pvirial_orig[0] = force->pair->virial[0]; pvirial_orig[1] = force->pair->virial[1]; pvirial_orig[2] = force->pair->virial[2]; pvirial_orig[3] = force->pair->virial[3]; pvirial_orig[4] = force->pair->virial[4]; pvirial_orig[5] = force->pair->virial[5]; if (update->eflag_atom) { double *peatom = force->pair->eatom; for (i = 0; i < natom; i++) peatom_orig[i] = peatom[i]; } if (update->vflag_atom) { double **pvatom = force->pair->vatom; for (i = 0; i < natom; i++) { pvatom_orig[i][0] = pvatom[i][0]; pvatom_orig[i][1] = pvatom[i][1]; pvatom_orig[i][2] = pvatom[i][2]; pvatom_orig[i][3] = pvatom[i][3]; pvatom_orig[i][4] = pvatom[i][4]; pvatom_orig[i][5] = pvatom[i][5]; } } if (chgflag) { double *q = atom->q; for (i = 0; i < nall; i++) q_orig[i] = q[i]; if (force->kspace) { energy_orig = force->kspace->energy; kvirial_orig[0] = force->kspace->virial[0]; kvirial_orig[1] = force->kspace->virial[1]; kvirial_orig[2] = force->kspace->virial[2]; kvirial_orig[3] = force->kspace->virial[3]; kvirial_orig[4] = force->kspace->virial[4]; kvirial_orig[5] = force->kspace->virial[5]; if (update->eflag_atom) { double *keatom = force->kspace->eatom; for (i = 0; i < natom; i++) keatom_orig[i] = keatom[i]; } if (update->vflag_atom) { double **kvatom = force->kspace->vatom; for (i = 0; i < natom; i++) { kvatom_orig[i][0] = kvatom[i][0]; kvatom_orig[i][1] = kvatom[i][1]; kvatom_orig[i][2] = kvatom[i][2]; kvatom_orig[i][3] = kvatom[i][3]; kvatom_orig[i][4] = kvatom[i][4]; kvatom_orig[i][5] = kvatom[i][5]; } } } } } /* ---------------------------------------------------------------------- */ void ComputeFEP::restore_qfev() { int i; int nall = atom->nlocal + atom->nghost; int natom = atom->nlocal; if (force->newton || force->kspace->tip4pflag) natom += atom->nghost; double **f = atom->f; for (i = 0; i < natom; i++) { f[i][0] = f_orig[i][0]; f[i][1] = f_orig[i][1]; f[i][2] = f_orig[i][2]; } force->pair->eng_vdwl = eng_vdwl_orig; force->pair->eng_coul = eng_coul_orig; force->pair->virial[0] = pvirial_orig[0]; force->pair->virial[1] = pvirial_orig[1]; force->pair->virial[2] = pvirial_orig[2]; force->pair->virial[3] = pvirial_orig[3]; force->pair->virial[4] = pvirial_orig[4]; force->pair->virial[5] = pvirial_orig[5]; if (update->eflag_atom) { double *peatom = force->pair->eatom; for (i = 0; i < natom; i++) peatom[i] = peatom_orig[i]; } if (update->vflag_atom) { double **pvatom = force->pair->vatom; for (i = 0; i < natom; i++) { pvatom[i][0] = pvatom_orig[i][0]; pvatom[i][1] = pvatom_orig[i][1]; pvatom[i][2] = pvatom_orig[i][2]; pvatom[i][3] = pvatom_orig[i][3]; pvatom[i][4] = pvatom_orig[i][4]; pvatom[i][5] = pvatom_orig[i][5]; } } if (chgflag) { double *q = atom->q; for (i = 0; i < nall; i++) q[i] = q_orig[i]; if (force->kspace) { force->kspace->energy = energy_orig; force->kspace->virial[0] = kvirial_orig[0]; force->kspace->virial[1] = kvirial_orig[1]; force->kspace->virial[2] = kvirial_orig[2]; force->kspace->virial[3] = kvirial_orig[3]; force->kspace->virial[4] = kvirial_orig[4]; force->kspace->virial[5] = kvirial_orig[5]; if (update->eflag_atom) { double *keatom = force->kspace->eatom; for (i = 0; i < natom; i++) keatom[i] = keatom_orig[i]; } if (update->vflag_atom) { double **kvatom = force->kspace->vatom; for (i = 0; i < natom; i++) { kvatom[i][0] = kvatom_orig[i][0]; kvatom[i][1] = kvatom_orig[i][1]; kvatom[i][2] = kvatom_orig[i][2]; kvatom[i][3] = kvatom_orig[i][3]; kvatom[i][4] = kvatom_orig[i][4]; kvatom[i][5] = kvatom_orig[i][5]; } } } } } diff --git a/src/USER-FEP/fix_adapt_fep.cpp b/src/USER-FEP/fix_adapt_fep.cpp index 3e0e950cb..1b7fc5594 100644 --- a/src/USER-FEP/fix_adapt_fep.cpp +++ b/src/USER-FEP/fix_adapt_fep.cpp @@ -1,597 +1,597 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Charges by type and after option: Agilio Padua (Univ Blaise Pascal & CNRS) ------------------------------------------------------------------------- */ #include #include #include #include "fix_adapt_fep.h" #include "atom.h" #include "update.h" #include "group.h" #include "modify.h" #include "force.h" #include "pair.h" #include "pair_hybrid.h" #include "kspace.h" #include "fix_store.h" #include "input.h" #include "variable.h" #include "respa.h" #include "math_const.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace FixConst; using namespace MathConst; enum{PAIR,KSPACE,ATOM}; enum{DIAMETER,CHARGE}; /* ---------------------------------------------------------------------- */ FixAdaptFEP::FixAdaptFEP(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg) { if (narg < 5) error->all(FLERR,"Illegal fix adapt/fep command"); nevery = force->inumeric(FLERR,arg[3]); if (nevery < 0) error->all(FLERR,"Illegal fix adapt/fep command"); dynamic_group_allow = 1; create_attribute = 1; // count # of adaptations nadapt = 0; int iarg = 4; while (iarg < narg) { if (strcmp(arg[iarg],"pair") == 0) { if (iarg+6 > narg) error->all(FLERR,"Illegal fix adapt/fep command"); nadapt++; iarg += 6; } else if (strcmp(arg[iarg],"kspace") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal fix adapt/fep command"); nadapt++; iarg += 2; } else if (strcmp(arg[iarg],"atom") == 0) { if (iarg+4 > narg) error->all(FLERR,"Illegal fix adapt/fep command"); nadapt++; iarg += 4; } else break; } if (nadapt == 0) error->all(FLERR,"Illegal fix adapt/fep command"); adapt = new Adapt[nadapt]; // parse keywords nadapt = 0; diamflag = 0; chgflag = 0; iarg = 4; while (iarg < narg) { if (strcmp(arg[iarg],"pair") == 0) { if (iarg+6 > narg) error->all(FLERR,"Illegal fix adapt/fep command"); adapt[nadapt].which = PAIR; int n = strlen(arg[iarg+1]) + 1; adapt[nadapt].pstyle = new char[n]; strcpy(adapt[nadapt].pstyle,arg[iarg+1]); n = strlen(arg[iarg+2]) + 1; adapt[nadapt].pparam = new char[n]; strcpy(adapt[nadapt].pparam,arg[iarg+2]); - force->bounds(arg[iarg+3],atom->ntypes, + force->bounds(FLERR,arg[iarg+3],atom->ntypes, adapt[nadapt].ilo,adapt[nadapt].ihi); - force->bounds(arg[iarg+4],atom->ntypes, + force->bounds(FLERR,arg[iarg+4],atom->ntypes, adapt[nadapt].jlo,adapt[nadapt].jhi); if (strstr(arg[iarg+5],"v_") == arg[iarg+5]) { n = strlen(&arg[iarg+5][2]) + 1; adapt[nadapt].var = new char[n]; strcpy(adapt[nadapt].var,&arg[iarg+5][2]); } else error->all(FLERR,"Illegal fix adapt/fep command"); nadapt++; iarg += 6; } else if (strcmp(arg[iarg],"kspace") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal fix adapt/fep command"); adapt[nadapt].which = KSPACE; if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) { int n = strlen(&arg[iarg+1][2]) + 1; adapt[nadapt].var = new char[n]; strcpy(adapt[nadapt].var,&arg[iarg+1][2]); } else error->all(FLERR,"Illegal fix adapt/fep command"); nadapt++; iarg += 2; } else if (strcmp(arg[iarg],"atom") == 0) { if (iarg+3 > narg) error->all(FLERR,"Illegal fix adapt/fep command"); adapt[nadapt].which = ATOM; if (strcmp(arg[iarg+1],"diameter") == 0) { adapt[nadapt].aparam = DIAMETER; diamflag = 1; } else if (strcmp(arg[iarg+1],"charge") == 0) { adapt[nadapt].aparam = CHARGE; chgflag = 1; } else error->all(FLERR,"Illegal fix adapt/fep command"); - force->bounds(arg[iarg+2],atom->ntypes, + force->bounds(FLERR,arg[iarg+2],atom->ntypes, adapt[nadapt].ilo,adapt[nadapt].ihi); if (strstr(arg[iarg+3],"v_") == arg[iarg+3]) { int n = strlen(&arg[iarg+3][2]) + 1; adapt[nadapt].var = new char[n]; strcpy(adapt[nadapt].var,&arg[iarg+3][2]); } else error->all(FLERR,"Illegal fix adapt/fep command"); nadapt++; iarg += 4; } else break; } // optional keywords resetflag = 0; scaleflag = 0; afterflag = 0; while (iarg < narg) { if (strcmp(arg[iarg],"reset") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal fix adapt/fep command"); if (strcmp(arg[iarg+1],"no") == 0) resetflag = 0; else if (strcmp(arg[iarg+1],"yes") == 0) resetflag = 1; else error->all(FLERR,"Illegal fix adapt/fep command"); iarg += 2; } else if (strcmp(arg[iarg],"scale") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal fix adapt/fep command"); if (strcmp(arg[iarg+1],"no") == 0) scaleflag = 0; else if (strcmp(arg[iarg+1],"yes") == 0) scaleflag = 1; else error->all(FLERR,"Illegal fix adapt/fep command"); iarg += 2; } else if (strcmp(arg[iarg],"after") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal fix adapt/fep command"); if (strcmp(arg[iarg+1],"no") == 0) afterflag = 0; else if (strcmp(arg[iarg+1],"yes") == 0) afterflag = 1; else error->all(FLERR,"Illegal fix adapt/fep command"); iarg += 2; } else error->all(FLERR,"Illegal fix adapt/fep command"); } // allocate pair style arrays int n = atom->ntypes; for (int m = 0; m < nadapt; m++) if (adapt[m].which == PAIR) memory->create(adapt[m].array_orig,n+1,n+1,"adapt:array_orig"); id_fix_diam = id_fix_chg = NULL; } /* ---------------------------------------------------------------------- */ FixAdaptFEP::~FixAdaptFEP() { for (int m = 0; m < nadapt; m++) { delete [] adapt[m].var; if (adapt[m].which == PAIR) { delete [] adapt[m].pstyle; delete [] adapt[m].pparam; memory->destroy(adapt[m].array_orig); } } delete [] adapt; // check nfix in case all fixes have already been deleted if (id_fix_diam && modify->nfix) modify->delete_fix(id_fix_diam); if (id_fix_chg && modify->nfix) modify->delete_fix(id_fix_chg); delete [] id_fix_diam; delete [] id_fix_chg; } /* ---------------------------------------------------------------------- */ int FixAdaptFEP::setmask() { int mask = 0; mask |= PRE_FORCE; mask |= POST_RUN; mask |= PRE_FORCE_RESPA; return mask; } /* ---------------------------------------------------------------------- if need to restore per-atom quantities, create new fix STORE styles ------------------------------------------------------------------------- */ void FixAdaptFEP::post_constructor() { if (!resetflag) return; if (!diamflag && !chgflag) return; // new id = fix-ID + FIX_STORE_ATTRIBUTE // new fix group = group for this fix id_fix_diam = NULL; id_fix_chg = NULL; char **newarg = new char*[6]; newarg[1] = group->names[igroup]; newarg[2] = (char *) "STORE"; newarg[3] = (char *) "peratom"; newarg[4] = (char *) "1"; newarg[5] = (char *) "1"; if (diamflag) { int n = strlen(id) + strlen("_FIX_STORE_DIAM") + 1; id_fix_diam = new char[n]; strcpy(id_fix_diam,id); strcat(id_fix_diam,"_FIX_STORE_DIAM"); newarg[0] = id_fix_diam; modify->add_fix(6,newarg); fix_diam = (FixStore *) modify->fix[modify->nfix-1]; if (fix_diam->restart_reset) fix_diam->restart_reset = 0; else { double *vec = fix_diam->vstore; double *radius = atom->radius; int *mask = atom->mask; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) vec[i] = radius[i]; else vec[i] = 0.0; } } } if (chgflag) { int n = strlen(id) + strlen("_FIX_STORE_CHG") + 1; id_fix_chg = new char[n]; strcpy(id_fix_chg,id); strcat(id_fix_chg,"_FIX_STORE_CHG"); newarg[0] = id_fix_chg; modify->add_fix(6,newarg); fix_chg = (FixStore *) modify->fix[modify->nfix-1]; if (fix_chg->restart_reset) fix_chg->restart_reset = 0; else { double *vec = fix_chg->vstore; double *q = atom->q; int *mask = atom->mask; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) vec[i] = q[i]; else vec[i] = 0.0; } } } delete [] newarg; } /* ---------------------------------------------------------------------- */ void FixAdaptFEP::init() { int i,j; // allow a dynamic group only if ATOM attribute not used if (group->dynamic[igroup]) for (int i = 0; i < nadapt; i++) if (adapt[i].which == ATOM) error->all(FLERR,"Cannot use dynamic group with fix adapt/fep atom"); // setup and error checks anypair = 0; for (int m = 0; m < nadapt; m++) { Adapt *ad = &adapt[m]; ad->ivar = input->variable->find(ad->var); if (ad->ivar < 0) error->all(FLERR,"Variable name for fix adapt/fep does not exist"); if (!input->variable->equalstyle(ad->ivar)) error->all(FLERR,"Variable for fix adapt/fep is invalid style"); if (ad->which == PAIR) { anypair = 1; Pair *pair = NULL; if (lmp->suffix_enable) { char psuffix[128]; strcpy(psuffix,ad->pstyle); strcat(psuffix,"/"); strcat(psuffix,lmp->suffix); pair = force->pair_match(psuffix,1); } if (pair == NULL) pair = force->pair_match(ad->pstyle,1); if (pair == NULL) error->all(FLERR, "Fix adapt/fep pair style does not exist"); void *ptr = pair->extract(ad->pparam,ad->pdim); if (ptr == NULL) error->all(FLERR,"Fix adapt/fep pair style param not supported"); ad->pdim = 2; if (ad->pdim == 0) ad->scalar = (double *) ptr; if (ad->pdim == 2) ad->array = (double **) ptr; // if pair hybrid, test that ilo,ihi,jlo,jhi are valid for sub-style if (ad->pdim == 2 && (strcmp(force->pair_style,"hybrid") == 0 || strcmp(force->pair_style,"hybrid/overlay") == 0)) { PairHybrid *pair = (PairHybrid *) force->pair; for (i = ad->ilo; i <= ad->ihi; i++) for (j = MAX(ad->jlo,i); j <= ad->jhi; j++) if (!pair->check_ijtype(i,j,ad->pstyle)) error->all(FLERR,"Fix adapt/fep type pair range is not valid for " "pair hybrid sub-style"); } } else if (ad->which == KSPACE) { if (force->kspace == NULL) error->all(FLERR,"Fix adapt/fep kspace style does not exist"); kspace_scale = (double *) force->kspace->extract("scale"); } else if (ad->which == ATOM) { if (ad->aparam == DIAMETER) { if (!atom->radius_flag) error->all(FLERR,"Fix adapt/fep requires atom attribute diameter"); } if (ad->aparam == CHARGE) { if (!atom->q_flag) error->all(FLERR,"Fix adapt/fep requires atom attribute charge"); } } } // make copy of original pair array values for (int m = 0; m < nadapt; m++) { Adapt *ad = &adapt[m]; if (ad->which == PAIR && ad->pdim == 2) { for (i = ad->ilo; i <= ad->ihi; i++) for (j = MAX(ad->jlo,i); j <= ad->jhi; j++) ad->array_orig[i][j] = ad->array[i][j]; } } // fixes that store initial per-atom values if (id_fix_diam) { int ifix = modify->find_fix(id_fix_diam); if (ifix < 0) error->all(FLERR,"Could not find fix adapt storage fix ID"); fix_diam = (FixStore *) modify->fix[ifix]; } if (id_fix_chg) { int ifix = modify->find_fix(id_fix_chg); if (ifix < 0) error->all(FLERR,"Could not find fix adapt storage fix ID"); fix_chg = (FixStore *) modify->fix[ifix]; } if (strstr(update->integrate_style,"respa")) nlevels_respa = ((Respa *) update->integrate)->nlevels; } /* ---------------------------------------------------------------------- */ void FixAdaptFEP::setup_pre_force(int vflag) { change_settings(); } /* ---------------------------------------------------------------------- */ void FixAdaptFEP::setup_pre_force_respa(int vflag, int ilevel) { if (ilevel < nlevels_respa-1) return; setup_pre_force(vflag); } /* ---------------------------------------------------------------------- */ void FixAdaptFEP::pre_force(int vflag) { if (nevery == 0) return; if (afterflag) { // update at n+1 (better with fix ave/time) if (nevery == 1 || update->ntimestep == 0) change_settings(); else if (update->ntimestep > 1 && !((update->ntimestep - 1) % nevery)) change_settings(); } else { // original version: update at n if (update->ntimestep % nevery) return; change_settings(); } } /* ---------------------------------------------------------------------- */ void FixAdaptFEP::pre_force_respa(int vflag, int ilevel, int) { if (ilevel < nlevels_respa-1) return; pre_force(vflag); } /* ---------------------------------------------------------------------- */ void FixAdaptFEP::post_run() { if (resetflag) restore_settings(); } /* ---------------------------------------------------------------------- change pair,kspace,atom parameters based on variable evaluation ------------------------------------------------------------------------- */ void FixAdaptFEP::change_settings() { int i,j; // variable evaluation may invoke computes so wrap with clear/add modify->clearstep_compute(); for (int m = 0; m < nadapt; m++) { Adapt *ad = &adapt[m]; double value = input->variable->compute_equal(ad->ivar); // set global scalar or type pair array values if (ad->which == PAIR) { if (ad->pdim == 0) { if (scaleflag) *ad->scalar = value * ad->scalar_orig; else *ad->scalar = value; } else if (ad->pdim == 2) { if (scaleflag) for (i = ad->ilo; i <= ad->ihi; i++) for (j = MAX(ad->jlo,i); j <= ad->jhi; j++) ad->array[i][j] = value*ad->array_orig[i][j]; else for (i = ad->ilo; i <= ad->ihi; i++) for (j = MAX(ad->jlo,i); j <= ad->jhi; j++) ad->array[i][j] = value; } // set kspace scale factor } else if (ad->which == KSPACE) { *kspace_scale = value; // set per atom values, also make changes for ghost atoms } else if (ad->which == ATOM) { // reset radius from diameter // also scale rmass to new value if (ad->aparam == DIAMETER) { int mflag = 0; if (atom->rmass_flag) mflag = 1; double density; int *atype = atom->type; double *radius = atom->radius; double *rmass = atom->rmass; int *mask = atom->mask; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; if (mflag == 0) { for (i = 0; i < nall; i++) if (atype[i] >= ad->ilo && atype[i] <= ad->ihi) if (mask[i] & groupbit) radius[i] = 0.5*value; } else { for (i = 0; i < nall; i++) if (atype[i] >= ad->ilo && atype[i] <= ad->ihi) if (mask[i] & groupbit) { density = rmass[i] / (4.0*MY_PI/3.0 * radius[i]*radius[i]*radius[i]); radius[i] = 0.5*value; rmass[i] = 4.0*MY_PI/3.0 * radius[i]*radius[i]*radius[i] * density; } } } else if (ad->aparam == CHARGE) { int *atype = atom->type; double *q = atom->q; int *mask = atom->mask; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; for (i = 0; i < nall; i++) if (atype[i] >= ad->ilo && atype[i] <= ad->ihi) if (mask[i] & groupbit) q[i] = value; } } } modify->addstep_compute(update->ntimestep + nevery); // re-initialize pair styles if any PAIR settings were changed // this resets other coeffs that may depend on changed values, // and also offset and tail corrections if (anypair) force->pair->reinit(); // reset KSpace charges if charges have changed if (chgflag && force->kspace) force->kspace->qsum_qsq(); } /* ---------------------------------------------------------------------- restore pair,kspace.atom parameters to original values ------------------------------------------------------------------------- */ void FixAdaptFEP::restore_settings() { for (int m = 0; m < nadapt; m++) { Adapt *ad = &adapt[m]; if (ad->which == PAIR) { if (ad->pdim == 0) *ad->scalar = ad->scalar_orig; else if (ad->pdim == 2) { for (int i = ad->ilo; i <= ad->ihi; i++) for (int j = MAX(ad->jlo,i); j <= ad->jhi; j++) ad->array[i][j] = ad->array_orig[i][j]; } } else if (ad->which == KSPACE) { *kspace_scale = 1.0; } else if (ad->which == ATOM) { if (diamflag) { double density; double *vec = fix_diam->vstore; double *radius = atom->radius; double *rmass = atom->rmass; int *mask = atom->mask; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { density = rmass[i] / (4.0*MY_PI/3.0 * radius[i]*radius[i]*radius[i]); radius[i] = vec[i]; rmass[i] = 4.0*MY_PI/3.0 * radius[i]*radius[i]*radius[i] * density; } } if (chgflag) { double *vec = fix_chg->vstore; double *q = atom->q; int *mask = atom->mask; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) q[i] = vec[i]; } } } if (anypair) force->pair->reinit(); if (chgflag && force->kspace) force->kspace->qsum_qsq(); } /* ---------------------------------------------------------------------- initialize one atom's storage values, called when atom is created ------------------------------------------------------------------------- */ void FixAdaptFEP::set_arrays(int i) { if (fix_diam) fix_diam->vstore[i] = atom->radius[i]; if (fix_chg) fix_chg->vstore[i] = atom->q[i]; } diff --git a/src/USER-FEP/pair_coul_cut_soft.cpp b/src/USER-FEP/pair_coul_cut_soft.cpp index b82abc1ed..2c675c607 100644 --- a/src/USER-FEP/pair_coul_cut_soft.cpp +++ b/src/USER-FEP/pair_coul_cut_soft.cpp @@ -1,376 +1,376 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Soft-core version: Agilio Padua (Univ Blaise Pascal & CNRS) ------------------------------------------------------------------------- */ #include #include #include #include #include "pair_coul_cut_soft.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; /* ---------------------------------------------------------------------- */ PairCoulCutSoft::PairCoulCutSoft(LAMMPS *lmp) : Pair(lmp) {} /* ---------------------------------------------------------------------- */ PairCoulCutSoft::~PairCoulCutSoft() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut); memory->destroy(lambda); memory->destroy(lam1); memory->destroy(lam2); } } /* ---------------------------------------------------------------------- */ void PairCoulCutSoft::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,forcecoul,factor_coul; double denc; 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]) { denc = sqrt(lam2[itype][jtype] + rsq); forcecoul = qqrd2e * lam1[itype][jtype] * qtmp*q[j] / (denc*denc*denc); fpair = factor_coul*forcecoul; 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 * lam1[itype][jtype] * qtmp*q[j] / denc; 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 PairCoulCutSoft::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(lambda,n+1,n+1,"pair:lambda"); memory->create(lam1,n+1,n+1,"pair:lam1"); memory->create(lam2,n+1,n+1,"pair:lam2"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairCoulCutSoft::settings(int narg, char **arg) { if (narg != 3) error->all(FLERR,"Illegal pair_style command"); nlambda = force->numeric(FLERR,arg[0]); alphac = force->numeric(FLERR,arg[1]); cut_global = force->numeric(FLERR,arg[2]); // 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 PairCoulCutSoft::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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double lambda_one = force->numeric(FLERR,arg[2]); double cut_one = cut_global; if (narg == 4) cut_one = force->numeric(FLERR,arg[3]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { lambda[i][j] = lambda_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 PairCoulCutSoft::init_style() { if (!atom->q_flag) error->all(FLERR,"Pair style coul/cut/soft requires atom attribute q"); neighbor->request(this,instance_me); } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairCoulCutSoft::init_one(int i, int j) { if (setflag[i][j] == 0) { if (lambda[i][i] != lambda[j][j]) error->all(FLERR,"Pair coul/cut/soft different lambda values in mix"); lambda[i][j] = lambda[i][i]; cut[i][j] = mix_distance(cut[i][i],cut[j][j]); } lam1[i][j] = pow(lambda[i][j], nlambda); lam2[i][j] = alphac * (1.0 - lambda[i][j])*(1.0 - lambda[i][j]); cut[j][i] = cut[i][j]; lambda[j][i] = lambda[i][j]; lam1[j][i] = lam1[i][j]; lam2[j][i] = lam2[i][j]; return cut[i][j]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairCoulCutSoft::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(&lambda[i][j],sizeof(double),1,fp); fwrite(&cut[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairCoulCutSoft::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(&lambda[i][j],sizeof(double),1,fp); fread(&cut[i][j],sizeof(double),1,fp); } MPI_Bcast(&lambda[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairCoulCutSoft::write_restart_settings(FILE *fp) { fwrite(&nlambda,sizeof(double),1,fp); fwrite(&alphac,sizeof(double),1,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 PairCoulCutSoft::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&nlambda,sizeof(double),1,fp); fread(&alphac,sizeof(double),1,fp); fread(&cut_global,sizeof(double),1,fp); fread(&offset_flag,sizeof(int),1,fp); fread(&mix_flag,sizeof(int),1,fp); } MPI_Bcast(&nlambda,1,MPI_DOUBLE,0,world); MPI_Bcast(&alphac,1,MPI_DOUBLE,0,world); 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); } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void PairCoulCutSoft::write_data(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) fprintf(fp,"%d %g\n",i,lambda[i][i]); } /* ---------------------------------------------------------------------- proc 0 writes all pairs to data file ------------------------------------------------------------------------- */ void PairCoulCutSoft::write_data_all(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) fprintf(fp,"%d %d %g\n",i,j,lambda[i][j]); } /* ---------------------------------------------------------------------- */ double PairCoulCutSoft::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double forcecoul,phicoul; double denc; if (rsq < cutsq[itype][jtype]) { denc = sqrt(lam2[itype][jtype] + rsq); forcecoul = force->qqrd2e * lam1[itype][jtype] * atom->q[i]*atom->q[j] / (denc*denc*denc); } else forcecoul = 0.0; fforce = factor_coul*forcecoul; if (rsq < cutsq[itype][jtype]) phicoul = force->qqrd2e * lam1[itype][jtype] * atom->q[i]*atom->q[j] / denc; else phicoul = 0.0; return factor_coul*phicoul; } /* ---------------------------------------------------------------------- */ void *PairCoulCutSoft::extract(const char *str, int &dim) { dim = 2; if (strcmp(str,"lambda") == 0) return (void *) lambda; return NULL; } diff --git a/src/USER-FEP/pair_coul_long_soft.cpp b/src/USER-FEP/pair_coul_long_soft.cpp index d20962810..3d24a997d 100644 --- a/src/USER-FEP/pair_coul_long_soft.cpp +++ b/src/USER-FEP/pair_coul_long_soft.cpp @@ -1,395 +1,395 @@ /* ---------------------------------------------------------------------- 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) Soft-core version: Agilio Padua (Univ Blaise Pascal & CNRS) ------------------------------------------------------------------------- */ #include #include #include #include #include "pair_coul_long_soft.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 "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 /* ---------------------------------------------------------------------- */ PairCoulLongSoft::PairCoulLongSoft(LAMMPS *lmp) : Pair(lmp) { ewaldflag = pppmflag = 1; qdist = 0.0; } /* ---------------------------------------------------------------------- */ PairCoulLongSoft::~PairCoulLongSoft() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(scale); memory->destroy(lambda); memory->destroy(lam1); memory->destroy(lam2); } } /* ---------------------------------------------------------------------- */ void PairCoulLongSoft::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 r,rsq,forcecoul,factor_coul; double grij,expm2,prefactor,t,erfc; double denc; 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 < 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; denc = sqrt(lam2[itype][jtype] + rsq); prefactor = qqrd2e * lam1[itype][jtype] * qtmp*q[j] / (denc*denc*denc); forcecoul = prefactor * (erfc + EWALD_F*grij*expm2); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor; fpair = forcecoul; 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) { prefactor = qqrd2e * lam1[itype][jtype] * qtmp*q[j] / denc; ecoul = prefactor*erfc; 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 PairCoulLongSoft::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"); memory->create(lambda,n+1,n+1,"pair:lambda"); memory->create(lam1,n+1,n+1,"pair:lam1"); memory->create(lam2,n+1,n+1,"pair:lam2"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairCoulLongSoft::settings(int narg, char **arg) { if (narg != 3) error->all(FLERR,"Illegal pair_style command"); nlambda = force->numeric(FLERR,arg[0]); alphac = force->numeric(FLERR,arg[1]); cut_coul = force->numeric(FLERR,arg[2]); } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairCoulLongSoft::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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double lambda_one = force->numeric(FLERR,arg[2]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { lambda[i][j] = lambda_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 PairCoulLongSoft::init_style() { if (!atom->q_flag) error->all(FLERR,"Pair style lj/cut/coul/long requires atom attribute q"); neighbor->request(this,instance_me); 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 requires a KSpace style"); g_ewald = force->kspace->g_ewald; } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairCoulLongSoft::init_one(int i, int j) { if (setflag[i][j] == 0) { if (lambda[i][i] != lambda[j][j]) error->all(FLERR,"Pair coul/cut/soft different lambda values in mix"); lambda[i][j] = lambda[i][i]; } lam1[i][j] = pow(lambda[i][j], nlambda); lam2[i][j] = alphac * (1.0 - lambda[i][j])*(1.0 - lambda[i][j]); scale[j][i] = scale[i][j]; lambda[j][i] = lambda[i][j]; lam1[j][i] = lam1[i][j]; lam2[j][i] = lam2[i][j]; return cut_coul+2.0*qdist; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairCoulLongSoft::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(&lambda[i][j],sizeof(double),1,fp); } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairCoulLongSoft::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(&lambda[i][j],sizeof(double),1,fp); MPI_Bcast(&lambda[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairCoulLongSoft::write_restart_settings(FILE *fp) { fwrite(&nlambda,sizeof(double),1,fp); fwrite(&alphac,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 PairCoulLongSoft::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&nlambda,sizeof(double),1,fp); fread(&alphac,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(&nlambda,1,MPI_DOUBLE,0,world); MPI_Bcast(&alphac,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 PairCoulLongSoft::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r,grij,expm2,t,erfc,prefactor; double forcecoul,phicoul; double denc; 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; denc = sqrt(lam2[itype][jtype] + rsq); prefactor = force->qqrd2e * lam1[itype][jtype] * atom->q[i]*atom->q[j] / (denc*denc*denc); forcecoul = prefactor * (erfc + EWALD_F*grij*expm2); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor; } else forcecoul = 0.0; fforce = forcecoul; if (rsq < cut_coulsq) { prefactor = force->qqrd2e * lam1[itype][jtype] * atom->q[i]*atom->q[j] / denc; phicoul = prefactor*erfc; if (factor_coul < 1.0) phicoul -= (1.0-factor_coul)*prefactor; } else phicoul = 0.0; return phicoul; } /* ---------------------------------------------------------------------- */ void *PairCoulLongSoft::extract(const char *str, int &dim) { dim = 0; if (strcmp(str,"cut_coul") == 0) return (void *) &cut_coul; dim = 2; if (strcmp(str,"scale") == 0) return (void *) scale; if (strcmp(str,"lambda") == 0) return (void *) lambda; return NULL; } diff --git a/src/USER-FEP/pair_lj_charmm_coul_long_soft.cpp b/src/USER-FEP/pair_lj_charmm_coul_long_soft.cpp index d2a9a04ba..81b82e977 100644 --- a/src/USER-FEP/pair_lj_charmm_coul_long_soft.cpp +++ b/src/USER-FEP/pair_lj_charmm_coul_long_soft.cpp @@ -1,1028 +1,1028 @@ /* ---------------------------------------------------------------------- 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) Soft-core version: Agilio Padua (Univ Blaise Pascal & CNRS) ------------------------------------------------------------------------- */ #include #include #include #include #include "pair_lj_charmm_coul_long_soft.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; #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 /* ---------------------------------------------------------------------- */ PairLJCharmmCoulLongSoft::PairLJCharmmCoulLongSoft(LAMMPS *lmp) : Pair(lmp) { respa_enable = 1; ewaldflag = pppmflag = 1; implicit = 0; mix_flag = ARITHMETIC; writedata = 1; } /* ---------------------------------------------------------------------- */ PairLJCharmmCoulLongSoft::~PairLJCharmmCoulLongSoft() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(epsilon); memory->destroy(sigma); memory->destroy(lambda); 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 PairLJCharmmCoulLongSoft::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 r,rsq,forcecoul,forcelj,factor_coul,factor_lj; double grij,expm2,prefactor,t,erfc; double philj,switch1,switch2; double denc, denlj, r4sig6; 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 < cut_bothsq) { 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; denc = sqrt(lj4[itype][jtype] + rsq); prefactor = qqrd2e * lj1[itype][jtype] * qtmp*q[j] / (denc*denc*denc); 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) { r4sig6 = rsq*rsq / lj2[itype][jtype]; denlj = lj3[itype][jtype] + rsq*r4sig6; forcelj = lj1[itype][jtype] * epsilon[itype][jtype] * (48.0*r4sig6/(denlj*denlj*denlj) - 24.0*r4sig6/(denlj*denlj)); 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 * (cut_ljsq-rsq) * (rsq-cut_lj_innersq) / denom_lj; philj = lj1[itype][jtype] * 4.0 * epsilon[itype][jtype] * (1.0/(denlj*denlj) - 1.0/denlj); forcelj = forcelj*switch1 + philj*switch2; } } else forcelj = 0.0; fpair = forcecoul + factor_lj*forcelj; 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) { prefactor = qqrd2e * lj1[itype][jtype] * qtmp*q[j] / denc; ecoul = prefactor*erfc; if (factor_coul < 1.0) ecoul -= (1.0-factor_coul)*prefactor; } else ecoul = 0.0; if (rsq < cut_ljsq) { evdwl = lj1[itype][jtype] * 4.0 * epsilon[itype][jtype] * (1.0/(denlj*denlj) - 1.0/denlj); 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 PairLJCharmmCoulLongSoft::compute_inner() { int i,j,ii,jj,inum,jnum,itype,jtype; double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,fpair; double rsq,forcecoul,forcelj,factor_coul,factor_lj; double rsw; double denc, denlj, r4sig6; 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) { jtype = type[j]; denc = sqrt(lj4[itype][jtype] + rsq); forcecoul = qqrd2e * lj1[itype][jtype] * qtmp*q[j] / (denc*denc*denc); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*forcecoul; r4sig6 = rsq*rsq / lj2[itype][jtype]; denlj = lj3[itype][jtype] + rsq*r4sig6; forcelj = lj1[itype][jtype] * epsilon[itype][jtype] * (48.0*r4sig6/(denlj*denlj*denlj) - 24.0*r4sig6/(denlj*denlj)); fpair = forcecoul + factor_lj*forcelj; 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 PairLJCharmmCoulLongSoft::compute_middle() { int i,j,ii,jj,inum,jnum,itype,jtype; double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,fpair; double rsq,forcecoul,forcelj,factor_coul,factor_lj; double philj,switch1,switch2; double rsw; double denc, denlj, r4sig6; 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) { jtype = type[j]; denc = sqrt(lj4[itype][jtype] + rsq); forcecoul = qqrd2e * lj1[itype][jtype] * qtmp*q[j] / (denc*denc*denc); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*forcecoul; r4sig6 = rsq*rsq / lj2[itype][jtype]; denlj = lj3[itype][jtype] + rsq*r4sig6; forcelj = lj1[itype][jtype] * epsilon[itype][jtype] * (48.0*r4sig6/(denlj*denlj*denlj) - 24.0*r4sig6/(denlj*denlj)); 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 * (cut_ljsq-rsq) * (rsq-cut_lj_innersq) / denom_lj; philj = lj1[itype][jtype] * 4.0 * epsilon[itype][jtype] * (1.0/(denlj*denlj) - 1.0/denlj); forcelj = forcelj*switch1 + philj*switch2; } fpair = forcecoul + factor_lj*forcelj; 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 PairLJCharmmCoulLongSoft::compute_outer(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 r,rsq,forcecoul,forcelj,factor_coul,factor_lj; double grij,expm2,fprefactor,eprefactor,t,erfc; double philj,switch1,switch2; double rsw; double denc, denlj, r4sig6; int *ilist,*jlist,*numneigh,**firstneigh; 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; if (rsq < cut_bothsq) { jtype = type[j]; 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; denc = sqrt(lj4[itype][jtype] + rsq); fprefactor = qqrd2e * lj1[itype][jtype] * qtmp*q[j] / (denc*denc*denc); forcecoul = fprefactor * (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 += fprefactor*rsw*rsw*(3.0 - 2.0*rsw); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*fprefactor*rsw*rsw*(3.0 - 2.0*rsw); } else { forcecoul += fprefactor; if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*fprefactor; } } } else forcecoul = 0.0; if (rsq < cut_ljsq && rsq > cut_in_off_sq) { r4sig6 = rsq*rsq / lj2[itype][jtype]; denlj = lj3[itype][jtype] + rsq*r4sig6; forcelj = lj1[itype][jtype] * epsilon[itype][jtype] * (48.0*r4sig6/(denlj*denlj*denlj) - 24.0*r4sig6/(denlj*denlj)); 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 * (cut_ljsq-rsq) * (rsq-cut_lj_innersq) / denom_lj; philj = lj1[itype][jtype] * 4.0 * epsilon[itype][jtype] * (1.0/(denlj*denlj) - 1.0/denlj); 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; 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) { eprefactor = qqrd2e * lj1[itype][jtype] * qtmp*q[j] / denc; ecoul = eprefactor*erfc; if (factor_coul < 1.0) ecoul -= (1.0-factor_coul)*eprefactor; } else ecoul = 0.0; if (rsq < cut_ljsq) { r4sig6 = rsq*rsq / lj2[itype][jtype]; denlj = lj3[itype][jtype] + rsq*r4sig6; evdwl = lj1[itype][jtype] * 4.0 * epsilon[itype][jtype] * (1.0/(denlj*denlj) - 1.0/denlj); 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) { forcecoul = fprefactor * (erfc + EWALD_F*grij*expm2); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*fprefactor; } else forcecoul = 0.0; if (rsq <= cut_in_off_sq) { r4sig6 = rsq*rsq / lj2[itype][jtype]; denlj = lj3[itype][jtype] + rsq*r4sig6; forcelj = lj1[itype][jtype] * epsilon[itype][jtype] * (48.0*r4sig6/(denlj*denlj*denlj) - 24.0*r4sig6/(denlj*denlj)); 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 * (cut_ljsq-rsq) * (rsq-cut_lj_innersq) / denom_lj; philj = lj1[itype][jtype] * 4.0 * epsilon[itype][jtype] * (1.0/(denlj*denlj) - 1.0/denlj); forcelj = forcelj*switch1 + philj*switch2; } } else if (rsq <= cut_in_on_sq) { r4sig6 = rsq*rsq / lj2[itype][jtype]; denlj = lj3[itype][jtype] + rsq*r4sig6; forcelj = lj1[itype][jtype] * epsilon[itype][jtype] * (48.0*r4sig6/(denlj*denlj*denlj) - 24.0*r4sig6/(denlj*denlj)); 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 * (cut_ljsq-rsq) * (rsq-cut_lj_innersq) / denom_lj; philj = lj1[itype][jtype] * 4.0 * epsilon[itype][jtype] * (1.0/(denlj*denlj) - 1.0/denlj); forcelj = forcelj*switch1 + philj*switch2; } } fpair = forcecoul + factor_lj*forcelj; } if (evflag) ev_tally(i,j,nlocal,newton_pair, evdwl,ecoul,fpair,delx,dely,delz); } } } } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairLJCharmmCoulLongSoft::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(lambda,n+1,n+1,"pair:lambda"); 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 PairLJCharmmCoulLongSoft::settings(int narg, char **arg) { if (narg != 5 && narg != 6) error->all(FLERR,"Illegal pair_style command"); nlambda = force->numeric(FLERR,arg[0]); alphalj = force->numeric(FLERR,arg[1]); alphac = force->numeric(FLERR,arg[2]); cut_lj_inner = force->numeric(FLERR,arg[3]); cut_lj = force->numeric(FLERR,arg[4]); if (narg == 5) cut_coul = cut_lj; else cut_coul = force->numeric(FLERR,arg[5]); } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairLJCharmmCoulLongSoft::coeff(int narg, char **arg) { if (narg != 5 && narg != 7) 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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(FLERR,arg[2]); double sigma_one = force->numeric(FLERR,arg[3]); double lambda_one = force->numeric(FLERR,arg[4]); double eps14_one = epsilon_one; double sigma14_one = sigma_one; if (narg == 7) { eps14_one = force->numeric(FLERR,arg[5]); sigma14_one = force->numeric(FLERR,arg[6]); } 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; lambda[i][j] = lambda_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 PairLJCharmmCoulLongSoft::init_style() { if (!atom->q_flag) error->all(FLERR, "Pair style lj/charmm/coul/long/soft 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,instance_me); else if (respa == 1) { irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respainner = 1; irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 3; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respaouter = 1; } else { irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respainner = 1; irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 2; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respamiddle = 1; irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 3; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respaouter = 1; } } else irequest = neighbor->request(this,instance_me); // 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 requires a KSpace style"); g_ewald = force->kspace->g_ewald; } /* ---------------------------------------------------------------------- neighbor callback to inform pair style of neighbor list to use regular or rRESPA ------------------------------------------------------------------------- */ void PairLJCharmmCoulLongSoft::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 PairLJCharmmCoulLongSoft::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]); if (lambda[i][i] != lambda[j][j]) error->all(FLERR,"Pair lj/charmm/coul/long/soft different lambda values in mix"); lambda[i][j] = lambda[i][i]; 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] = pow(lambda[i][j], nlambda); lj2[i][j] = pow(sigma[i][j], 6.0); lj3[i][j] = alphalj * (1.0 - lambda[i][j])*(1.0 - lambda[i][j]); lj4[i][j] = alphac * (1.0 - lambda[i][j])*(1.0 - lambda[i][j]); // 1-4 interactions unaffected (they're part of the dihedral term) 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); epsilon[j][i] = epsilon[i][j]; sigma[j][i] = sigma[i][j]; lambda[j][i] = lambda[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]; 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 PairLJCharmmCoulLongSoft::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(&lambda[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 PairLJCharmmCoulLongSoft::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(&lambda[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(&lambda[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 PairLJCharmmCoulLongSoft::write_restart_settings(FILE *fp) { fwrite(&nlambda,sizeof(double),1,fp); fwrite(&alphalj,sizeof(double),1,fp); fwrite(&alphac,sizeof(double),1,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 PairLJCharmmCoulLongSoft::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&nlambda,sizeof(double),1,fp); fread(&alphalj,sizeof(double),1,fp); fread(&alphac,sizeof(double),1,fp); 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(&nlambda,1,MPI_DOUBLE,0,world); MPI_Bcast(&alphalj,1,MPI_DOUBLE,0,world); MPI_Bcast(&alphac,1,MPI_DOUBLE,0,world); 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); } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void PairLJCharmmCoulLongSoft::write_data(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) fprintf(fp,"%d %g %g %g %g %g\n",i,epsilon[i][i],sigma[i][i], lambda[i][i],eps14[i][i],sigma14[i][i]); } /* ---------------------------------------------------------------------- proc 0 writes all pairs to data file ------------------------------------------------------------------------- */ void PairLJCharmmCoulLongSoft::write_data_all(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) fprintf(fp,"%d %d %g %g %g %g %g\n",i,j,epsilon[i][j],sigma[i][j], lambda[i][j],eps14[i][j],sigma14[i][j]); } /* ---------------------------------------------------------------------- */ double PairLJCharmmCoulLongSoft::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r,grij,expm2,t,erfc,prefactor; double switch1,switch2,forcecoul,forcelj,phicoul,philj; double denc, denlj, r4sig6; 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; denc = sqrt(lj4[itype][jtype] + rsq); prefactor = force->qqrd2e * lj1[itype][jtype] * atom->q[i]*atom->q[j] / (denc*denc*denc); 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) { r4sig6 = rsq*rsq / lj2[itype][jtype]; denlj = lj3[itype][jtype] + rsq*r4sig6; forcelj = lj1[itype][jtype] * epsilon[itype][jtype] * (48.0*r4sig6/(denlj*denlj*denlj) - 24.0*r4sig6/(denlj*denlj)); 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 * (cut_ljsq-rsq) * (rsq-cut_lj_innersq) / denom_lj; philj = lj1[itype][jtype] * 4.0 * epsilon[itype][jtype] * (1.0/(denlj*denlj) - 1.0/denlj); forcelj = forcelj*switch1 + philj*switch2; } } else forcelj = 0.0; fforce = forcecoul + factor_lj*forcelj; double eng = 0.0; if (rsq < cut_coulsq) { prefactor = force->qqrd2e * lj1[itype][jtype] * atom->q[i]*atom->q[j] / denc; phicoul = prefactor*erfc; if (factor_coul < 1.0) phicoul -= (1.0-factor_coul)*prefactor; eng += phicoul; } if (rsq < cut_ljsq) { philj = lj1[itype][jtype] * 4.0 * epsilon[itype][jtype] * (1.0/(denlj*denlj) - 1.0/denlj) - offset[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 *PairLJCharmmCoulLongSoft::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; if (strcmp(str,"epsilon") == 0) return (void *) epsilon; if (strcmp(str,"sigma") == 0) return (void *) sigma; if (strcmp(str,"lambda") == 0) return (void *) lambda; 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/USER-FEP/pair_lj_cut_coul_cut_soft.cpp b/src/USER-FEP/pair_lj_cut_coul_cut_soft.cpp index 631d608af..16da07a65 100644 --- a/src/USER-FEP/pair_lj_cut_coul_cut_soft.cpp +++ b/src/USER-FEP/pair_lj_cut_coul_cut_soft.cpp @@ -1,514 +1,514 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Soft-core version: Agilio Padua (Univ Blaise Pascal & CNRS) ------------------------------------------------------------------------- */ #include #include #include #include #include "pair_lj_cut_coul_cut_soft.h" #include "atom.h" #include "comm.h" #include "force.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; /* ---------------------------------------------------------------------- */ PairLJCutCoulCutSoft::PairLJCutCoulCutSoft(LAMMPS *lmp) : Pair(lmp) { writedata = 1; } /* ---------------------------------------------------------------------- */ PairLJCutCoulCutSoft::~PairLJCutCoulCutSoft() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut_lj); memory->destroy(cut_ljsq); memory->destroy(cut_coul); memory->destroy(cut_coulsq); memory->destroy(epsilon); memory->destroy(sigma); memory->destroy(lambda); memory->destroy(lj1); memory->destroy(lj2); memory->destroy(lj3); memory->destroy(lj4); memory->destroy(offset); } } /* ---------------------------------------------------------------------- */ void PairLJCutCoulCutSoft::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,forcecoul,forcelj,factor_coul,factor_lj; double denc, denlj, r4sig6; 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]) { if (rsq < cut_coulsq[itype][jtype]) { denc = sqrt(lj4[itype][jtype] + rsq); forcecoul = qqrd2e * lj1[itype][jtype] * qtmp*q[j] / (denc*denc*denc); } else forcecoul = 0.0; if (rsq < cut_ljsq[itype][jtype]) { r4sig6 = rsq*rsq / lj2[itype][jtype]; denlj = lj3[itype][jtype] + rsq*r4sig6; forcelj = lj1[itype][jtype] * epsilon[itype][jtype] * (48.0*r4sig6/(denlj*denlj*denlj) - 24.0*r4sig6/(denlj*denlj)); } else forcelj = 0.0; fpair = factor_coul*forcecoul + factor_lj*forcelj; 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[itype][jtype]) ecoul = factor_coul * qqrd2e * lj1[itype][jtype] * qtmp*q[j] / denc; else ecoul = 0.0; if (rsq < cut_ljsq[itype][jtype]) { evdwl = lj1[itype][jtype] * 4.0 * epsilon[itype][jtype] * (1.0/(denlj*denlj) - 1.0/denlj) - 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 PairLJCutCoulCutSoft::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(cut_coul,n+1,n+1,"pair:cut_coul"); memory->create(cut_coulsq,n+1,n+1,"pair:cut_coulsq"); memory->create(epsilon,n+1,n+1,"pair:epsilon"); memory->create(sigma,n+1,n+1,"pair:sigma"); memory->create(lambda,n+1,n+1,"pair:lambda"); 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 PairLJCutCoulCutSoft::settings(int narg, char **arg) { if (narg < 4 || narg > 5) error->all(FLERR,"Illegal pair_style command"); nlambda = force->numeric(FLERR,arg[0]); alphalj = force->numeric(FLERR,arg[1]); alphac = force->numeric(FLERR,arg[2]); cut_lj_global = force->numeric(FLERR,arg[3]); if (narg == 4) cut_coul_global = cut_lj_global; else cut_coul_global = force->numeric(FLERR,arg[4]); // 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; cut_coul[i][j] = cut_coul_global; } } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairLJCutCoulCutSoft::coeff(int narg, char **arg) { if (narg < 5 || narg > 7) 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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(FLERR,arg[2]); double sigma_one = force->numeric(FLERR,arg[3]); double lambda_one = force->numeric(FLERR,arg[4]); double cut_lj_one = cut_lj_global; double cut_coul_one = cut_coul_global; if (narg >= 6) cut_coul_one = cut_lj_one = force->numeric(FLERR,arg[5]); if (narg == 7) cut_coul_one = force->numeric(FLERR,arg[6]); 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; lambda[i][j] = lambda_one; cut_lj[i][j] = cut_lj_one; cut_coul[i][j] = cut_coul_one; setflag[i][j] = 1; count++; } } if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairLJCutCoulCutSoft::init_style() { if (!atom->q_flag) error->all(FLERR,"Pair style lj/cut/coul/cut/soft requires atom attribute q"); neighbor->request(this,instance_me); } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairLJCutCoulCutSoft::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]); if (lambda[i][i] != lambda[j][j]) error->all(FLERR,"Pair lj/cut/coul/cut/soft different lambda values in mix"); lambda[i][j] = lambda[i][i]; cut_lj[i][j] = mix_distance(cut_lj[i][i],cut_lj[j][j]); cut_coul[i][j] = mix_distance(cut_coul[i][i],cut_coul[j][j]); } double cut = MAX(cut_lj[i][j],cut_coul[i][j]); cut_ljsq[i][j] = cut_lj[i][j] * cut_lj[i][j]; cut_coulsq[i][j] = cut_coul[i][j] * cut_coul[i][j]; lj1[i][j] = pow(lambda[i][j], nlambda); lj2[i][j] = pow(sigma[i][j], 6.0); lj3[i][j] = alphalj * (1.0 - lambda[i][j])*(1.0 - lambda[i][j]); lj4[i][j] = alphac * (1.0 - lambda[i][j])*(1.0 - lambda[i][j]); if (offset_flag) { double denlj = lj3[i][j] + pow(cut_lj[i][j] / sigma[i][j], 6.0); offset[i][j] = lj1[i][j] * 4.0 * epsilon[i][j] * (1.0/(denlj*denlj) - 1.0/denlj); } else offset[i][j] = 0.0; epsilon[j][i] = epsilon[i][j]; sigma[j][i] = sigma[i][j]; lambda[j][i] = lambda[i][j]; cut_ljsq[j][i] = cut_ljsq[i][j]; cut_coulsq[j][i] = cut_coulsq[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 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]* lj1[i][j] * epsilon[i][j] * sig6 * (sig6 - 3.0*rc6) / (9.0*rc9); ptail_ij = 16.0*MY_PI*all[0]*all[1]* lj1[i][j] * epsilon[i][j] * sig6 * (2.0*sig6 - 3.0*rc6) / (9.0*rc9); } return cut; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJCutCoulCutSoft::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(&lambda[i][j],sizeof(double),1,fp); fwrite(&cut_lj[i][j],sizeof(double),1,fp); fwrite(&cut_coul[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJCutCoulCutSoft::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(&lambda[i][j],sizeof(double),1,fp); fread(&cut_lj[i][j],sizeof(double),1,fp); fread(&cut_coul[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(&lambda[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_lj[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_coul[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJCutCoulCutSoft::write_restart_settings(FILE *fp) { fwrite(&nlambda,sizeof(double),1,fp); fwrite(&alphalj,sizeof(double),1,fp); fwrite(&alphac,sizeof(double),1,fp); fwrite(&cut_lj_global,sizeof(double),1,fp); fwrite(&cut_coul_global,sizeof(double),1,fp); fwrite(&offset_flag,sizeof(int),1,fp); fwrite(&mix_flag,sizeof(int),1,fp); fwrite(&tail_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJCutCoulCutSoft::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&nlambda,sizeof(double),1,fp); fread(&alphalj,sizeof(double),1,fp); fread(&alphac,sizeof(double),1,fp); fread(&cut_lj_global,sizeof(double),1,fp); fread(&cut_coul_global,sizeof(double),1,fp); fread(&offset_flag,sizeof(int),1,fp); fread(&mix_flag,sizeof(int),1,fp); fread(&tail_flag,sizeof(int),1,fp); } MPI_Bcast(&nlambda,1,MPI_DOUBLE,0,world); MPI_Bcast(&alphalj,1,MPI_DOUBLE,0,world); MPI_Bcast(&alphac,1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_lj_global,1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_coul_global,1,MPI_DOUBLE,0,world); MPI_Bcast(&offset_flag,1,MPI_INT,0,world); MPI_Bcast(&mix_flag,1,MPI_INT,0,world); MPI_Bcast(&tail_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void PairLJCutCoulCutSoft::write_data(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) fprintf(fp,"%d %g %g %g\n",i,epsilon[i][i],sigma[i][i],lambda[i][i]); } /* ---------------------------------------------------------------------- proc 0 writes all pairs to data file ------------------------------------------------------------------------- */ void PairLJCutCoulCutSoft::write_data_all(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) fprintf(fp,"%d %d %g %g %g %g\n",i,j,epsilon[i][j],sigma[i][j], lambda[i][j],cut_lj[i][j]); } /* ---------------------------------------------------------------------- */ double PairLJCutCoulCutSoft::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double forcecoul,forcelj,phicoul,philj; double denc, denlj, r4sig6; if (rsq < cut_coulsq[itype][jtype]) { denc = sqrt(lj4[itype][jtype] + rsq); forcecoul = force->qqrd2e * lj1[itype][jtype] * atom->q[i]*atom->q[j] / (denc*denc*denc); } else forcecoul = 0.0; if (rsq < cut_ljsq[itype][jtype]) { r4sig6 = rsq*rsq / lj2[itype][jtype]; denlj = lj3[itype][jtype] + rsq*r4sig6; forcelj = lj1[itype][jtype] * epsilon[itype][jtype] * (48.0*r4sig6/(denlj*denlj*denlj) - 24.0*r4sig6/(denlj*denlj)); } else forcelj = 0.0; fforce = factor_coul*forcecoul + factor_lj*forcelj; double eng = 0.0; if (rsq < cut_coulsq[itype][jtype]) { phicoul = force->qqrd2e * lj1[itype][jtype] * atom->q[i]*atom->q[j] / denc; eng += factor_coul*phicoul; } if (rsq < cut_ljsq[itype][jtype]) { philj = lj1[itype][jtype] * 4.0 * epsilon[itype][jtype] * (1.0/(denlj*denlj) - 1.0/denlj) - offset[itype][jtype]; eng += factor_lj*philj; } return eng; } /* ---------------------------------------------------------------------- */ void *PairLJCutCoulCutSoft::extract(const char *str, int &dim) { dim = 0; if (strcmp(str,"cut_coul") == 0) return (void *) &cut_coul; dim = 2; if (strcmp(str,"epsilon") == 0) return (void *) epsilon; if (strcmp(str,"sigma") == 0) return (void *) sigma; if (strcmp(str,"lambda") == 0) return (void *) lambda; return NULL; } diff --git a/src/USER-FEP/pair_lj_cut_coul_long_soft.cpp b/src/USER-FEP/pair_lj_cut_coul_long_soft.cpp index 1b3c2b5ec..6636e7271 100644 --- a/src/USER-FEP/pair_lj_cut_coul_long_soft.cpp +++ b/src/USER-FEP/pair_lj_cut_coul_long_soft.cpp @@ -1,959 +1,959 @@ /* ---------------------------------------------------------------------- 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) Soft-core version: Agilio Padua (Univ Blaise Pascal & CNRS) ------------------------------------------------------------------------- */ #include #include #include #include #include "pair_lj_cut_coul_long_soft.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 /* ---------------------------------------------------------------------- */ PairLJCutCoulLongSoft::PairLJCutCoulLongSoft(LAMMPS *lmp) : Pair(lmp) { ewaldflag = pppmflag = 1; respa_enable = 1; writedata = 1; qdist = 0.0; } /* ---------------------------------------------------------------------- */ PairLJCutCoulLongSoft::~PairLJCutCoulLongSoft() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut_lj); memory->destroy(cut_ljsq); memory->destroy(epsilon); memory->destroy(sigma); memory->destroy(lambda); memory->destroy(lj1); memory->destroy(lj2); memory->destroy(lj3); memory->destroy(lj4); memory->destroy(offset); } } /* ---------------------------------------------------------------------- */ void PairLJCutCoulLongSoft::compute(int eflag, int vflag) { int i,ii,j,jj,inum,jnum,itype,jtype; double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair; double r,rsq,forcecoul,forcelj,factor_coul,factor_lj; double grij,expm2,prefactor,t,erfc; double denc, denlj, r4sig6; 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]) { 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; denc = sqrt(lj4[itype][jtype] + rsq); prefactor = qqrd2e * lj1[itype][jtype] * qtmp*q[j] / (denc*denc*denc); 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]) { r4sig6 = rsq*rsq / lj2[itype][jtype]; denlj = lj3[itype][jtype] + rsq*r4sig6; forcelj = lj1[itype][jtype] * epsilon[itype][jtype] * (48.0*r4sig6/(denlj*denlj*denlj) - 24.0*r4sig6/(denlj*denlj)); } else forcelj = 0.0; fpair = forcecoul + factor_lj*forcelj; 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) { prefactor = qqrd2e * lj1[itype][jtype] * qtmp*q[j] / denc; 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 = lj1[itype][jtype] * 4.0 * epsilon[itype][jtype] * (1.0/(denlj*denlj) - 1.0/denlj) - 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 PairLJCutCoulLongSoft::compute_inner() { int i,j,ii,jj,inum,jnum,itype,jtype; double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,fpair; double rsq,forcecoul,forcelj,factor_coul,factor_lj; double rsw; double denc, denlj, r4sig6; 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) { jtype = type[j]; denc = sqrt(lj4[itype][jtype] + rsq); forcecoul = qqrd2e * lj1[itype][jtype] * qtmp*q[j] / (denc*denc*denc); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*forcecoul; if (rsq < cut_ljsq[itype][jtype]) { r4sig6 = rsq*rsq / lj2[itype][jtype]; denlj = lj3[itype][jtype] + rsq*r4sig6; forcelj = lj1[itype][jtype] * epsilon[itype][jtype] * (48.0*r4sig6/(denlj*denlj*denlj) - 24.0*r4sig6/(denlj*denlj)); } else forcelj = 0.0; fpair = forcecoul + factor_lj*forcelj; 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 PairLJCutCoulLongSoft::compute_middle() { int i,j,ii,jj,inum,jnum,itype,jtype; double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,fpair; double rsq,forcecoul,forcelj,factor_coul,factor_lj; double rsw; double denc, denlj, r4sig6; 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) { jtype = type[j]; denc = sqrt(lj4[itype][jtype] + rsq); forcecoul = qqrd2e * lj1[itype][jtype] * qtmp*q[j] / (denc*denc*denc); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*forcecoul; if (rsq < cut_ljsq[itype][jtype]) { r4sig6 = rsq*rsq / lj2[itype][jtype]; denlj = lj3[itype][jtype] + rsq*r4sig6; forcelj = lj1[itype][jtype] * epsilon[itype][jtype] * (48.0*r4sig6/(denlj*denlj*denlj) - 24.0*r4sig6/(denlj*denlj)); } else forcelj = 0.0; fpair = forcecoul + factor_lj*forcelj; 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 PairLJCutCoulLongSoft::compute_outer(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 r,rsq,forcecoul,forcelj,factor_coul,factor_lj; double grij,expm2,fprefactor,eprefactor,t,erfc; double rsw; double denc, denlj, r4sig6; int *ilist,*jlist,*numneigh,**firstneigh; 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]) { 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; denc = sqrt(lj4[itype][jtype] + rsq); fprefactor = qqrd2e * lj1[itype][jtype] * qtmp*q[j] / (denc*denc*denc); forcecoul = fprefactor * (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 += fprefactor*rsw*rsw*(3.0 - 2.0*rsw); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*fprefactor*rsw*rsw*(3.0 - 2.0*rsw); } else { forcecoul += fprefactor; if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*fprefactor; } } } else forcecoul = 0.0; if (rsq < cut_ljsq[itype][jtype] && rsq > cut_in_off_sq) { r4sig6 = rsq*rsq / lj2[itype][jtype]; denlj = lj3[itype][jtype] + rsq*r4sig6; forcelj = lj1[itype][jtype] * epsilon[itype][jtype] * (48.0*r4sig6/(denlj*denlj*denlj) - 24.0*r4sig6/(denlj*denlj)); 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; 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) { eprefactor = qqrd2e * lj1[itype][jtype] * qtmp*q[j] / denc; ecoul = eprefactor*erfc; if (factor_coul < 1.0) ecoul -= (1.0-factor_coul)*eprefactor; } else ecoul = 0.0; if (rsq < cut_ljsq[itype][jtype]) { r4sig6 = rsq*rsq / lj2[itype][jtype]; denlj = lj3[itype][jtype] + rsq*r4sig6; evdwl = lj1[itype][jtype] * 4.0 * epsilon[itype][jtype] * (1.0/(denlj*denlj) - 1.0/denlj) - offset[itype][jtype]; evdwl *= factor_lj; } else evdwl = 0.0; } if (vflag) { if (rsq < cut_coulsq) { forcecoul = fprefactor * (erfc + EWALD_F*grij*expm2); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*fprefactor; } else forcecoul = 0.0; if (rsq <= cut_in_off_sq) { r4sig6 = rsq*rsq / lj2[itype][jtype]; denlj = lj3[itype][jtype] + rsq*r4sig6; forcelj = lj1[itype][jtype] * epsilon[itype][jtype] * (48.0*r4sig6/(denlj*denlj*denlj) - 24.0*r4sig6/(denlj*denlj)); } else if (rsq < cut_in_on_sq) { r4sig6 = rsq*rsq / lj2[itype][jtype]; denlj = lj3[itype][jtype] + rsq*r4sig6; forcelj = lj1[itype][jtype] * epsilon[itype][jtype] * (48.0*r4sig6/(denlj*denlj*denlj) - 24.0*r4sig6/(denlj*denlj)); } fpair = forcecoul + factor_lj*forcelj; } if (evflag) ev_tally(i,j,nlocal,newton_pair, evdwl,ecoul,fpair,delx,dely,delz); } } } } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairLJCutCoulLongSoft::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(lambda,n+1,n+1,"pair:lambda"); 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 PairLJCutCoulLongSoft::settings(int narg, char **arg) { if (narg < 4 || narg > 5) error->all(FLERR,"Illegal pair_style command"); nlambda = force->numeric(FLERR,arg[0]); alphalj = force->numeric(FLERR,arg[1]); alphac = force->numeric(FLERR,arg[2]); cut_lj_global = force->numeric(FLERR,arg[3]); if (narg == 4) cut_coul = cut_lj_global; else cut_coul = force->numeric(FLERR,arg[4]); // 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 PairLJCutCoulLongSoft::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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(FLERR,arg[2]); double sigma_one = force->numeric(FLERR,arg[3]); double lambda_one = force->numeric(FLERR,arg[4]); double cut_lj_one = cut_lj_global; if (narg == 6) cut_lj_one = force->numeric(FLERR,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; lambda[i][j] = lambda_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 PairLJCutCoulLongSoft::init_style() { if (!atom->q_flag) error->all(FLERR,"Pair style lj/cut/coul/long/soft 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,instance_me); else if (respa == 1) { irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respainner = 1; irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 3; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respaouter = 1; } else { irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respainner = 1; irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 2; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respamiddle = 1; irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 3; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respaouter = 1; } } else irequest = neighbor->request(this,instance_me); 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 requires a KSpace style"); g_ewald = force->kspace->g_ewald; } /* ---------------------------------------------------------------------- neighbor callback to inform pair style of neighbor list to use regular or rRESPA ------------------------------------------------------------------------- */ void PairLJCutCoulLongSoft::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 PairLJCutCoulLongSoft::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]); if (lambda[i][i] != lambda[j][j]) error->all(FLERR,"Pair lj/cut/coul/long/soft different lambda values in mix"); lambda[i][j] = lambda[i][i]; cut_lj[i][j] = mix_distance(cut_lj[i][i],cut_lj[j][j]); } // include TIP4P qdist in full cutoff, qdist = 0.0 if not TIP4P double cut = MAX(cut_lj[i][j],cut_coul+2.0*qdist); cut_ljsq[i][j] = cut_lj[i][j] * cut_lj[i][j]; lj1[i][j] = pow(lambda[i][j], nlambda); lj2[i][j] = pow(sigma[i][j], 6.0); lj3[i][j] = alphalj * (1.0 - lambda[i][j])*(1.0 - lambda[i][j]); lj4[i][j] = alphac * (1.0 - lambda[i][j])*(1.0 - lambda[i][j]); if (offset_flag) { double denlj = lj3[i][j] + pow(cut_lj[i][j] / sigma[i][j], 6.0); offset[i][j] = lj1[i][j] * 4.0 * epsilon[i][j] * (1.0/(denlj*denlj) - 1.0/denlj); } else offset[i][j] = 0.0; epsilon[j][i] = epsilon[i][j]; sigma[j][i] = sigma[i][j]; lambda[j][i] = lambda[i][j]; 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]* lj1[i][j] * epsilon[i][j] * sig6 * (sig6 - 3.0*rc6) / (9.0*rc9); ptail_ij = 16.0*MY_PI*all[0]*all[1]* lj1[i][j] * epsilon[i][j] * sig6 * (2.0*sig6 - 3.0*rc6) / (9.0*rc9); } return cut; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJCutCoulLongSoft::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(&lambda[i][j],sizeof(double),1,fp); fwrite(&cut_lj[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJCutCoulLongSoft::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(&lambda[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(&lambda[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 PairLJCutCoulLongSoft::write_restart_settings(FILE *fp) { fwrite(&nlambda,sizeof(double),1,fp); fwrite(&alphalj,sizeof(double),1,fp); fwrite(&alphac,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); fwrite(&tail_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJCutCoulLongSoft::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&nlambda,sizeof(double),1,fp); fread(&alphalj,sizeof(double),1,fp); fread(&alphac,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); fread(&tail_flag,sizeof(int),1,fp); } MPI_Bcast(&nlambda,1,MPI_DOUBLE,0,world); MPI_Bcast(&alphalj,1,MPI_DOUBLE,0,world); MPI_Bcast(&alphac,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); MPI_Bcast(&tail_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void PairLJCutCoulLongSoft::write_data(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) fprintf(fp,"%d %g %g %g\n",i,epsilon[i][i],sigma[i][i],lambda[i][i]); } /* ---------------------------------------------------------------------- proc 0 writes all pairs to data file ------------------------------------------------------------------------- */ void PairLJCutCoulLongSoft::write_data_all(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) fprintf(fp,"%d %d %g %g %g %g\n",i,j,epsilon[i][j],sigma[i][j], lambda[i][j],cut_lj[i][j]); } /* ---------------------------------------------------------------------- */ double PairLJCutCoulLongSoft::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r,grij,expm2,t,erfc,prefactor; double forcecoul,forcelj,phicoul,philj; double denc, denlj, r4sig6; 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; denc = sqrt(lj4[itype][jtype] + rsq); prefactor = force->qqrd2e * lj1[itype][jtype] * atom->q[i]*atom->q[j] / (denc*denc*denc); 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]) { r4sig6 = rsq*rsq / lj2[itype][jtype]; denlj = lj3[itype][jtype] + rsq*r4sig6; forcelj = lj1[itype][jtype] * epsilon[itype][jtype] * (48.0*r4sig6/(denlj*denlj*denlj) - 24.0*r4sig6/(denlj*denlj)); } else forcelj = 0.0; fforce = forcecoul + factor_lj*forcelj; double eng = 0.0; if (rsq < cut_coulsq) { prefactor = force->qqrd2e * lj1[itype][jtype] * atom->q[i]*atom->q[j] / denc; phicoul = prefactor*erfc; if (factor_coul < 1.0) phicoul -= (1.0-factor_coul)*prefactor; eng += phicoul; } if (rsq < cut_ljsq[itype][jtype]) { philj = lj1[itype][jtype] * 4.0 * epsilon[itype][jtype] * (1.0/(denlj*denlj) - 1.0/denlj) - offset[itype][jtype]; eng += factor_lj*philj; } return eng; } /* ---------------------------------------------------------------------- */ void *PairLJCutCoulLongSoft::extract(const char *str, int &dim) { dim = 0; if (strcmp(str,"cut_coul") == 0) return (void *) &cut_coul; dim = 2; if (strcmp(str,"epsilon") == 0) return (void *) epsilon; if (strcmp(str,"sigma") == 0) return (void *) sigma; if (strcmp(str,"lambda") == 0) return (void *) lambda; return NULL; } diff --git a/src/USER-FEP/pair_lj_cut_soft.cpp b/src/USER-FEP/pair_lj_cut_soft.cpp index 7f04158c1..3798b2793 100644 --- a/src/USER-FEP/pair_lj_cut_soft.cpp +++ b/src/USER-FEP/pair_lj_cut_soft.cpp @@ -1,781 +1,781 @@ /* ---------------------------------------------------------------------- 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) Soft-core version: Agilio Padua (Univ Blaise Pascal & CNRS) ------------------------------------------------------------------------- */ #include #include #include #include #include "pair_lj_cut_soft.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; /* ---------------------------------------------------------------------- */ PairLJCutSoft::PairLJCutSoft(LAMMPS *lmp) : Pair(lmp) { respa_enable = 1; writedata = 1; allocated = 0; } /* ---------------------------------------------------------------------- */ PairLJCutSoft::~PairLJCutSoft() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut); memory->destroy(epsilon); memory->destroy(sigma); memory->destroy(lambda); memory->destroy(lj1); memory->destroy(lj2); memory->destroy(lj3); memory->destroy(offset); allocated=0; } } /* ---------------------------------------------------------------------- */ void PairLJCutSoft::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,forcelj,factor_lj; double denlj, r4sig6; 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]) { r4sig6 = rsq*rsq / lj2[itype][jtype]; denlj = lj3[itype][jtype] + rsq*r4sig6; forcelj = lj1[itype][jtype] * epsilon[itype][jtype] * (48.0*r4sig6/(denlj*denlj*denlj) - 24.0*r4sig6/(denlj*denlj)); fpair = factor_lj*forcelj; 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 = lj1[itype][jtype] * 4.0 * epsilon[itype][jtype] * (1.0/(denlj*denlj) - 1.0/denlj) - 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 PairLJCutSoft::compute_inner() { int i,j,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,fpair; double rsq,forcelj,factor_lj,rsw; double denlj, r4sig6; 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) { jtype = type[j]; r4sig6 = rsq*rsq / lj2[itype][jtype]; denlj = lj3[itype][jtype] + rsq*r4sig6; forcelj = lj1[itype][jtype] * epsilon[itype][jtype] * (48.0*r4sig6/(denlj*denlj*denlj) - 24.0*r4sig6/(denlj*denlj)); fpair = factor_lj*forcelj; 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 PairLJCutSoft::compute_middle() { int i,j,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,fpair; double rsq,forcelj,factor_lj,rsw; double denlj, r4sig6; 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) { jtype = type[j]; r4sig6 = rsq*rsq / lj2[itype][jtype]; denlj = lj3[itype][jtype] + rsq*r4sig6; forcelj = lj1[itype][jtype] * epsilon[itype][jtype] * (48.0*r4sig6/(denlj*denlj*denlj) - 24.0*r4sig6/(denlj*denlj)); fpair = factor_lj*forcelj; 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 PairLJCutSoft::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,forcelj,factor_lj,rsw; double denlj, r4sig6; 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) { r4sig6 = rsq*rsq / lj2[itype][jtype]; denlj = lj3[itype][jtype] + rsq*r4sig6; forcelj = lj1[itype][jtype] * epsilon[itype][jtype] * (48.0*r4sig6/(denlj*denlj*denlj) - 24.0*r4sig6/(denlj*denlj)); fpair = factor_lj*forcelj; 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) { r4sig6 = rsq*rsq / lj2[itype][jtype]; denlj = lj3[itype][jtype] + rsq*r4sig6; evdwl = lj1[itype][jtype] * 4.0 * epsilon[itype][jtype] * (1.0/(denlj*denlj) - 1.0/denlj) - offset[itype][jtype]; evdwl *= factor_lj; } if (vflag) { if (rsq <= cut_in_off_sq) { r4sig6 = rsq*rsq / lj2[itype][jtype]; denlj = lj3[itype][jtype] + rsq*r4sig6; forcelj = lj1[itype][jtype] * epsilon[itype][jtype] * (48.0*r4sig6/(denlj*denlj*denlj) - 24.0*r4sig6/(denlj*denlj)); fpair = factor_lj*forcelj; } else if (rsq < cut_in_on_sq) fpair = factor_lj*forcelj; } if (evflag) ev_tally(i,j,nlocal,newton_pair, evdwl,0.0,fpair,delx,dely,delz); } } } } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairLJCutSoft::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(lambda,n+1,n+1,"pair:lambda"); 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(offset,n+1,n+1,"pair:offset"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairLJCutSoft::settings(int narg, char **arg) { if (narg != 3) error->all(FLERR,"Illegal pair_style command"); nlambda = force->numeric(FLERR,arg[0]); alphalj = force->numeric(FLERR,arg[1]); cut_global = force->numeric(FLERR,arg[2]); // 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 PairLJCutSoft::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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(FLERR,arg[2]); double sigma_one = force->numeric(FLERR,arg[3]); double lambda_one = force->numeric(FLERR,arg[4]); double cut_one = cut_global; if (narg == 6) cut_one = force->numeric(FLERR,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; lambda[i][j] = lambda_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 PairLJCutSoft::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,instance_me); else if (respa == 1) { irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respainner = 1; irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 3; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respaouter = 1; } else { irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respainner = 1; irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 2; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respamiddle = 1; irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 3; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respaouter = 1; } } else irequest = neighbor->request(this,instance_me); // 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 PairLJCutSoft::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 PairLJCutSoft::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] = pow(lambda[i][j], nlambda); lj2[i][j] = pow(sigma[i][j], 6.0); lj3[i][j] = alphalj * (1.0 - lambda[i][j])*(1.0 - lambda[i][j]); if (offset_flag) { double denlj = lj3[i][j] + pow(cut[i][j] / sigma[i][j], 6.0); offset[i][j] = lj1[i][j] * 4.0 * epsilon[i][j] * (1.0/(denlj*denlj) - 1.0/denlj); } else offset[i][j] = 0.0; epsilon[j][i] = epsilon[i][j]; sigma[j][i] = sigma[i][j]; lambda[j][i] = lambda[i][j]; lj1[j][i] = lj1[i][j]; lj2[j][i] = lj2[i][j]; lj3[j][i] = lj3[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]* lj1[i][j] * epsilon[i][j] * sig6 * (sig6 - 3.0*rc6) / (9.0*rc9); ptail_ij = 16.0*MY_PI*all[0]*all[1]* lj1[i][j] * epsilon[i][j] * sig6 * (2.0*sig6 - 3.0*rc6) / (9.0*rc9); } return cut[i][j]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJCutSoft::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(&lambda[i][j],sizeof(double),1,fp); fwrite(&cut[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJCutSoft::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(&lambda[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(&lambda[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJCutSoft::write_restart_settings(FILE *fp) { fwrite(&nlambda,sizeof(double),1,fp); fwrite(&alphalj,sizeof(double),1,fp); fwrite(&cut_global,sizeof(double),1,fp); fwrite(&offset_flag,sizeof(int),1,fp); fwrite(&mix_flag,sizeof(int),1,fp); fwrite(&tail_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJCutSoft::read_restart_settings(FILE *fp) { int me = comm->me; if (me == 0) { fread(&nlambda,sizeof(double),1,fp); fread(&alphalj,sizeof(double),1,fp); fread(&cut_global,sizeof(double),1,fp); fread(&offset_flag,sizeof(int),1,fp); fread(&mix_flag,sizeof(int),1,fp); fread(&tail_flag,sizeof(int),1,fp); } MPI_Bcast(&nlambda,1,MPI_DOUBLE,0,world); MPI_Bcast(&alphalj,1,MPI_DOUBLE,0,world); 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); MPI_Bcast(&tail_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void PairLJCutSoft::write_data(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) fprintf(fp,"%d %g %g %g\n",i,epsilon[i][i],sigma[i][i],lambda[i][i]); } /* ---------------------------------------------------------------------- proc 0 writes all pairs to data file ------------------------------------------------------------------------- */ void PairLJCutSoft::write_data_all(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) fprintf(fp,"%d %d %g %g %g %g\n",i,j,epsilon[i][j],sigma[i][j], lambda[i][j],cut[i][j]); } /* ---------------------------------------------------------------------- */ double PairLJCutSoft::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double forcelj,philj; double r4sig6, denlj; if (rsq < cutsq[itype][jtype]) { r4sig6 = rsq*rsq / lj2[itype][jtype]; denlj = lj3[itype][jtype] + rsq*r4sig6; forcelj = lj1[itype][jtype] * epsilon[itype][jtype] * (48.0*r4sig6/(denlj*denlj*denlj) - 24.0*r4sig6/(denlj*denlj)); } else forcelj = 0.0; fforce = factor_lj*forcelj; if (rsq < cutsq[itype][jtype]) { philj = lj1[itype][jtype] * 4.0 * epsilon[itype][jtype] * (1.0/(denlj*denlj) - 1.0/denlj) - offset[itype][jtype]; } else philj = 0.0; return factor_lj*philj; } /* ---------------------------------------------------------------------- */ void *PairLJCutSoft::extract(const char *str, int &dim) { dim = 2; if (strcmp(str,"epsilon") == 0) return (void *) epsilon; if (strcmp(str,"sigma") == 0) return (void *) sigma; if (strcmp(str,"lambda") == 0) return (void *) lambda; return NULL; } diff --git a/src/USER-FEP/pair_morse_soft.cpp b/src/USER-FEP/pair_morse_soft.cpp index 877fa74d6..6c86d8916 100644 --- a/src/USER-FEP/pair_morse_soft.cpp +++ b/src/USER-FEP/pair_morse_soft.cpp @@ -1,424 +1,424 @@ /* ---------------------------------------------------------------------- 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 #include #include #include #include "pair_morse_soft.h" #include "atom.h" #include "comm.h" #include "force.h" #include "neigh_list.h" #include "memory.h" #include "math_special.h" #include "error.h" using namespace LAMMPS_NS; using namespace MathSpecial; /* ---------------------------------------------------------------------- Contributing author: Stefan Paquay (TU/e) ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */ PairMorseSoft::~PairMorseSoft() { if(allocated){ memory->destroy(lambda); } } /* ---------------------------------------------------------------------- */ void PairMorseSoft::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,r,dr,dexp,dexp2,dexp3,factor_lj; double ea,phi,V0,iea2; double D, a, x0, l, B, s1, llf; 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); dr = r - r0[itype][jtype]; D = d0[itype][jtype]; a = alpha[itype][jtype]; x0 = r0[itype][jtype]; dexp = exp( -a * dr ); dexp2 = dexp*dexp; dexp3 = dexp2*dexp; l = lambda[itype][jtype]; ea = exp( a * x0 ); iea2 = exp( -2.*a*x0 ); V0 = D * dexp * ( dexp - 2.0 ); B = -2.0 * D * iea2 * ( ea - 1.0 ) / 3.0; if (l >= shift_range){ s1 = (l - 1.0) / (shift_range - 1.0); phi = V0 + B*dexp3 * s1; // Force computation: fpair = 3.0*a*B*dexp3*s1 + 2.0*a*D*(dexp2 - dexp); fpair /= r; }else{ llf = MathSpecial::powint( l / shift_range, nlambda ); phi = V0 + B*dexp3; phi *= llf; // Force computation: if (r == 0.0){ fpair = 0.0; }else{ fpair = 3.0*a*B*dexp3 + 2.0*a*D*(dexp2 - dexp); fpair *= llf / r; } } fpair *= factor_lj; 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 = phi*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 PairMorseSoft::allocate() { PairMorse::allocate(); int n = atom->ntypes; memory->create(lambda,n+1,n+1,"pair:lambda"); } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairMorseSoft::coeff(int narg, char **arg) { if (narg < 6 || narg > 7) 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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double d0_one = force->numeric(FLERR,arg[2]); double alpha_one = force->numeric(FLERR,arg[3]); double r0_one = force->numeric(FLERR,arg[4]); double lambda_one = force->numeric(FLERR,arg[5]); double cut_one = cut_global; if (narg == 7) cut_one = force->numeric(FLERR,arg[6]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { d0[i][j] = d0_one; alpha[i][j] = alpha_one; r0[i][j] = r0_one; lambda[i][j] = lambda_one; cut[i][j] = cut_one; setflag[i][j] = 1; count++; } } if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- Set global stuff. ------------------------------------------------------------------------- */ void PairMorseSoft::settings(int narg, char **arg) { if (narg != 3) error->all(FLERR,"Illegal pair_style command"); nlambda = force->inumeric(FLERR,arg[0]); shift_range = force->numeric(FLERR,arg[1]); cut_global = force->numeric(FLERR,arg[2]); // 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; } } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairMorseSoft::init_one(int i, int j) { if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set"); morse1[i][j] = 2.0*d0[i][j]*alpha[i][j]; if (offset_flag) { double l, s1, V0, B, llf; double alpha_dr = -alpha[i][j] * (cut[i][j] - r0[i][j]); double D = d0[i][j]; double a = alpha[i][j]; double x0 = r0[i][j]; double dexp = exp( alpha_dr ); double dexp2 = dexp*dexp; double dexp3 = dexp2*dexp; l = lambda[i][j]; double ea = exp( a*x0 ); double iea2 = exp( -2.*a*x0 ); V0 = D * dexp * ( dexp - 2.0 ); B = -2.0 * D * iea2 * ( ea - 1.0 ) / 3.0; if (l >= shift_range){ s1 = (l - 1.0) / (shift_range - 1.0); offset[i][j] = V0 + B*dexp3 * s1; }else{ llf = MathSpecial::powint( l / shift_range, nlambda ); offset[i][j] = V0 + B*dexp3; offset[i][j] *= llf; } } else offset[i][j] = 0.0; d0[j][i] = d0[i][j]; alpha[j][i] = alpha[i][j]; r0[j][i] = r0[i][j]; morse1[j][i] = morse1[i][j]; lambda[j][i] = lambda[i][j]; offset[j][i] = offset[i][j]; return cut[i][j]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairMorseSoft::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(&d0[i][j],sizeof(double),1,fp); fwrite(&alpha[i][j],sizeof(double),1,fp); fwrite(&r0[i][j],sizeof(double),1,fp); fwrite(&lambda[i][j],sizeof(double),1,fp); fwrite(&cut[i][j],sizeof(double),1,fp); } } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairMorseSoft::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(&d0[i][j],sizeof(double),1,fp); fread(&alpha[i][j],sizeof(double),1,fp); fread(&r0[i][j],sizeof(double),1,fp); fread(&lambda[i][j],sizeof(double),1,fp); fread(&cut[i][j],sizeof(double),1,fp); } MPI_Bcast(&d0[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&alpha[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&r0[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&lambda[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); } } } } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void PairMorseSoft::write_data(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) fprintf(fp,"%d %g %g %g %g\n",i,d0[i][i],alpha[i][i],r0[i][i], lambda[i][i]); } /* ---------------------------------------------------------------------- proc 0 writes all pairs to data file ------------------------------------------------------------------------- */ void PairMorseSoft::write_data_all(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) fprintf(fp,"%d %g %g %g %g\n",i,d0[i][j],alpha[i][j],r0[i][j], lambda[i][j]); } /* ---------------------------------------------------------------------- */ double PairMorseSoft::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r, dr, dexp, dexp2, dexp3, phi; double B, D, a, ea, iea2; double x0, V0, s1, l, llf; D = d0[itype][jtype]; a = alpha[itype][jtype]; x0 = r0[itype][jtype]; r = sqrt(rsq); dr = r - r0[itype][jtype]; dexp = exp( -a * dr ); dexp2 = dexp*dexp; dexp3 = dexp2*dexp; l = lambda[itype][jtype]; ea = exp( a * x0 ); iea2 = exp( -2.*a*x0 ); V0 = D * dexp * ( dexp - 2.0 ); B = -2.0 * D * iea2 * ( ea - 1.0 ) / 3.0; if (l >= shift_range){ s1 = (l - 1.0) / (shift_range - 1.0); phi = V0 + B*dexp3 * s1; // Force computation: fforce = 3.0*a*B*dexp3*s1 + 2.0*a*D*(dexp2 - dexp); fforce /= r; }else{ llf = MathSpecial::powint( l / shift_range, nlambda ); phi = V0 + B*dexp3; phi *= llf; // Force computation: if (r == 0.0){ fforce = 0.0; }else{ fforce = 3.0*a*B*dexp3 + 2.0*a*D*(dexp2 - dexp); fforce *= llf / r; } } fforce *= factor_lj; phi -= offset[itype][jtype]; return factor_lj*phi; } /* ---------------------------------------------------------------------- */ void *PairMorseSoft::extract(const char *str, int &dim) { dim = 2; if (strcmp(str,"d0") == 0) return (void *) d0; if (strcmp(str,"r0") == 0) return (void *) r0; if (strcmp(str,"alpha") == 0) return (void *) alpha; if (strcmp(str,"lambda") == 0) return (void *) lambda; return NULL; } diff --git a/src/USER-LB/fix_lb_rigid_pc_sphere.cpp b/src/USER-LB/fix_lb_rigid_pc_sphere.cpp index 54637ce34..b5383fe1a 100644 --- a/src/USER-LB/fix_lb_rigid_pc_sphere.cpp +++ b/src/USER-LB/fix_lb_rigid_pc_sphere.cpp @@ -1,1691 +1,1691 @@ /* ---------------------------------------------------------------------- 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: Frances Mackay, Santtu Ollila, Colin Denniston (UWO) Based on fix_rigid (version from 2008). ------------------------------------------------------------------------- */ #include #include #include #include #include "fix_lb_rigid_pc_sphere.h" #include "atom.h" #include "atom_vec.h" #include "domain.h" #include "update.h" #include "respa.h" #include "modify.h" #include "group.h" #include "comm.h" #include "force.h" #include "output.h" #include "memory.h" #include "error.h" #include "fix_lb_fluid.h" using namespace LAMMPS_NS; using namespace FixConst; /* -------------------------------------------------------------------------- */ FixLbRigidPCSphere::FixLbRigidPCSphere(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg) { int i, ibody; scalar_flag = 1; extscalar = 0; time_integrate = 1; rigid_flag = 1; create_attribute = 1; virial_flag = 1; // perform initial allocation of atom-based arrays // register with Atom class body = NULL; up = NULL; grow_arrays(atom->nmax); atom->add_callback(0); // by default assume all of the particles interact with the fluid. inner_nodes = 0; // parse command-line args // set nbody and body[i] for each atom if (narg < 4) error->all(FLERR,"Illegal fix lb/rigid/pc/sphere command"); // single rigid body // nbody = 1 // all atoms in fix group are part of body int iarg; if (strcmp(arg[3],"single") == 0) { iarg = 4; nbody = 1; int *mask = atom->mask; int nlocal = atom->nlocal; for (i = 0; i < nlocal; i++) { body[i] = -1; if (mask[i] & groupbit) body[i] = 0; } // each molecule in fix group is a rigid body // maxmol = largest molecule # // ncount = # of atoms in each molecule (have to sum across procs) // nbody = # of non-zero ncount values // use nall as incremented ptr to set body[] values for each atom } else if (strcmp(arg[3],"molecule") == 0) { iarg = 4; if (atom->molecular == 0) error->all(FLERR,"Must use a molecular atom style with " "fix lb/rigid/pc/sphere molecule"); int *mask = atom->mask; tagint *molecule = atom->molecule; int nlocal = atom->nlocal; tagint maxmol_tag = -1; for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) maxmol_tag = MAX(maxmol_tag,molecule[i]); tagint itmp; MPI_Allreduce(&maxmol_tag,&itmp,1,MPI_LMP_TAGINT,MPI_MAX,world); if (itmp+1 > MAXSMALLINT) error->all(FLERR,"Too many molecules for fix lb/rigid/pc/sphere"); int maxmol = (int) itmp; int *ncount; memory->create(ncount,maxmol+1,"rigid:ncount"); for (i = 0; i <= maxmol; i++) ncount[i] = 0; for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) ncount[molecule[i]]++; int *nall; memory->create(nall,maxmol+1,"rigid:ncount"); MPI_Allreduce(ncount,nall,maxmol+1,MPI_LMP_TAGINT,MPI_SUM,world); nbody = 0; for (i = 0; i <= maxmol; i++) if (nall[i]) nall[i] = nbody++; else nall[i] = -1; for (i = 0; i < nlocal; i++) { body[i] = -1; if (mask[i] & groupbit) body[i] = nall[molecule[i]]; } memory->destroy(ncount); memory->destroy(nall); // each listed group is a rigid body // check if all listed groups exist // an atom must belong to fix group and listed group to be in rigid body // error if atom belongs to more than 1 rigid body } else if (strcmp(arg[3],"group") == 0) { if (narg < 5) error->all(FLERR,"Illegal fix lb/rigid/pc/sphere command"); nbody = atoi(arg[4]); if (nbody <= 0) error->all(FLERR,"Illegal fix lb/rigid/pc/sphere command"); if (narg < 5+nbody) error->all(FLERR,"Illegal fix lb/rigid/pc/sphere command"); iarg = 5 + nbody; int *igroups = new int[nbody]; for (ibody = 0; ibody < nbody; ibody++) { igroups[ibody] = group->find(arg[5+ibody]); if (igroups[ibody] == -1) error->all(FLERR,"Could not find fix lb/rigid/pc/sphere group ID"); } int *mask = atom->mask; int nlocal = atom->nlocal; int flag = 0; for (i = 0; i < nlocal; i++) { body[i] = -1; if (mask[i] & groupbit) for (ibody = 0; ibody < nbody; ibody++) if (mask[i] & group->bitmask[igroups[ibody]]) { if (body[i] >= 0) flag = 1; body[i] = ibody; } } int flagall; MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,world); if (flagall) error->all(FLERR,"One or more atoms belong to multiple rigid bodies"); delete [] igroups; }else error->all(FLERR,"Illegal fix lb/rigid/pc/sphere command"); // error check on nbody if (nbody == 0) error->all(FLERR,"No rigid bodies defined"); // create all nbody-length arrays memory->create(nrigid,nbody,"lb/rigid/pc/sphere:nrigid"); memory->create(nrigid_shell,nbody,"lb/rigid/pc/sphere:nrigid_shell"); memory->create(masstotal,nbody,"lb/rigid/pc/sphere:masstotal"); memory->create(masstotal_shell,nbody,"lb/rigid/pc/sphere:masstotal_shell"); memory->create(sphereradius,nbody,"lb/rigid/pc/sphere:sphereradius"); memory->create(xcm,nbody,3,"lb/rigid/pc/sphere:xcm"); memory->create(xcm_old,nbody,3,"lb/rigid/pc/sphere:xcm_old"); memory->create(vcm,nbody,3,"lb/rigid/pc/sphere:vcm"); memory->create(ucm,nbody,3,"lb/rigid/pc/sphere:ucm"); memory->create(ucm_old,nbody,3,"lb/rigid/pc/sphere:ucm_old"); memory->create(fcm,nbody,3,"lb/rigid/pc/sphere:fcm"); memory->create(fcm_old,nbody,3,"lb/rigid/pc/sphere:fcm_old"); memory->create(fcm_fluid,nbody,3,"lb/rigid/pc/sphere:fcm_fluid"); memory->create(omega,nbody,3,"lb/rigid/pc/sphere:omega"); memory->create(torque,nbody,3,"lb/rigid/pc/sphere:torque"); memory->create(torque_old,nbody,3,"lb/rigid/pc/sphere:torque_old"); memory->create(torque_fluid,nbody,3,"lb/rigid/pc/sphere:torque_fluid"); memory->create(torque_fluid_old,nbody,3,"lb/rigid/pc/sphere:torque_fluid_old"); memory->create(rotate,nbody,3,"lb/rigid/pc/sphere:rotate"); memory->create(imagebody,nbody,"lb/rigid/pc/sphere:imagebody"); memory->create(fflag,nbody,3,"lb/rigid/pc/sphere:fflag"); memory->create(tflag,nbody,3,"lb/rigid/pc/sphere:tflag"); memory->create(sum,nbody,6,"lb/rigid/pc/sphere:sum"); memory->create(all,nbody,6,"lb/rigid/pc/sphere:all"); memory->create(remapflag,nbody,4,"lb/rigid/pc/sphere:remapflag"); Gamma_MD = new double[nbody]; // initialize force/torque flags to default = 1.0 array_flag = 1; size_array_rows = nbody; size_array_cols = 15; global_freq = 1; extarray = 0; for (i = 0; i < nbody; i++) { fflag[i][0] = fflag[i][1] = fflag[i][2] = 1.0; tflag[i][0] = tflag[i][1] = tflag[i][2] = 1.0; } // parse optional args that set fflag and tflag while (iarg < narg) { if (strcmp(arg[iarg],"force") == 0) { if (iarg+5 > narg) error->all(FLERR,"Illegal fix lb/rigid/pc/sphere command"); int mlo,mhi; - force->bounds(arg[iarg+1],nbody,mlo,mhi); + force->bounds(FLERR,arg[iarg+1],nbody,mlo,mhi); double xflag,yflag,zflag; if (strcmp(arg[iarg+2],"off") == 0) xflag = 0.0; else if (strcmp(arg[iarg+2],"on") == 0) xflag = 1.0; else error->all(FLERR,"Illegal fix lb/rigid/pc/sphere command"); if (strcmp(arg[iarg+2],"off") == 0) yflag = 0.0; else if (strcmp(arg[iarg+3],"on") == 0) yflag = 1.0; else error->all(FLERR,"Illegal fix lb/rigid/pc/sphere command"); if (strcmp(arg[iarg+4],"off") == 0) zflag = 0.0; else if (strcmp(arg[iarg+4],"on") == 0) zflag = 1.0; else error->all(FLERR,"Illegal fix lb/rigid/pc/sphere command"); int count = 0; for (int m = mlo; m <= mhi; m++) { fflag[m-1][0] = xflag; fflag[m-1][1] = yflag; fflag[m-1][2] = zflag; count++; } if (count == 0) error->all(FLERR,"Illegal fix lb/rigid/pc/sphere command"); iarg += 5; } else if (strcmp(arg[iarg],"torque") == 0) { if (iarg+5 > narg) error->all(FLERR,"Illegal fix lb/rigid/pc/sphere command"); int mlo,mhi; - force->bounds(arg[iarg+1],nbody,mlo,mhi); + force->bounds(FLERR,arg[iarg+1],nbody,mlo,mhi); double xflag,yflag,zflag; if (strcmp(arg[iarg+2],"off") == 0) xflag = 0.0; else if (strcmp(arg[iarg+2],"on") == 0) xflag = 1.0; else error->all(FLERR,"Illegal fix lb/rigid/pc/sphere command"); if (strcmp(arg[iarg+3],"off") == 0) yflag = 0.0; else if (strcmp(arg[iarg+3],"on") == 0) yflag = 1.0; else error->all(FLERR,"Illegal fix lb/rigid/pc/sphere command"); if (strcmp(arg[iarg+4],"off") == 0) zflag = 0.0; else if (strcmp(arg[iarg+4],"on") == 0) zflag = 1.0; else error->all(FLERR,"Illegal fix lb/rigid/pc/sphere command"); int count = 0; for (int m = mlo; m <= mhi; m++) { tflag[m-1][0] = xflag; tflag[m-1][1] = yflag; tflag[m-1][2] = zflag; count++; } if (count == 0) error->all(FLERR,"Illegal fix lb/rigid/pc/sphere command"); iarg += 5; // specify if certain particles are inside the rigid spherical body, // and therefore should not } else if(strcmp(arg[iarg],"innerNodes")==0){ inner_nodes = 1; igroupinner = group->find(arg[iarg+1]); if(igroupinner == -1) error->all(FLERR,"Could not find fix lb/rigid/pc/sphere innerNodes group ID"); iarg += 2; } else error->all(FLERR,"Illegal fix lb/rigid/pc/sphere command"); } // initialize vector output quantities in case accessed before run for (i = 0; i < nbody; i++) { xcm[i][0] = xcm[i][1] = xcm[i][2] = 0.0; xcm_old[i][0] = xcm_old[i][1] = xcm_old[i][2] = 0.0; vcm[i][0] = vcm[i][1] = vcm[i][2] = 0.0; ucm[i][0] = ucm[i][1] = ucm[i][2] = 0.0; ucm_old[i][0] = ucm_old[i][1] = ucm_old[i][2] = 0.0; fcm[i][0] = fcm[i][1] = fcm[i][2] = 0.0; fcm_old[i][0] = fcm_old[i][1] = fcm_old[i][2] = 0.0; fcm_fluid[i][0] = fcm_fluid[i][1] = fcm_fluid[i][2] = 0.0; torque[i][0] = torque[i][1] = torque[i][2] = 0.0; torque_old[i][0] = torque_old[i][1] = torque_old[i][2] = 0.0; torque_fluid[i][0] = torque_fluid[i][1] = torque_fluid[i][2] = 0.0; torque_fluid_old[i][0] = torque_fluid_old[i][1] = torque_fluid_old[i][2] = 0.0; } // nrigid[n] = # of atoms in Nth rigid body // error if one or zero atoms int *ncount = new int[nbody]; for (ibody = 0; ibody < nbody; ibody++) ncount[ibody] = 0; int nlocal = atom->nlocal; for (i = 0; i < nlocal; i++) if (body[i] >= 0) ncount[body[i]]++; MPI_Allreduce(ncount,nrigid,nbody,MPI_INT,MPI_SUM,world); //count the number of atoms in the shell. if(inner_nodes == 1){ int *mask = atom->mask; for(ibody=0; ibodybitmask[igroupinner])){ if(body[i] >= 0) ncount[body[i]]++; } } MPI_Allreduce(ncount,nrigid_shell,nbody,MPI_INT,MPI_SUM,world); }else { for(ibody=0; ibody < nbody; ibody++) nrigid_shell[ibody]=nrigid[ibody]; } delete [] ncount; for (ibody = 0; ibody < nbody; ibody++) if (nrigid[ibody] <= 1) error->all(FLERR,"One or zero atoms in rigid body"); // set image flags for each rigid body to default values // will be reset during init() based on xcm and then by pre_neighbor() // set here, so image value will persist from run to run for (ibody = 0; ibody < nbody; ibody++) imagebody[ibody] = ((imageint) IMGMAX << IMG2BITS) | ((imageint) IMGMAX << IMGBITS) | IMGMAX; // print statistics int nsum = 0; for (ibody = 0; ibody < nbody; ibody++) nsum += nrigid[ibody]; if (comm->me == 0) { if (screen) fprintf(screen,"%d rigid bodies with %d atoms\n",nbody,nsum); if (logfile) fprintf(logfile,"%d rigid bodies with %d atoms\n",nbody,nsum); } int groupbit_lb_fluid = 0; for(int ifix=0; ifixnfix; ifix++) if(strcmp(modify->fix[ifix]->style,"lb/fluid")==0){ fix_lb_fluid = (FixLbFluid *)modify->fix[ifix]; groupbit_lb_fluid = group->bitmask[modify->fix[ifix]->igroup]; } if(groupbit_lb_fluid == 0) error->all(FLERR,"the lb/fluid fix must also be used if using the lb/rigid/pc/sphere fix"); int *mask = atom->mask; if(inner_nodes == 1){ for(int j=0; jbitmask[igroupinner]) && !(mask[j] & groupbit_lb_fluid)) error->one(FLERR,"use the innerNodes keyword in the lb/rigid/pc/sphere fix for atoms which do not interact with the lb/fluid"); // If inner nodes are present, which should not interact with the fluid, make // sure these are not used by the lb/fluid fix to apply a force to the fluid. if((mask[j] & groupbit) && (mask[j] & groupbit_lb_fluid) && (mask[j] & group->bitmask[igroupinner])) error->one(FLERR,"the inner nodes specified in lb/rigid/pc/sphere should not be included in the lb/fluid fix"); } }else{ for(int j=0; jone(FLERR,"use the innerNodes keyword in the lb/rigid/pc/sphere fix for atoms which do not interact with the lb/fluid"); } } } /* ---------------------------------------------------------------------- */ FixLbRigidPCSphere::~FixLbRigidPCSphere() { // unregister callbacks to this fix from Atom class atom->delete_callback(id,0); // delete locally stored arrays memory->destroy(body); memory->destroy(up); // delete nbody-length arrays memory->destroy(nrigid); memory->destroy(nrigid_shell); memory->destroy(masstotal); memory->destroy(masstotal_shell); memory->destroy(sphereradius); memory->destroy(xcm); memory->destroy(xcm_old); memory->destroy(vcm); memory->destroy(ucm); memory->destroy(ucm_old); memory->destroy(fcm); memory->destroy(fcm_old); memory->destroy(fcm_fluid); memory->destroy(omega); memory->destroy(torque); memory->destroy(torque_old); memory->destroy(torque_fluid); memory->destroy(torque_fluid_old); memory->destroy(rotate); memory->destroy(imagebody); memory->destroy(fflag); memory->destroy(tflag); memory->destroy(sum); memory->destroy(all); memory->destroy(remapflag); delete [] Gamma_MD; } /* ---------------------------------------------------------------------- */ int FixLbRigidPCSphere::setmask() { int mask = 0; mask |= INITIAL_INTEGRATE; mask |= FINAL_INTEGRATE; mask |= PRE_NEIGHBOR; return mask; } /* ---------------------------------------------------------------------- */ void FixLbRigidPCSphere::init() { int i,ibody; // warn if more than one rigid fix int count = 0; for (int i = 0; i < modify->nfix; i++) if (strcmp(modify->fix[i]->style,"lb/rigid/pc/sphere") == 0) count++; if (count > 1 && comm->me == 0) error->warning(FLERR,"More than one fix lb/rigid/pc/sphere"); // timestep info dtv = update->dt; dtf = 0.5 * update->dt * force->ftm2v; int *type = atom->type; int nlocal = atom->nlocal; double **x = atom->x; imageint *image = atom->image; double *rmass = atom->rmass; double *mass = atom->mass; int *periodicity = domain->periodicity; double xprd = domain->xprd; double yprd = domain->yprd; double zprd = domain->zprd; double **mu = atom->mu; double *radius = atom->radius; int *ellipsoid = atom->ellipsoid; int extended = 0; int *mask = atom->mask; // Warn if any extended particles are included. if (atom->radius_flag || atom->ellipsoid_flag || atom->mu_flag) { int flag = 0; for (i = 0; i < nlocal; i++) { if (body[i] < 0) continue; if (radius && radius[i] > 0.0) flag = 1; if (ellipsoid && ellipsoid[i] >= 0) flag = 1; if (mu && mu[i][3] > 0.0) flag = 1; } MPI_Allreduce(&flag,&extended,1,MPI_INT,MPI_MAX,world); } if(extended) error->warning(FLERR,"Fix lb/rigid/pc/sphere assumes point particles"); // compute masstotal & center-of-mass of each rigid body for (ibody = 0; ibody < nbody; ibody++) for (i = 0; i < 6; i++) sum[ibody][i] = 0.0; int xbox,ybox,zbox; double massone,xunwrap,yunwrap,zunwrap; for (i = 0; i < nlocal; i++) { if (body[i] < 0) continue; ibody = body[i]; xbox = (image[i] & IMGMASK) - IMGMAX; ybox = (image[i] >> IMGBITS & IMGMASK) - IMGMAX; zbox = (image[i] >> IMG2BITS) - IMGMAX; if (rmass) massone = rmass[i]; else massone = mass[type[i]]; if ((xbox && !periodicity[0]) || (ybox && !periodicity[1]) || (zbox && !periodicity[2])) error->one(FLERR,"Fix lb/rigid/pc/sphere atom has non-zero image flag " "in a non-periodic dimension"); xunwrap = x[i][0] + xbox*xprd; yunwrap = x[i][1] + ybox*yprd; zunwrap = x[i][2] + zbox*zprd; sum[ibody][0] += xunwrap * massone; sum[ibody][1] += yunwrap * massone; sum[ibody][2] += zunwrap * massone; sum[ibody][3] += massone; if(inner_nodes == 1){ if(!(mask[i] & group->bitmask[igroupinner])){ sum[ibody][4] += massone; } }else{ sum[ibody][4] += massone; } } MPI_Allreduce(sum[0],all[0],6*nbody,MPI_DOUBLE,MPI_SUM,world); for (ibody = 0; ibody < nbody; ibody++) { masstotal[ibody] = all[ibody][3]; masstotal_shell[ibody] = all[ibody][4]; xcm[ibody][0] = all[ibody][0]/masstotal[ibody]; xcm[ibody][1] = all[ibody][1]/masstotal[ibody]; xcm[ibody][2] = all[ibody][2]/masstotal[ibody]; } // Calculate the radius of the rigid body, and assign the value for gamma: double dx,dy,dz; double *Gamma = fix_lb_fluid->Gamma; double dm_lb = fix_lb_fluid->dm_lb; double dt_lb = fix_lb_fluid->dt_lb; for (ibody = 0; ibody < nbody; ibody++) for (i = 0; i < 6; i++) sum[ibody][i] = 0.0; for (i=0; ibitmask[igroupinner])){ ibody = body[i]; xbox = (image[i] & IMGMASK) - IMGMAX; ybox = (image[i] >> IMGBITS & IMGMASK) - IMGMAX; zbox = (image[i] >> IMG2BITS) - IMGMAX; xunwrap = x[i][0] + xbox*xprd; yunwrap = x[i][1] + ybox*yprd; zunwrap = x[i][2] + zbox*zprd; dx = xunwrap - xcm[ibody][0]; dy = yunwrap - xcm[ibody][1]; dz = zunwrap - xcm[ibody][2]; sum[ibody][0] += dx*dx + dy*dy + dz*dz; sum[ibody][1] += Gamma[type[i]]; } }else{ ibody = body[i]; xbox = (image[i] & IMGMASK) - IMGMAX; ybox = (image[i] >> IMGBITS & IMGMASK) - IMGMAX; zbox = (image[i] >> IMG2BITS) - IMGMAX; xunwrap = x[i][0] + xbox*xprd; yunwrap = x[i][1] + ybox*yprd; zunwrap = x[i][2] + zbox*zprd; dx = xunwrap - xcm[ibody][0]; dy = yunwrap - xcm[ibody][1]; dz = zunwrap - xcm[ibody][2]; sum[ibody][0] += dx*dx + dy*dy + dz*dz; sum[ibody][1] += Gamma[type[i]]; } } MPI_Allreduce(sum[0],all[0],6*nbody,MPI_DOUBLE,MPI_SUM,world); for(ibody=0; ibody < nbody; ibody++){ sphereradius[ibody] = sqrt(all[ibody][0]/nrigid_shell[ibody]); Gamma_MD[ibody] = all[ibody][1]*dm_lb/dt_lb/nrigid_shell[ibody]; } // Check that all atoms in the rigid body have the same value of gamma. double eps = 1.0e-7; for (i=0; ibitmask[igroupinner])){ ibody = body[i]; if(Gamma_MD[ibody]*dt_lb/dm_lb - Gamma[type[i]] > eps) error->one(FLERR,"All atoms in a rigid body must have the same gamma value"); } }else{ ibody = body[i]; if(Gamma_MD[ibody]*dt_lb/dm_lb - Gamma[type[i]] > eps) error->one(FLERR,"All atoms in a rigid body must have the same gamma value"); } } // remap the xcm of each body back into simulation box if needed // only really necessary the 1st time a run is performed pre_neighbor(); // temperature scale factor double ndof = 0.0; for (ibody = 0; ibody < nbody; ibody++) { ndof += fflag[ibody][0] + fflag[ibody][1] + fflag[ibody][2]; ndof += tflag[ibody][0] + tflag[ibody][1] + tflag[ibody][2]; } if (ndof > 0.0) tfactor = force->mvv2e / (ndof * force->boltz); else tfactor = 0.0; } /* ---------------------------------------------------------------------- */ void FixLbRigidPCSphere::setup(int vflag) { int i,n,ibody; double massone; // vcm = velocity of center-of-mass of each rigid body // fcm = force on center-of-mass of each rigid body double **x = atom->x; double **v = atom->v; double **f = atom->f; double *rmass = atom->rmass; double *mass = atom->mass; int *type = atom->type; int nlocal = atom->nlocal; imageint *image = atom->image; double unwrap[3]; double dx,dy,dz; for (ibody = 0; ibody < nbody; ibody++) for (i = 0; i < 6; i++) sum[ibody][i] = 0.0; for (i = 0; i < nlocal; i++) { if (body[i] < 0) continue; ibody = body[i]; if (rmass) massone = rmass[i]; else massone = mass[type[i]]; sum[ibody][0] += v[i][0] * massone; sum[ibody][1] += v[i][1] * massone; sum[ibody][2] += v[i][2] * massone; sum[ibody][3] += f[i][0]; sum[ibody][4] += f[i][1]; sum[ibody][5] += f[i][2]; } MPI_Allreduce(sum[0],all[0],6*nbody,MPI_DOUBLE,MPI_SUM,world); for (ibody = 0; ibody < nbody; ibody++) { vcm[ibody][0] = all[ibody][0]/masstotal[ibody]; vcm[ibody][1] = all[ibody][1]/masstotal[ibody]; vcm[ibody][2] = all[ibody][2]/masstotal[ibody]; fcm[ibody][0] = all[ibody][3]; fcm[ibody][1] = all[ibody][4]; fcm[ibody][2] = all[ibody][5]; } // omega = angular velocity of each rigid body // Calculated as the average of the angular velocities of the // individual atoms comprising the rigid body. // torque = torque on each rigid body for (ibody = 0; ibody < nbody; ibody++) for (i = 0; i < 6; i++) sum[ibody][i] = 0.0; for (i = 0; i < nlocal; i++) { if (body[i] < 0) continue; ibody = body[i]; domain->unmap(x[i],image[i],unwrap); dx = unwrap[0] - xcm[ibody][0]; dy = unwrap[1] - xcm[ibody][1]; dz = unwrap[2] - xcm[ibody][2]; if (rmass) massone = rmass[i]; else massone = mass[type[i]]; sum[ibody][0] += (dy * (v[i][2]-vcm[ibody][2]) - dz * (v[i][1]-vcm[ibody][1]))/(dx*dx+dy*dy+dz*dz); sum[ibody][1] += (dz * (v[i][0]-vcm[ibody][0]) - dx * (v[i][2]-vcm[ibody][2]))/(dx*dx+dy*dy+dz*dz); sum[ibody][2] += (dx * (v[i][1]-vcm[ibody][1]) - dy * (v[i][0]-vcm[ibody][0]))/(dx*dx+dy*dy+dz*dz); sum[ibody][3] += dy * f[i][2] - dz * f[i][1]; sum[ibody][4] += dz * f[i][0] - dx * f[i][2]; sum[ibody][5] += dx * f[i][1] - dy * f[i][0]; } MPI_Allreduce(sum[0],all[0],6*nbody,MPI_DOUBLE,MPI_SUM,world); for (ibody = 0; ibody < nbody; ibody++) { omega[ibody][0] = all[ibody][0]/nrigid[ibody]; omega[ibody][1] = all[ibody][1]/nrigid[ibody]; omega[ibody][2] = all[ibody][2]/nrigid[ibody]; torque[ibody][0] = all[ibody][3]; torque[ibody][1] = all[ibody][4]; torque[ibody][2] = all[ibody][5]; } // virial setup before call to set_v if (vflag) v_setup(vflag); else evflag = 0; // Set the velocities set_v(); if (vflag_global) for (n = 0; n < 6; n++) virial[n] *= 2.0; if (vflag_atom) { for (i = 0; i < nlocal; i++) for (n = 0; n < 6; n++) vatom[i][n] *= 2.0; } } /* ---------------------------------------------------------------------- */ void FixLbRigidPCSphere::initial_integrate(int vflag) { double dtfm; int i,ibody; double massone; double **x = atom->x; double **v = atom->v; double *rmass = atom->rmass; double *mass = atom->mass; int *type = atom->type; int nlocal = atom->nlocal; imageint *image = atom->image; double unwrap[3]; double dx,dy,dz; int *mask = atom->mask; // compute the fluid velocity at the initial particle positions compute_up(); for (ibody = 0; ibody < nbody; ibody++) for (i = 0; i < 6; i++) sum[ibody][i] = 0.0; // Store the fluid velocity at the center of mass for (i = 0; i < nlocal; i++) { if (body[i] < 0) continue; ibody = body[i]; if (rmass) massone = rmass[i]; else massone = mass[type[i]]; if(inner_nodes == 1){ if(!(mask[i] & group->bitmask[igroupinner])){ sum[ibody][0] += up[i][0]*massone; sum[ibody][1] += up[i][1]*massone; sum[ibody][2] += up[i][2]*massone; } }else{ sum[ibody][0] += up[i][0]*massone; sum[ibody][1] += up[i][1]*massone; sum[ibody][2] += up[i][2]*massone; } } MPI_Allreduce(sum[0],all[0],6*nbody,MPI_DOUBLE,MPI_SUM,world); for (ibody = 0; ibody < nbody; ibody++) { ucm[ibody][0] = all[ibody][0]/masstotal_shell[ibody]; ucm[ibody][1] = all[ibody][1]/masstotal_shell[ibody]; ucm[ibody][2] = all[ibody][2]/masstotal_shell[ibody]; } //Store the total torque due to the fluid. for (ibody = 0; ibody < nbody; ibody++) for(i = 0; i < 6; i++) sum[ibody][i] = 0.0; for(i = 0; iunmap(x[i],image[i],unwrap); dx = unwrap[0] - xcm[ibody][0]; dy = unwrap[1] - xcm[ibody][1]; dz = unwrap[2] - xcm[ibody][2]; if (rmass) massone = rmass[i]; else massone = mass[type[i]]; if(inner_nodes == 1){ if(!(mask[i] & group->bitmask[igroupinner])){ sum[ibody][0] += Gamma_MD[ibody]*(dy * ((up[i][2]-vcm[ibody][2])) - dz * ((up[i][1]-vcm[ibody][1]))); sum[ibody][1] += Gamma_MD[ibody]*(dz * ((up[i][0]-vcm[ibody][0])) - dx * ((up[i][2]-vcm[ibody][2]))); sum[ibody][2] += Gamma_MD[ibody]*(dx * ((up[i][1]-vcm[ibody][1])) - dy * ((up[i][0]-vcm[ibody][0]))); sum[ibody][3] += -Gamma_MD[ibody]*(v[i][0]-up[i][0]); sum[ibody][4] += -Gamma_MD[ibody]*(v[i][1]-up[i][1]); sum[ibody][5] += -Gamma_MD[ibody]*(v[i][2]-up[i][2]); } }else{ sum[ibody][0] += Gamma_MD[ibody]*(dy * ((up[i][2]-vcm[ibody][2])) - dz * ((up[i][1]-vcm[ibody][1]))); sum[ibody][1] += Gamma_MD[ibody]*(dz * ((up[i][0]-vcm[ibody][0])) - dx * ((up[i][2]-vcm[ibody][2]))); sum[ibody][2] += Gamma_MD[ibody]*(dx * ((up[i][1]-vcm[ibody][1])) - dy * ((up[i][0]-vcm[ibody][0]))); sum[ibody][3] += -Gamma_MD[ibody]*(v[i][0]-up[i][0]); sum[ibody][4] += -Gamma_MD[ibody]*(v[i][1]-up[i][1]); sum[ibody][5] += -Gamma_MD[ibody]*(v[i][2]-up[i][2]); } } MPI_Allreduce(sum[0],all[0],6*nbody,MPI_DOUBLE,MPI_SUM,world); for (ibody = 0; ibody < nbody; ibody++) { torque_fluid[ibody][0] = all[ibody][0]; torque_fluid[ibody][1] = all[ibody][1]; torque_fluid[ibody][2] = all[ibody][2]; fcm_fluid[ibody][0] = all[ibody][3]; fcm_fluid[ibody][1] = all[ibody][4]; fcm_fluid[ibody][2] = all[ibody][5]; } for (int ibody = 0; ibody < nbody; ibody++) { fcm_old[ibody][0] = fcm[ibody][0]; fcm_old[ibody][1] = fcm[ibody][1]; fcm_old[ibody][2] = fcm[ibody][2]; torque_old[ibody][0] = torque[ibody][0]; torque_old[ibody][1] = torque[ibody][1]; torque_old[ibody][2] = torque[ibody][2]; torque_fluid_old[ibody][0] = torque_fluid[ibody][0]; torque_fluid_old[ibody][1] = torque_fluid[ibody][1]; torque_fluid_old[ibody][2] = torque_fluid[ibody][2]; ucm_old[ibody][0] = ucm[ibody][0]; ucm_old[ibody][1] = ucm[ibody][1]; ucm_old[ibody][2] = ucm[ibody][2]; xcm_old[ibody][0] = xcm[ibody][0]; xcm_old[ibody][1] = xcm[ibody][1]; xcm_old[ibody][2] = xcm[ibody][2]; // update xcm by full step dtfm = dtf / masstotal[ibody]; xcm[ibody][0] += dtv * vcm[ibody][0]+(fcm[ibody][0]+fcm_fluid[ibody][0]/force->ftm2v)*fflag[ibody][0]*dtfm*dtv; xcm[ibody][1] += dtv * vcm[ibody][1]+(fcm[ibody][1]+fcm_fluid[ibody][1]/force->ftm2v)*fflag[ibody][1]*dtfm*dtv; xcm[ibody][2] += dtv * vcm[ibody][2]+(fcm[ibody][2]+fcm_fluid[ibody][2]/force->ftm2v)*fflag[ibody][2]*dtfm*dtv; rotate[ibody][0] = omega[ibody][0]*dtv + tflag[ibody][0]*(torque[ibody][0]*force->ftm2v+torque_fluid[ibody][0])* dtv*dtv*5.0/(4.0*masstotal[ibody]*sphereradius[ibody]*sphereradius[ibody]); rotate[ibody][1] = omega[ibody][1]*dtv + tflag[ibody][1]*(torque[ibody][1]*force->ftm2v+torque_fluid[ibody][1])* dtv*dtv*5.0/(4.0*masstotal[ibody]*sphereradius[ibody]*sphereradius[ibody]); rotate[ibody][2] = omega[ibody][2]*dtv + tflag[ibody][2]*(torque[ibody][2]*force->ftm2v+torque_fluid[ibody][2])* dtv*dtv*5.0/(4.0*masstotal[ibody]*sphereradius[ibody]*sphereradius[ibody]); // Approximate vcm expminusdttimesgamma = exp(-Gamma_MD[ibody]*dtv*nrigid_shell[ibody]/masstotal[ibody]); force_factor = force->ftm2v/Gamma_MD[ibody]/nrigid_shell[ibody]; if(fflag[ibody][0]==1){ vcm[ibody][0] = expminusdttimesgamma*(vcm[ibody][0] - ucm[ibody][0] - fcm[ibody][0]*force_factor) + ucm[ibody][0] + fcm[ibody][0]*force_factor; } if(fflag[ibody][1]==1){ vcm[ibody][1] = expminusdttimesgamma*(vcm[ibody][1] - ucm[ibody][1] - fcm[ibody][1]*force_factor) + ucm[ibody][1] + fcm[ibody][1]*force_factor; } if(fflag[ibody][2]==1){ vcm[ibody][2] = expminusdttimesgamma*(vcm[ibody][2] - ucm[ibody][2] - fcm[ibody][2]*force_factor) + ucm[ibody][2] + fcm[ibody][2]*force_factor; } // Approximate angmom torque_factor = 5.0*Gamma_MD[ibody]*nrigid_shell[ibody]/(3.0*masstotal[ibody]); expminusdttimesgamma = exp(-dtv*torque_factor); if(tflag[ibody][0]==1){ omega[ibody][0] = expminusdttimesgamma*(omega[ibody][0] - (3.0/(2.0*nrigid_shell[ibody]*sphereradius[ibody]*sphereradius[ibody]*Gamma_MD[ibody]))* (force->ftm2v*torque[ibody][0] + torque_fluid[ibody][0])) + (3.0/(2.0*nrigid_shell[ibody]*sphereradius[ibody]*sphereradius[ibody]*Gamma_MD[ibody]))* (force->ftm2v*torque[ibody][0] + torque_fluid[ibody][0]); } if(tflag[ibody][1]==1){ omega[ibody][1] = expminusdttimesgamma*(omega[ibody][1] - (3.0/(2.0*nrigid_shell[ibody]*sphereradius[ibody]*sphereradius[ibody]*Gamma_MD[ibody]))* (force->ftm2v*torque[ibody][1] + torque_fluid[ibody][1])) + (3.0/(2.0*nrigid_shell[ibody]*sphereradius[ibody]*sphereradius[ibody]*Gamma_MD[ibody]))* (force->ftm2v*torque[ibody][1] + torque_fluid[ibody][1]); } if(tflag[ibody][2]==1){ omega[ibody][2] = expminusdttimesgamma*(omega[ibody][2] - (3.0/(2.0*nrigid_shell[ibody]*sphereradius[ibody]*sphereradius[ibody]*Gamma_MD[ibody]))* (force->ftm2v*torque[ibody][2] + torque_fluid[ibody][2])) + (3.0/(2.0*nrigid_shell[ibody]*sphereradius[ibody]*sphereradius[ibody]*Gamma_MD[ibody]))* (force->ftm2v*torque[ibody][2] + torque_fluid[ibody][2]); } } // virial setup before call to set_xv if (vflag) v_setup(vflag); else evflag = 0; set_xv(); } /* ---------------------------------------------------------------------- */ void FixLbRigidPCSphere::final_integrate() { int i,ibody; // sum over atoms to get force and torque on rigid body double massone; imageint *image = atom->image; double **x = atom->x; double **f = atom->f; double *rmass = atom->rmass; double *mass = atom->mass; int *type = atom->type; int nlocal = atom->nlocal; double unwrap[3]; double dx,dy,dz; int *mask = atom->mask; for (ibody = 0; ibody < nbody; ibody++) for (i = 0; i < 6; i++) sum[ibody][i] = 0.0; for (i = 0; i < nlocal; i++) { if (body[i] < 0) continue; ibody = body[i]; sum[ibody][0] += f[i][0]; sum[ibody][1] += f[i][1]; sum[ibody][2] += f[i][2]; domain->unmap(x[i],image[i],unwrap); dx = unwrap[0] - xcm[ibody][0]; dy = unwrap[1] - xcm[ibody][1]; dz = unwrap[2] - xcm[ibody][2]; sum[ibody][3] += dy*f[i][2] - dz*f[i][1]; sum[ibody][4] += dz*f[i][0] - dx*f[i][2]; sum[ibody][5] += dx*f[i][1] - dy*f[i][0]; } MPI_Allreduce(sum[0],all[0],6*nbody,MPI_DOUBLE,MPI_SUM,world); //Compute the correction to the velocity and angular momentum due to the non-fluid forces: for (ibody = 0; ibody < nbody; ibody++) { fcm[ibody][0] = all[ibody][0]; fcm[ibody][1] = all[ibody][1]; fcm[ibody][2] = all[ibody][2]; torque[ibody][0] = all[ibody][3]; torque[ibody][1] = all[ibody][4]; torque[ibody][2] = all[ibody][5]; expminusdttimesgamma = exp(-dtv*Gamma_MD[ibody]*nrigid_shell[ibody]/masstotal[ibody]); DMDcoeff= (dtv - (masstotal[ibody]/nrigid_shell[ibody])*(1.0-expminusdttimesgamma)/Gamma_MD[ibody]); vcm[ibody][0] += fflag[ibody][0]*DMDcoeff*force->ftm2v*(fcm[ibody][0]-fcm_old[ibody][0])/Gamma_MD[ibody]/dtv/nrigid_shell[ibody]; vcm[ibody][1] += fflag[ibody][1]*DMDcoeff*force->ftm2v*(fcm[ibody][1]-fcm_old[ibody][1])/Gamma_MD[ibody]/dtv/nrigid_shell[ibody]; vcm[ibody][2] += fflag[ibody][2]*DMDcoeff*force->ftm2v*(fcm[ibody][2]-fcm_old[ibody][2])/Gamma_MD[ibody]/dtv/nrigid_shell[ibody]; torque_factor = 5.0*Gamma_MD[ibody]*nrigid_shell[ibody]/(3.0*masstotal[ibody]); expminusdttimesgamma = exp(-dtv*torque_factor); DMDcoeff = (dtv - (1.0-expminusdttimesgamma)/torque_factor); omega[ibody][0] += tflag[ibody][0]*(3.0/(2.0*nrigid_shell[ibody]*sphereradius[ibody]*sphereradius[ibody]*Gamma_MD[ibody]))*DMDcoeff* force->ftm2v*(torque[ibody][0] - torque_old[ibody][0])/dtv; omega[ibody][1] += tflag[ibody][1]*(3.0/(2.0*nrigid_shell[ibody]*sphereradius[ibody]*sphereradius[ibody]*Gamma_MD[ibody]))*DMDcoeff* force->ftm2v*(torque[ibody][1] - torque_old[ibody][1])/dtv; omega[ibody][2] += tflag[ibody][2]*(3.0/(2.0*nrigid_shell[ibody]*sphereradius[ibody]*sphereradius[ibody]*Gamma_MD[ibody]))*DMDcoeff* force->ftm2v*(torque[ibody][2] - torque_old[ibody][2])/dtv; } //Next, calculate the correction to the velocity and angular momentum due to the fluid forces: //Calculate the fluid velocity at the new particle locations. compute_up(); // store fluid quantities for the total body for (ibody = 0; ibody < nbody; ibody++) for (i = 0; i < 6; i++) sum[ibody][i] = 0.0; // Store the fluid velocity at the center of mass, and the total force // due to the fluid. for (i = 0; i < nlocal; i++) { if (body[i] < 0) continue; ibody = body[i]; if (rmass) massone = rmass[i]; else massone = mass[type[i]]; domain->unmap(x[i],image[i],unwrap); dx = unwrap[0] - xcm[ibody][0]; dy = unwrap[1] - xcm[ibody][1]; dz = unwrap[2] - xcm[ibody][2]; if(inner_nodes == 1){ if(!(mask[i] & group->bitmask[igroupinner])){ sum[ibody][0] += up[i][0]*massone; sum[ibody][1] += up[i][1]*massone; sum[ibody][2] += up[i][2]*massone; sum[ibody][3] += Gamma_MD[ibody]*(dy * ((up[i][2]-vcm[ibody][2])) - dz * ((up[i][1]-vcm[ibody][1]))); sum[ibody][4] += Gamma_MD[ibody]*(dz * ((up[i][0]-vcm[ibody][0])) - dx * ((up[i][2]-vcm[ibody][2]))); sum[ibody][5] += Gamma_MD[ibody]*(dx * ((up[i][1]-vcm[ibody][1])) - dy * ((up[i][0]-vcm[ibody][0]))); } }else{ sum[ibody][0] += up[i][0]*massone; sum[ibody][1] += up[i][1]*massone; sum[ibody][2] += up[i][2]*massone; sum[ibody][3] += Gamma_MD[ibody]*(dy * ((up[i][2]-vcm[ibody][2])) - dz * ((up[i][1]-vcm[ibody][1]))); sum[ibody][4] += Gamma_MD[ibody]*(dz * ((up[i][0]-vcm[ibody][0])) - dx * ((up[i][2]-vcm[ibody][2]))); sum[ibody][5] += Gamma_MD[ibody]*(dx * ((up[i][1]-vcm[ibody][1])) - dy * ((up[i][0]-vcm[ibody][0]))); } } MPI_Allreduce(sum[0],all[0],6*nbody,MPI_DOUBLE,MPI_SUM,world); for (ibody = 0; ibody < nbody; ibody++) { ucm[ibody][0] = all[ibody][0]/masstotal_shell[ibody]; ucm[ibody][1] = all[ibody][1]/masstotal_shell[ibody]; ucm[ibody][2] = all[ibody][2]/masstotal_shell[ibody]; torque_fluid[ibody][0] = all[ibody][3]; torque_fluid[ibody][1] = all[ibody][4]; torque_fluid[ibody][2] = all[ibody][5]; } for (ibody = 0; ibody < nbody; ibody++) { expminusdttimesgamma = exp(-dtv*Gamma_MD[ibody]*nrigid_shell[ibody]/masstotal[ibody]); DMDcoeff= (dtv - (masstotal[ibody]/nrigid_shell[ibody])*(1.0-expminusdttimesgamma)/Gamma_MD[ibody]); vcm[ibody][0] += DMDcoeff*fflag[ibody][0]*(ucm[ibody][0]-ucm_old[ibody][0])/dtv; vcm[ibody][1] += DMDcoeff*fflag[ibody][1]*(ucm[ibody][1]-ucm_old[ibody][1])/dtv; vcm[ibody][2] += DMDcoeff*fflag[ibody][2]*(ucm[ibody][2]-ucm_old[ibody][2])/dtv; torque_factor = 5.0*Gamma_MD[ibody]*nrigid_shell[ibody]/(3.0*masstotal[ibody]); expminusdttimesgamma = exp(-dtv*torque_factor); DMDcoeff = (dtv - (1.0-expminusdttimesgamma)/torque_factor); omega[ibody][0] += tflag[ibody][0]*(3.0/(2.0*nrigid_shell[ibody]*sphereradius[ibody]*sphereradius[ibody]*Gamma_MD[ibody]))* DMDcoeff*(torque_fluid[ibody][0] - torque_fluid_old[ibody][0])/dtv; omega[ibody][1] += tflag[ibody][1]*(3.0/(2.0*nrigid_shell[ibody]*sphereradius[ibody]*sphereradius[ibody]*Gamma_MD[ibody]))* DMDcoeff*(torque_fluid[ibody][1] - torque_fluid_old[ibody][1])/dtv; omega[ibody][2] += tflag[ibody][2]*(3.0/(2.0*nrigid_shell[ibody]*sphereradius[ibody]*sphereradius[ibody]*Gamma_MD[ibody]))* DMDcoeff*(torque_fluid[ibody][2] - torque_fluid_old[ibody][2])/dtv; } set_v(); } /* ---------------------------------------------------------------------- set space-frame velocity of each atom in a rigid body set omega and angmom of extended particles v = Vcm + (W cross (x - Xcm)) ------------------------------------------------------------------------- */ void FixLbRigidPCSphere::set_v() { int ibody; int xbox,ybox,zbox; double dx,dy,dz; double x0,x1,x2,v0,v1,v2,fc0,fc1,fc2,massone; double vr[6]; double **x = atom->x; double **v = atom->v; double **f = atom->f; double *rmass = atom->rmass; double *mass = atom->mass; int *type = atom->type; imageint *image = atom->image; int nlocal = atom->nlocal; double xprd = domain->xprd; double yprd = domain->yprd; double zprd = domain->zprd; double xunwrap,yunwrap,zunwrap; // set v of each atom for (int i = 0; i < nlocal; i++) { if (body[i] < 0) continue; ibody = body[i]; xbox = (image[i] & IMGMASK) - IMGMAX; ybox = (image[i] >> IMGBITS & IMGMASK) - IMGMAX; zbox = (image[i] >> IMG2BITS) - IMGMAX; xunwrap = x[i][0] + xbox*xprd; yunwrap = x[i][1] + ybox*yprd; zunwrap = x[i][2] + zbox*zprd; dx = xunwrap - xcm[ibody][0]; dy = yunwrap - xcm[ibody][1]; dz = zunwrap - xcm[ibody][2]; // save old velocities for virial. if(evflag){ v0 = v[i][0]; v1 = v[i][1]; v2 = v[i][2]; } v[i][0] = (omega[ibody][1]*dz - omega[ibody][2]*dy) + vcm[ibody][0]; v[i][1] = (omega[ibody][2]*dx - omega[ibody][0]*dz) + vcm[ibody][1]; v[i][2] = (omega[ibody][0]*dy - omega[ibody][1]*dx) + vcm[ibody][2]; // virial = unwrapped coords dotted into body constraint force // body constraint force = implied force due to v change minus f external // assume f does not include forces internal to body // 1/2 factor b/c initial_integrate contributes other half // assume per-atom contribution is due to constraint force on that atom if (evflag) { if (rmass) massone = rmass[i]; else massone = mass[type[i]]; fc0 = massone*(v[i][0] - v0)/dtf - f[i][0] + Gamma_MD[ibody]*(v0-up[i][0]); fc1 = massone*(v[i][1] - v1)/dtf - f[i][1] + Gamma_MD[ibody]*(v1-up[i][1]); fc2 = massone*(v[i][2] - v2)/dtf - f[i][2] + Gamma_MD[ibody]*(v2-up[i][2]); xbox = (image[i] & IMGMASK) - IMGMAX; ybox = (image[i] >> IMGBITS & IMGMASK) - IMGMAX; zbox = (image[i] >> IMG2BITS) - IMGMAX; x0 = x[i][0] + xbox*xprd; x1 = x[i][1] + ybox*yprd; x2 = x[i][2] + zbox*zprd; vr[0] = 0.5*x0*fc0; vr[1] = 0.5*x1*fc1; vr[2] = 0.5*x2*fc2; vr[3] = 0.5*x0*fc1; vr[4] = 0.5*x0*fc2; vr[5] = 0.5*x1*fc2; v_tally(1,&i,1.0,vr); } } } /* ---------------------------------------------------------------------- set space-frame coords and velocity of each atom in each rigid body set orientation and rotation of extended particles x = Q displace + Xcm, mapped back to periodic box v = Vcm + (W cross (x - Xcm)) ------------------------------------------------------------------------- */ void FixLbRigidPCSphere::set_xv() { int ibody; int xbox,ybox,zbox; double x0,x1,x2,v0,v1,v2,fc0,fc1,fc2,massone; double vr[6]; double **x = atom->x; double **v = atom->v; double **f = atom->f; double *rmass = atom->rmass; double *mass = atom->mass; int *type = atom->type; imageint *image = atom->image; int nlocal = atom->nlocal; double xprd = domain->xprd; double yprd = domain->yprd; double zprd = domain->zprd; double xunwrap,yunwrap,zunwrap; double dx,dy,dz; // set x and v of each atom for (int i = 0; i < nlocal; i++) { if (body[i] < 0) continue; ibody = body[i]; xbox = (image[i] & IMGMASK) - IMGMAX; ybox = (image[i] >> IMGBITS & IMGMASK) - IMGMAX; zbox = (image[i] >> IMG2BITS) - IMGMAX; xunwrap = x[i][0] + xbox*xprd; yunwrap = x[i][1] + ybox*yprd; zunwrap = x[i][2] + zbox*zprd; dx = xunwrap - xcm_old[ibody][0]; dy = yunwrap - xcm_old[ibody][1]; dz = zunwrap - xcm_old[ibody][2]; // save old positions and velocities for virial if(evflag){ x0 = xunwrap; x1 = yunwrap; x2 = zunwrap; v0 = v[i][0]; v1 = v[i][1]; v2 = v[i][2]; } // x = displacement from center-of-mass, based on body orientation // v = vcm + omega around center-of-mass x[i][0] = dx; x[i][1] = dy; x[i][2] = dz; //Perform the rotations: dx = x[i][0]; dy = x[i][1]; dz = x[i][2]; x[i][0] = cos(rotate[ibody][2])*dx - sin(rotate[ibody][2])*dy; x[i][1] = sin(rotate[ibody][2])*dx + cos(rotate[ibody][2])*dy; dx = x[i][0]; dy = x[i][1]; dz = x[i][2]; x[i][0] = cos(rotate[ibody][1])*dx + sin(rotate[ibody][1])*dz; x[i][2] = -sin(rotate[ibody][1])*dx + cos(rotate[ibody][1])*dz; dx = x[i][0]; dy = x[i][1]; dz = x[i][2]; x[i][1] = cos(rotate[ibody][0])*dy - sin(rotate[ibody][0])*dz; x[i][2] = sin(rotate[ibody][0])*dy + cos(rotate[ibody][0])*dz; v[i][0] = (omega[ibody][1]*x[i][2] - omega[ibody][2]*x[i][1]) + vcm[ibody][0]; v[i][1] = (omega[ibody][2]*x[i][0] - omega[ibody][0]*x[i][2]) + vcm[ibody][1]; v[i][2] = (omega[ibody][0]*x[i][1] - omega[ibody][1]*x[i][0]) + vcm[ibody][2]; // add center of mass to displacement // map back into periodic box via xbox,ybox,zbox // for triclinic, add in box tilt factors as well x[i][0] += xcm[ibody][0] - xbox*xprd; x[i][1] += xcm[ibody][1] - ybox*yprd; x[i][2] += xcm[ibody][2] - zbox*zprd; // virial = unwrapped coords dotted into body constraint force // body constraint force = implied force due to v change minus f external // assume f does not include forces internal to body // 1/2 factor b/c final_integrate contributes other half // assume per-atom contribution is due to constraint force on that atom if (evflag) { if (rmass) massone = rmass[i]; else massone = mass[type[i]]; fc0 = massone*(v[i][0] - v0)/dtf - f[i][0] + Gamma_MD[ibody]*(v0-up[i][0]); fc1 = massone*(v[i][1] - v1)/dtf - f[i][1] + Gamma_MD[ibody]*(v1-up[i][1]); fc2 = massone*(v[i][2] - v2)/dtf - f[i][2] + Gamma_MD[ibody]*(v2-up[i][2]); vr[0] = 0.5*x0*fc0; vr[1] = 0.5*x1*fc1; vr[2] = 0.5*x2*fc2; vr[3] = 0.5*x0*fc1; vr[4] = 0.5*x0*fc2; vr[5] = 0.5*x1*fc2; v_tally(1,&i,1.0,vr); } } } /* ---------------------------------------------------------------------- remap xcm of each rigid body back into periodic simulation box done during pre_neighbor so will be after call to pbc() and after fix_deform::pre_exchange() may have flipped box use domain->remap() in case xcm is far away from box due to 1st definition of rigid body or due to box flip if don't do this, then atoms of a body which drifts far away from a triclinic box will be remapped back into box with huge displacements when the box tilt changes via set_x() ------------------------------------------------------------------------- */ void FixLbRigidPCSphere::pre_neighbor() { imageint original,oldimage,newimage; for (int ibody = 0; ibody < nbody; ibody++) { original = imagebody[ibody]; domain->remap(xcm[ibody],imagebody[ibody]); if (original == imagebody[ibody]) remapflag[ibody][3] = 0; else { oldimage = original & IMGMASK; newimage = imagebody[ibody] & IMGMASK; remapflag[ibody][0] = newimage - oldimage; oldimage = (original >> IMGBITS) & IMGMASK; newimage = (imagebody[ibody] >> IMGBITS) & IMGMASK; remapflag[ibody][1] = newimage - oldimage; oldimage = original >> IMG2BITS; newimage = imagebody[ibody] >> IMG2BITS; remapflag[ibody][2] = newimage - oldimage; remapflag[ibody][3] = 1; } } // adjust image flags of any atom in a rigid body whose xcm was remapped imageint *atomimage = atom->image; int nlocal = atom->nlocal; int ibody; imageint idim,otherdims; for (int i = 0; i < nlocal; i++) { if (body[i] == -1) continue; if (remapflag[body[i]][3] == 0) continue; ibody = body[i]; if (remapflag[ibody][0]) { idim = atomimage[i] & IMGMASK; otherdims = atomimage[i] ^ idim; idim -= remapflag[ibody][0]; idim &= IMGMASK; atomimage[i] = otherdims | idim; } if (remapflag[ibody][1]) { idim = (atomimage[i] >> IMGBITS) & IMGMASK; otherdims = atomimage[i] ^ (idim << IMGBITS); idim -= remapflag[ibody][1]; idim &= IMGMASK; atomimage[i] = otherdims | (idim << IMGBITS); } if (remapflag[ibody][2]) { idim = atomimage[i] >> IMG2BITS; otherdims = atomimage[i] ^ (idim << IMG2BITS); idim -= remapflag[ibody][2]; idim &= IMGMASK; atomimage[i] = otherdims | (idim << IMG2BITS); } } } /* ---------------------------------------------------------------------- count # of degrees-of-freedom removed by fix_rigid for atoms in igroup ------------------------------------------------------------------------- */ int FixLbRigidPCSphere::dof(int igroup) { int groupbit = group->bitmask[igroup]; // ncount = # of atoms in each rigid body that are also in group int *mask = atom->mask; int nlocal = atom->nlocal; int *ncount = new int[nbody]; for (int ibody = 0; ibody < nbody; ibody++) ncount[ibody] = 0; for (int i = 0; i < nlocal; i++) if (body[i] >= 0 && mask[i] & groupbit) ncount[body[i]]++; int *nall = new int[nbody]; MPI_Allreduce(ncount,nall,nbody,MPI_INT,MPI_SUM,world); // remove 3N - 6 dof for each rigid body if more than 2 atoms in igroup // remove 3N - 5 dof for each diatomic rigid body in igroup int n = 0; for (int ibody = 0; ibody < nbody; ibody++) { if (nall[ibody] > 2) n += 3*nall[ibody] - 6; else if (nall[ibody] == 2) n++; } delete [] ncount; delete [] nall; return n; } /* ---------------------------------------------------------------------- memory usage of local atom-based arrays ------------------------------------------------------------------------- */ double FixLbRigidPCSphere::memory_usage() { int nmax = atom->nmax; double bytes = nmax * sizeof(int); bytes += nmax*3 * sizeof(double); bytes += maxvatom*6 * sizeof(double); return bytes; } /* ---------------------------------------------------------------------- allocate local atom-based arrays ------------------------------------------------------------------------- */ void FixLbRigidPCSphere::grow_arrays(int nmax) { memory->grow(body,nmax,"rigid:body"); memory->grow(up,nmax,3,"rigid:up"); } /* ---------------------------------------------------------------------- copy values within local atom-based arrays ------------------------------------------------------------------------- */ void FixLbRigidPCSphere::copy_arrays(int i, int j, int delflag) { body[j] = body[i]; up[j][0] = up[i][0]; up[j][1] = up[i][1]; up[j][2] = up[i][2]; } /* ---------------------------------------------------------------------- initialize one atom's array values, called when atom is created ------------------------------------------------------------------------- */ void FixLbRigidPCSphere::set_arrays(int i) { body[i] = -1; up[i][0] = 0.0; up[i][1] = 0.0; up[i][2] = 0.0; } /* ---------------------------------------------------------------------- pack values in local atom-based arrays for exchange with another proc ------------------------------------------------------------------------- */ int FixLbRigidPCSphere::pack_exchange(int i, double *buf) { buf[0] = body[i]; buf[1] = up[i][0]; buf[2] = up[i][1]; buf[3] = up[i][2]; return 4; } /* ---------------------------------------------------------------------- unpack values in local atom-based arrays from exchange with another proc ------------------------------------------------------------------------- */ int FixLbRigidPCSphere::unpack_exchange(int nlocal, double *buf) { body[nlocal] = static_cast (buf[0]); up[nlocal][0] = buf[1]; up[nlocal][1] = buf[2]; up[nlocal][2] = buf[3]; return 4; } /* ---------------------------------------------------------------------- */ void FixLbRigidPCSphere::reset_dt() { dtv = update->dt; dtf = 0.5 * update->dt * force->ftm2v; } /* ---------------------------------------------------------------------- return temperature of collection of rigid bodies non-active DOF are removed by fflag/tflag and in tfactor ------------------------------------------------------------------------- */ double FixLbRigidPCSphere::compute_scalar() { double inertia; double t = 0.0; for (int i = 0; i < nbody; i++) { t += masstotal[i] * (fflag[i][0]*vcm[i][0]*vcm[i][0] + fflag[i][1]*vcm[i][1]*vcm[i][1] + \ fflag[i][2]*vcm[i][2]*vcm[i][2]); // wbody = angular velocity in body frame inertia = 2.0*masstotal[i]*sphereradius[i]*sphereradius[i]/5.0; t += tflag[i][0]*inertia*omega[i][0]*omega[i][0] + tflag[i][1]*inertia*omega[i][1]*omega[i][1] + tflag[i][2]*inertia*omega[i][2]*omega[i][2]; } t *= tfactor; return t; } /* ---------------------------------------------------------------------- return attributes of a rigid body 15 values per body xcm = 0,1,2; vcm = 3,4,5; fcm = 6,7,8; torque = 9,10,11; image = 12,13,14 ------------------------------------------------------------------------- */ double FixLbRigidPCSphere::compute_array(int i, int j) { if (j < 3) return xcm[i][j]; if (j < 6) return vcm[i][j-3]; if (j < 9) return (fcm[i][j-6]+fcm_fluid[i][j-6]); if (j < 12) return (torque[i][j-9]+torque_fluid[i][j-9]); if (j == 12) return (imagebody[i] & IMGMASK) - IMGMAX; if (j == 13) return (imagebody[i] >> IMGBITS & IMGMASK) - IMGMAX; return (imagebody[i] >> IMG2BITS) - IMGMAX; } /* ---------------------------------------------------------------------- */ void FixLbRigidPCSphere::compute_up(void) { int *mask = atom->mask; int nlocal = atom->nlocal; double **x = atom->x; int i,k; int ix,iy,iz; int ixp,iyp,izp; double dx1,dy1,dz1; int isten,ii,jj,kk; double r,rsq,weightx,weighty,weightz; double ****u_lb = fix_lb_fluid->u_lb; int subNbx = fix_lb_fluid->subNbx; int subNby = fix_lb_fluid->subNby; int subNbz = fix_lb_fluid->subNbz; double dx_lb = fix_lb_fluid->dx_lb; double dt_lb = fix_lb_fluid->dt_lb; int trilinear_stencil = fix_lb_fluid->trilinear_stencil; double FfP[64]; for(i=0; isublo[0])/dx_lb); iy = (int)ceil((x[i][1]-domain->sublo[1])/dx_lb); iz = (int)ceil((x[i][2]-domain->sublo[2])/dx_lb); //Calculate distances to the nearest points. dx1 = x[i][0] - (domain->sublo[0] + (ix-1)*dx_lb); dy1 = x[i][1] - (domain->sublo[1] + (iy-1)*dx_lb); dz1 = x[i][2] - (domain->sublo[2] + (iz-1)*dx_lb); // Need to convert these to lattice units: dx1 = dx1/dx_lb; dy1 = dy1/dx_lb; dz1 = dz1/dx_lb; up[i][0]=0.0; up[i][1]=0.0; up[i][2]=0.0; if(trilinear_stencil==0){ isten=0; for(ii=-1; ii<3; ii++){ rsq=(-dx1+ii)*(-dx1+ii); if(rsq>=4) weightx=0.0; else{ r=sqrt(rsq); if(rsq>1){ weightx=(5.0-2.0*r-sqrt(-7.0+12.0*r-4.0*rsq))/8.; } else{ weightx=(3.0-2.0*r+sqrt(1.0+4.0*r-4.0*rsq))/8.; } } for(jj=-1; jj<3; jj++){ rsq=(-dy1+jj)*(-dy1+jj); if(rsq>=4) weighty=0.0; else{ r=sqrt(rsq); if(rsq>1){ weighty=(5.0-2.0*r-sqrt(-7.0+12.0*r-4.0*rsq))/8.; } else{ weighty=(3.0-2.0*r+sqrt(1.0+4.0*r-4.0*rsq))/8.; } } for(kk=-1; kk<3; kk++){ rsq=(-dz1+kk)*(-dz1+kk); if(rsq>=4) weightz=0.0; else{ r=sqrt(rsq); if(rsq>1){ weightz=(5.0-2.0*r-sqrt(-7.0+12.0*r-4.0*rsq))/8.; } else{ weightz=(3.0-2.0*r+sqrt(1.0+4.0*r-4.0*rsq))/8.; } } ixp = ix+ii; iyp = iy+jj; izp = iz+kk; if(ixp==-1) ixp=subNbx+2; if(iyp==-1) iyp=subNby+2; if(izp==-1) izp=subNbz+2; FfP[isten] = weightx*weighty*weightz; // interpolated velocity based on delta function. for(k=0; k<3; k++){ up[i][k] += u_lb[ixp][iyp][izp][k]*FfP[isten]; } } } } }else{ FfP[0] = (1.-dx1)*(1.-dy1)*(1.-dz1); FfP[1] = (1.-dx1)*(1.-dy1)*dz1; FfP[2] = (1.-dx1)*dy1*(1.-dz1); FfP[3] = (1.-dx1)*dy1*dz1; FfP[4] = dx1*(1.-dy1)*(1.-dz1); FfP[5] = dx1*(1.-dy1)*dz1; FfP[6] = dx1*dy1*(1.-dz1); FfP[7] = dx1*dy1*dz1; ixp = (ix+1); iyp = (iy+1); izp = (iz+1); for (k=0; k<3; k++) { // tri-linearly interpolated velocity at node up[i][k] = u_lb[ix][iy][iz][k]*FfP[0] + u_lb[ix][iy][izp][k]*FfP[1] + u_lb[ix][iyp][iz][k]*FfP[2] + u_lb[ix][iyp][izp][k]*FfP[3] + u_lb[ixp][iy][iz][k]*FfP[4] + u_lb[ixp][iy][izp][k]*FfP[5] + u_lb[ixp][iyp][iz][k]*FfP[6] + u_lb[ixp][iyp][izp][k]*FfP[7]; } } for(k=0; k<3; k++) up[i][k] = up[i][k]*dx_lb/dt_lb; } } } diff --git a/src/USER-MISC/angle_cosine_shift.cpp b/src/USER-MISC/angle_cosine_shift.cpp index 8e7c67fd7..66f5c82c8 100644 --- a/src/USER-MISC/angle_cosine_shift.cpp +++ b/src/USER-MISC/angle_cosine_shift.cpp @@ -1,273 +1,273 @@ /* ---------------------------------------------------------------------- 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: Carsten Svaneborg, science@zqex.dk ------------------------------------------------------------------------- */ #include #include #include "angle_cosine_shift.h" #include "atom.h" #include "neighbor.h" #include "domain.h" #include "comm.h" #include "force.h" #include "math_const.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace MathConst; #define SMALL 0.001 /* ---------------------------------------------------------------------- */ AngleCosineShift::AngleCosineShift(LAMMPS *lmp) : Angle(lmp) {} /* ---------------------------------------------------------------------- */ AngleCosineShift::~AngleCosineShift() { if (allocated) { memory->destroy(setflag); memory->destroy(k); memory->destroy(kcost); memory->destroy(ksint); memory->destroy(theta); } } /* ---------------------------------------------------------------------- */ void AngleCosineShift::compute(int eflag, int vflag) { int i1,i2,i3,n,type; double delx1,dely1,delz1,delx2,dely2,delz2; double eangle,f1[3],f3[3]; double rsq1,rsq2,r1,r2,c,s,cps,kcos,ksin,a11,a12,a22; eangle = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; int **anglelist = neighbor->anglelist; int nanglelist = neighbor->nanglelist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < nanglelist; n++) { i1 = anglelist[n][0]; i2 = anglelist[n][1]; i3 = anglelist[n][2]; type = anglelist[n][3]; // 1st bond delx1 = x[i1][0] - x[i2][0]; dely1 = x[i1][1] - x[i2][1]; delz1 = x[i1][2] - x[i2][2]; rsq1 = delx1*delx1 + dely1*dely1 + delz1*delz1; r1 = sqrt(rsq1); // 2nd bond delx2 = x[i3][0] - x[i2][0]; dely2 = x[i3][1] - x[i2][1]; delz2 = x[i3][2] - x[i2][2]; rsq2 = delx2*delx2 + dely2*dely2 + delz2*delz2; r2 = sqrt(rsq2); // c = cosine of angle c = delx1*delx2 + dely1*dely2 + delz1*delz2; c /= r1*r2; if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; // C= sine of angle s = sqrt(1.0 - c*c); if (s < SMALL) s = SMALL; // force & energy kcos=kcost[type]; ksin=ksint[type]; if (eflag) eangle = -k[type]-kcos*c-ksin*s; cps = c/s; // NOTE absorbed one c a11 = (-kcos +ksin*cps )*c/ rsq1; a12 = ( kcos -ksin*cps ) / (r1*r2); a22 = (-kcos +ksin*cps )*c/ rsq2; f1[0] = a11*delx1 + a12*delx2; f1[1] = a11*dely1 + a12*dely2; f1[2] = a11*delz1 + a12*delz2; f3[0] = a22*delx2 + a12*delx1; f3[1] = a22*dely2 + a12*dely1; f3[2] = a22*delz2 + a12*delz1; // apply force to each of 3 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += f1[0]; f[i1][1] += f1[1]; f[i1][2] += f1[2]; } if (newton_bond || i2 < nlocal) { f[i2][0] -= f1[0] + f3[0]; f[i2][1] -= f1[1] + f3[1]; f[i2][2] -= f1[2] + f3[2]; } if (newton_bond || i3 < nlocal) { f[i3][0] += f3[0]; f[i3][1] += f3[1]; f[i3][2] += f3[2]; } if (evflag) ev_tally(i1,i2,i3,nlocal,newton_bond,eangle,f1,f3, delx1,dely1,delz1,delx2,dely2,delz2); } } /* ---------------------------------------------------------------------- */ void AngleCosineShift::allocate() { allocated = 1; int n = atom->nangletypes; memory->create(k ,n+1,"Angle:k"); memory->create(ksint ,n+1,"Angle:ksint"); memory->create(kcost ,n+1,"Angle:kcost"); memory->create(theta ,n+1,"Angle:theta"); memory->create(setflag,n+1, "Angle:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one type ------------------------------------------------------------------------- */ void AngleCosineShift::coeff(int narg, char **arg) { if (narg != 3) error->all(FLERR,"Incorrect args for angle coefficients"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->nangletypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->nangletypes,ilo,ihi); double umin = force->numeric(FLERR,arg[1]); double theta0 = force->numeric(FLERR,arg[2]); // k=Umin/2 int count = 0; for (int i = ilo; i <= ihi; i++) { k[i] = umin/2; kcost[i] = umin/2*cos(theta0*MY_PI / 180.0); ksint[i] = umin/2*sin(theta0*MY_PI / 180.0); theta[i] = theta0*MY_PI / 180.0; setflag[i] = 1; count++; } if (count == 0) error->all(FLERR,"Incorrect args for angle coefficients"); } /* ---------------------------------------------------------------------- */ double AngleCosineShift::equilibrium_angle(int i) { return theta[i]; } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void AngleCosineShift::write_restart(FILE *fp) { fwrite(&k[1],sizeof(double),atom->nangletypes,fp); fwrite(&kcost[1],sizeof(double),atom->nangletypes,fp); fwrite(&ksint[1],sizeof(double),atom->nangletypes,fp); fwrite(&theta[1],sizeof(double),atom->nangletypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void AngleCosineShift::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&k[1],sizeof(double),atom->nangletypes,fp); fread(&kcost[1],sizeof(double),atom->nangletypes,fp); fread(&ksint[1],sizeof(double),atom->nangletypes,fp); fread(&theta[1],sizeof(double),atom->nangletypes,fp); } MPI_Bcast(&k[1],atom->nangletypes,MPI_DOUBLE,0,world); MPI_Bcast(&kcost[1],atom->nangletypes,MPI_DOUBLE,0,world); MPI_Bcast(&ksint[1],atom->nangletypes,MPI_DOUBLE,0,world); MPI_Bcast(&theta[1],atom->nangletypes,MPI_DOUBLE,0,world); for (int i = 1; i <= atom->nangletypes; i++) setflag[i] = 1; } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void AngleCosineShift::write_data(FILE *fp) { for (int i = 1; i <= atom->nangletypes; i++) fprintf(fp,"%d %g %g\n",i,2.0*k[i],theta[i]/MY_PI*180.0); } /* ---------------------------------------------------------------------- */ double AngleCosineShift::single(int type, int i1, int i2, int i3) { double **x = atom->x; double delx1 = x[i1][0] - x[i2][0]; double dely1 = x[i1][1] - x[i2][1]; double delz1 = x[i1][2] - x[i2][2]; domain->minimum_image(delx1,dely1,delz1); double r1 = sqrt(delx1*delx1 + dely1*dely1 + delz1*delz1); double delx2 = x[i3][0] - x[i2][0]; double dely2 = x[i3][1] - x[i2][1]; double delz2 = x[i3][2] - x[i2][2]; domain->minimum_image(delx2,dely2,delz2); double r2 = sqrt(delx2*delx2 + dely2*dely2 + delz2*delz2); double c = delx1*delx2 + dely1*dely2 + delz1*delz2; c /= r1*r2; if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; double s=sqrt(1.0-c*c); return -k[type]-kcost[type]*c-ksint[type]*s; } diff --git a/src/USER-MISC/angle_cosine_shift_exp.cpp b/src/USER-MISC/angle_cosine_shift_exp.cpp index e19b9e20e..6d11c6894 100644 --- a/src/USER-MISC/angle_cosine_shift_exp.cpp +++ b/src/USER-MISC/angle_cosine_shift_exp.cpp @@ -1,315 +1,315 @@ /* ---------------------------------------------------------------------- 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: Carsten Svaneborg, science@zqex.dk ------------------------------------------------------------------------- */ #include #include #include "angle_cosine_shift_exp.h" #include "atom.h" #include "neighbor.h" #include "domain.h" #include "comm.h" #include "force.h" #include "math_const.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace MathConst; #define SMALL 0.001 /* ---------------------------------------------------------------------- */ AngleCosineShiftExp::AngleCosineShiftExp(LAMMPS *lmp) : Angle(lmp) {} /* ---------------------------------------------------------------------- */ AngleCosineShiftExp::~AngleCosineShiftExp() { if (allocated) { memory->destroy(setflag); memory->destroy(umin); memory->destroy(a); memory->destroy(opt1); memory->destroy(cost); memory->destroy(sint); memory->destroy(theta0); memory->destroy(doExpansion); } } /* ---------------------------------------------------------------------- */ void AngleCosineShiftExp::compute(int eflag, int vflag) { int i1,i2,i3,n,type; double delx1,dely1,delz1,delx2,dely2,delz2; double eangle,f1[3],f3[3],ff; double rsq1,rsq2,r1,r2,c,s,a11,a12,a22; double exp2,aa,uumin,cccpsss,cssmscc; eangle = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; int **anglelist = neighbor->anglelist; int nanglelist = neighbor->nanglelist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < nanglelist; n++) { i1 = anglelist[n][0]; i2 = anglelist[n][1]; i3 = anglelist[n][2]; type = anglelist[n][3]; // 1st bond delx1 = x[i1][0] - x[i2][0]; dely1 = x[i1][1] - x[i2][1]; delz1 = x[i1][2] - x[i2][2]; rsq1 = delx1*delx1 + dely1*dely1 + delz1*delz1; r1 = sqrt(rsq1); // 2nd bond delx2 = x[i3][0] - x[i2][0]; dely2 = x[i3][1] - x[i2][1]; delz2 = x[i3][2] - x[i2][2]; rsq2 = delx2*delx2 + dely2*dely2 + delz2*delz2; r2 = sqrt(rsq2); // c = cosine of angle c = delx1*delx2 + dely1*dely2 + delz1*delz2; c /= r1*r2; if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; // C= sine of angle s = sqrt(1.0 - c*c); if (s < SMALL) s = SMALL; // force & energy aa=a[type]; uumin=umin[type]; cccpsss = c*cost[type]+s*sint[type]; cssmscc = c*sint[type]-s*cost[type]; if (doExpansion[type]) { // |a|<0.01 so use expansions relative precision <1e-5 // std::cout << "Using expansion\n"; if (eflag) eangle = -0.125*(1+cccpsss)*(4+aa*(cccpsss-1))*uumin; ff=0.25*uumin*cssmscc*(2+aa*cccpsss)/s; } else { // std::cout << "Not using expansion\n"; exp2=exp(0.5*aa*(1+cccpsss)); if (eflag) eangle = opt1[type]*(1-exp2); ff=0.5*a[type]*opt1[type]*exp2*cssmscc/s; } a11 = ff*c/ rsq1; a12 = -ff / (r1*r2); a22 = ff*c/ rsq2; f1[0] = a11*delx1 + a12*delx2; f1[1] = a11*dely1 + a12*dely2; f1[2] = a11*delz1 + a12*delz2; f3[0] = a22*delx2 + a12*delx1; f3[1] = a22*dely2 + a12*dely1; f3[2] = a22*delz2 + a12*delz1; // apply force to each of 3 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += f1[0]; f[i1][1] += f1[1]; f[i1][2] += f1[2]; } if (newton_bond || i2 < nlocal) { f[i2][0] -= f1[0] + f3[0]; f[i2][1] -= f1[1] + f3[1]; f[i2][2] -= f1[2] + f3[2]; } if (newton_bond || i3 < nlocal) { f[i3][0] += f3[0]; f[i3][1] += f3[1]; f[i3][2] += f3[2]; } if (evflag) ev_tally(i1,i2,i3,nlocal,newton_bond,eangle,f1,f3, delx1,dely1,delz1,delx2,dely2,delz2); } } /* ---------------------------------------------------------------------- */ void AngleCosineShiftExp::allocate() { allocated = 1; int n = atom->nangletypes; memory->create(doExpansion, n+1, "angle:doExpansion"); memory->create(umin , n+1, "angle:umin"); memory->create(a , n+1, "angle:a"); memory->create(sint , n+1, "angle:sint"); memory->create(cost , n+1, "angle:cost"); memory->create(opt1 , n+1, "angle:opt1"); memory->create(theta0 , n+1, "angle:theta0"); memory->create(setflag , n+1, "angle:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one type ------------------------------------------------------------------------- */ void AngleCosineShiftExp::coeff(int narg, char **arg) { if (narg != 4) error->all(FLERR,"Incorrect args for angle coefficients"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->nangletypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->nangletypes,ilo,ihi); double umin_ = force->numeric(FLERR,arg[1]); double theta0_ = force->numeric(FLERR,arg[2]); double a_ = force->numeric(FLERR,arg[3]); int count = 0; for (int i = ilo; i <= ihi; i++) { doExpansion[i]=(fabs(a_)<0.001); umin[i] = umin_; a[i] = a_; cost[i] = cos(theta0_*MY_PI / 180.0); sint[i] = sin(theta0_*MY_PI / 180.0); theta0[i]= theta0_*MY_PI / 180.0; if (!doExpansion[i]) opt1[i]=umin_/(exp(a_)-1); setflag[i] = 1; count++; } if (count == 0) error->all(FLERR,"Incorrect args for angle coefficients"); } /* ---------------------------------------------------------------------- */ double AngleCosineShiftExp::equilibrium_angle(int i) { return theta0[i]; } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void AngleCosineShiftExp::write_restart(FILE *fp) { fwrite(&umin[1],sizeof(double),atom->nangletypes,fp); fwrite(&a[1],sizeof(double),atom->nangletypes,fp); fwrite(&cost[1],sizeof(double),atom->nangletypes,fp); fwrite(&sint[1],sizeof(double),atom->nangletypes,fp); fwrite(&theta0[1],sizeof(double),atom->nangletypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void AngleCosineShiftExp::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&umin[1],sizeof(double),atom->nangletypes,fp); fread(&a[1],sizeof(double),atom->nangletypes,fp); fread(&cost[1],sizeof(double),atom->nangletypes,fp); fread(&sint[1],sizeof(double),atom->nangletypes,fp); fread(&theta0[1],sizeof(double),atom->nangletypes,fp); } MPI_Bcast(&umin[1],atom->nangletypes,MPI_DOUBLE,0,world); MPI_Bcast(&a[1],atom->nangletypes,MPI_DOUBLE,0,world); MPI_Bcast(&cost[1],atom->nangletypes,MPI_DOUBLE,0,world); MPI_Bcast(&sint[1],atom->nangletypes,MPI_DOUBLE,0,world); MPI_Bcast(&theta0[1],atom->nangletypes,MPI_DOUBLE,0,world); for (int i = 1; i <= atom->nangletypes; i++) { setflag[i] = 1; doExpansion[i]=(fabs(a[i])<0.01); if (!doExpansion[i]) opt1[i]=umin[i]/(exp(a[i])-1); } } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void AngleCosineShiftExp::write_data(FILE *fp) { for (int i = 1; i <= atom->nangletypes; i++) fprintf(fp,"%d %g %g %g\n",i,umin[i],theta0[i]/MY_PI*180.0,a[i]); } /* ---------------------------------------------------------------------- */ double AngleCosineShiftExp::single(int type, int i1, int i2, int i3) { double **x = atom->x; double delx1 = x[i1][0] - x[i2][0]; double dely1 = x[i1][1] - x[i2][1]; double delz1 = x[i1][2] - x[i2][2]; domain->minimum_image(delx1,dely1,delz1); double r1 = sqrt(delx1*delx1 + dely1*dely1 + delz1*delz1); double delx2 = x[i3][0] - x[i2][0]; double dely2 = x[i3][1] - x[i2][1]; double delz2 = x[i3][2] - x[i2][2]; domain->minimum_image(delx2,dely2,delz2); double r2 = sqrt(delx2*delx2 + dely2*dely2 + delz2*delz2); double c = delx1*delx2 + dely1*dely2 + delz1*delz2; c /= r1*r2; if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; double s=sqrt(1.0-c*c); double cccpsss=c*cost[type]+s*sint[type]; if (doExpansion[type]) { return -0.125*(1+cccpsss)*(4+a[type]*(cccpsss-1))*umin[type]; } else { return opt1[type]*(1-exp(0.5*a[type]*(1+cccpsss))); } } diff --git a/src/USER-MISC/angle_dipole.cpp b/src/USER-MISC/angle_dipole.cpp index 52e94ad3f..990096ae7 100644 --- a/src/USER-MISC/angle_dipole.cpp +++ b/src/USER-MISC/angle_dipole.cpp @@ -1,246 +1,246 @@ /* ---------------------------------------------------------------------- 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: Mario Orsi & Wei Ding (QMUL), m.orsi@qmul.ac.uk ------------------------------------------------------------------------- */ #include #include #include "angle_dipole.h" #include "atom.h" #include "neighbor.h" #include "domain.h" #include "comm.h" #include "force.h" #include "math_const.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace MathConst; /* ---------------------------------------------------------------------- */ AngleDipole::AngleDipole(LAMMPS *lmp) : Angle(lmp) {} /* ---------------------------------------------------------------------- */ AngleDipole::~AngleDipole() { if (allocated) { memory->destroy(setflag); memory->destroy(k); memory->destroy(gamma0); } } /* ---------------------------------------------------------------------- */ void AngleDipole::compute(int eflag, int vflag) { int iRef,iDip,iDummy,n,type; double delx,dely,delz; double eangle,tangle,fi[3],fj[3]; double r,cosGamma,deltaGamma,kdg,rmu; eangle = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; // position vector double **mu = atom->mu; // point-dipole components and moment magnitude double **torque = atom->torque; int **anglelist = neighbor->anglelist; int nanglelist = neighbor->nanglelist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; double **f = atom->f; double delTx, delTy, delTz; double fx, fy, fz, fmod, fmod_sqrtff; if (!newton_bond) error->all(FLERR,"'newton' flag for bonded interactions must be 'on'"); for (n = 0; n < nanglelist; n++) { iDip = anglelist[n][0]; // dipole whose orientation is to be restrained iRef = anglelist[n][1]; // reference atom toward which dipole will point iDummy = anglelist[n][2]; // dummy atom - irrelevant to the interaction type = anglelist[n][3]; delx = x[iRef][0] - x[iDip][0]; dely = x[iRef][1] - x[iDip][1]; delz = x[iRef][2] - x[iDip][2]; r = sqrt(delx*delx + dely*dely + delz*delz); rmu = r * mu[iDip][3]; cosGamma = (mu[iDip][0]*delx+mu[iDip][1]*dely+mu[iDip][2]*delz) / rmu; deltaGamma = cosGamma - cos(gamma0[type]); kdg = k[type] * deltaGamma; if (eflag) eangle = kdg * deltaGamma; // energy tangle = 2.0 * kdg / rmu; delTx = tangle * (dely*mu[iDip][2] - delz*mu[iDip][1]); delTy = tangle * (delz*mu[iDip][0] - delx*mu[iDip][2]); delTz = tangle * (delx*mu[iDip][1] - dely*mu[iDip][0]); torque[iDip][0] += delTx; torque[iDip][1] += delTy; torque[iDip][2] += delTz; // Force couple that counterbalances dipolar torque fx = dely*delTz - delz*delTy; // direction (fi): - r x (-T) fy = delz*delTx - delx*delTz; fz = delx*delTy - dely*delTx; fmod = sqrt(delTx*delTx + delTy*delTy + delTz*delTz) / r; // magnitude fmod_sqrtff = fmod / sqrt(fx*fx + fy*fy + fz*fz); fi[0] = fx * fmod_sqrtff; fi[1] = fy * fmod_sqrtff; fi[2] = fz * fmod_sqrtff; fj[0] = -fi[0]; fj[1] = -fi[1]; fj[2] = -fi[2]; f[iDip][0] += fj[0]; f[iDip][1] += fj[1]; f[iDip][2] += fj[2]; f[iRef][0] += fi[0]; f[iRef][1] += fi[1]; f[iRef][2] += fi[2]; if (evflag) // virial = rij.fi = 0 (fj = -fi & fk = 0) ev_tally(iRef,iDip,iDummy,nlocal,newton_bond,eangle,fj,fi, 0.0,0.0,0.0,0.0,0.0,0.0); } } /* ---------------------------------------------------------------------- */ void AngleDipole::allocate() { allocated = 1; int n = atom->nangletypes; memory->create(k,n+1,"angle:k"); memory->create(gamma0,n+1,"angle:gamma0"); memory->create(setflag,n+1,"angle:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one or more types ------------------------------------------------------------------------- */ void AngleDipole::coeff(int narg, char **arg) { if (narg != 3) error->all(FLERR,"Incorrect args for angle coefficients"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->nangletypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->nangletypes,ilo,ihi); double k_one = force->numeric(FLERR,arg[1]); double gamma0_one = force->numeric(FLERR,arg[2]); // convert gamma0 from degrees to radians int count = 0; for (int i = ilo; i <= ihi; i++) { k[i] = k_one; gamma0[i] = gamma0_one/180.0 * MY_PI; setflag[i] = 1; count++; } if (count == 0) error->all(FLERR,"Incorrect args for angle coefficients"); } /* ---------------------------------------------------------------------- used by SHAKE ------------------------------------------------------------------------- */ double AngleDipole::equilibrium_angle(int i) { return gamma0[i]; } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void AngleDipole::write_restart(FILE *fp) { fwrite(&k[1],sizeof(double),atom->nangletypes,fp); fwrite(&gamma0[1],sizeof(double),atom->nangletypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void AngleDipole::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&k[1],sizeof(double),atom->nangletypes,fp); fread(&gamma0[1],sizeof(double),atom->nangletypes,fp); } MPI_Bcast(&k[1],atom->nangletypes,MPI_DOUBLE,0,world); MPI_Bcast(&gamma0[1],atom->nangletypes,MPI_DOUBLE,0,world); for (int i = 1; i <= atom->nangletypes; i++) setflag[i] = 1; } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void AngleDipole::write_data(FILE *fp) { for (int i = 1; i <= atom->nangletypes; i++) fprintf(fp,"%d %g %g\n",i,k[i],gamma0[i]); } /* ---------------------------------------------------------------------- used by ComputeAngleLocal ------------------------------------------------------------------------- */ double AngleDipole::single(int type, int iRef, int iDip, int iDummy) { double **x = atom->x; // position vector double **mu = atom->mu; // point-dipole components and moment magnitude double delx = x[iRef][0] - x[iDip][0]; double dely = x[iRef][1] - x[iDip][1]; double delz = x[iRef][2] - x[iDip][2]; domain->minimum_image(delx,dely,delz); double r = sqrt(delx*delx + dely*dely + delz*delz); double rmu = r * mu[iDip][3]; double cosGamma = (mu[iDip][0]*delx+mu[iDip][1]*dely+mu[iDip][2]*delz) / rmu; double deltaGamma = cosGamma - cos(gamma0[type]); double kdg = k[type] * deltaGamma; return kdg * deltaGamma; // energy } diff --git a/src/USER-MISC/angle_fourier.cpp b/src/USER-MISC/angle_fourier.cpp index dee6ed130..c4dbf3f08 100644 --- a/src/USER-MISC/angle_fourier.cpp +++ b/src/USER-MISC/angle_fourier.cpp @@ -1,278 +1,278 @@ /* ---------------------------------------------------------------------- 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: Loukas D. Peristeras (Scienomics SARL) [ based on angle_cosine_squared.cpp Naveen Michaud-Agrawal (Johns Hopkins U)] ------------------------------------------------------------------------- */ #include #include #include "angle_fourier.h" #include "atom.h" #include "neighbor.h" #include "domain.h" #include "comm.h" #include "force.h" #include "math_const.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace MathConst; #define SMALL 0.001 /* ---------------------------------------------------------------------- */ AngleFourier::AngleFourier(LAMMPS *lmp) : Angle(lmp) {} /* ---------------------------------------------------------------------- */ AngleFourier::~AngleFourier() { if (allocated) { memory->destroy(setflag); memory->destroy(k); memory->destroy(C0); memory->destroy(C1); memory->destroy(C2); } } /* ---------------------------------------------------------------------- */ void AngleFourier::compute(int eflag, int vflag) { int i1,i2,i3,n,type; double delx1,dely1,delz1,delx2,dely2,delz2; double eangle,f1[3],f3[3]; double term; double rsq1,rsq2,r1,r2,c,c2,a,a11,a12,a22; eangle = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; int **anglelist = neighbor->anglelist; int nanglelist = neighbor->nanglelist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < nanglelist; n++) { i1 = anglelist[n][0]; i2 = anglelist[n][1]; i3 = anglelist[n][2]; type = anglelist[n][3]; // 1st bond delx1 = x[i1][0] - x[i2][0]; dely1 = x[i1][1] - x[i2][1]; delz1 = x[i1][2] - x[i2][2]; rsq1 = delx1*delx1 + dely1*dely1 + delz1*delz1; r1 = sqrt(rsq1); // 2nd bond delx2 = x[i3][0] - x[i2][0]; dely2 = x[i3][1] - x[i2][1]; delz2 = x[i3][2] - x[i2][2]; rsq2 = delx2*delx2 + dely2*dely2 + delz2*delz2; r2 = sqrt(rsq2); // angle (cos and sin) c = delx1*delx2 + dely1*dely2 + delz1*delz2; c /= r1*r2; if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; // force & energy c2 = 2.0*c*c-1.0; term = k[type]*(C0[type]+C1[type]*c+C2[type]*c2); if (eflag) eangle = term; a = k[type]*(C1[type]+4.0*C2[type]*c); a11 = a*c / rsq1; a12 = -a / (r1*r2); a22 = a*c / rsq2; f1[0] = a11*delx1 + a12*delx2; f1[1] = a11*dely1 + a12*dely2; f1[2] = a11*delz1 + a12*delz2; f3[0] = a22*delx2 + a12*delx1; f3[1] = a22*dely2 + a12*dely1; f3[2] = a22*delz2 + a12*delz1; // apply force to each of 3 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += f1[0]; f[i1][1] += f1[1]; f[i1][2] += f1[2]; } if (newton_bond || i2 < nlocal) { f[i2][0] -= f1[0] + f3[0]; f[i2][1] -= f1[1] + f3[1]; f[i2][2] -= f1[2] + f3[2]; } if (newton_bond || i3 < nlocal) { f[i3][0] += f3[0]; f[i3][1] += f3[1]; f[i3][2] += f3[2]; } if (evflag) ev_tally(i1,i2,i3,nlocal,newton_bond,eangle,f1,f3, delx1,dely1,delz1,delx2,dely2,delz2); } } /* ---------------------------------------------------------------------- */ void AngleFourier::allocate() { allocated = 1; int n = atom->nangletypes; memory->create(k,n+1,"angle:k"); memory->create(C0,n+1,"angle:C0"); memory->create(C1,n+1,"angle:C1"); memory->create(C2,n+1,"angle:C2"); memory->create(setflag,n+1,"angle:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one or more types ------------------------------------------------------------------------- */ void AngleFourier::coeff(int narg, char **arg) { if (narg != 5) error->all(FLERR,"Incorrect args for angle coefficients"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->nangletypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->nangletypes,ilo,ihi); double k_one = force->numeric(FLERR,arg[1]); double C0_one = force->numeric(FLERR,arg[2]); double C1_one = force->numeric(FLERR,arg[3]); double C2_one = force->numeric(FLERR,arg[4]); int count = 0; for (int i = ilo; i <= ihi; i++) { k[i] = k_one; C0[i] = C0_one; C1[i] = C1_one; C2[i] = C2_one; setflag[i] = 1; count++; } if (count == 0) error->all(FLERR,"Incorrect args for angle coefficients"); } /* ---------------------------------------------------------------------- */ double AngleFourier::equilibrium_angle(int i) { double ret=MY_PI; if ( C2[i] != 0.0 ) { ret = (C1[i]/4.0/C2[i]); if ( fabs(ret) <= 1.0 ) ret = acos(-ret); } return ret; } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void AngleFourier::write_restart(FILE *fp) { fwrite(&k[1],sizeof(double),atom->nangletypes,fp); fwrite(&C0[1],sizeof(double),atom->nangletypes,fp); fwrite(&C1[1],sizeof(double),atom->nangletypes,fp); fwrite(&C2[1],sizeof(double),atom->nangletypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void AngleFourier::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&k[1],sizeof(double),atom->nangletypes,fp); fread(&C0[1],sizeof(double),atom->nangletypes,fp); fread(&C1[1],sizeof(double),atom->nangletypes,fp); fread(&C2[1],sizeof(double),atom->nangletypes,fp); } MPI_Bcast(&k[1],atom->nangletypes,MPI_DOUBLE,0,world); MPI_Bcast(&C0[1],atom->nangletypes,MPI_DOUBLE,0,world); MPI_Bcast(&C1[1],atom->nangletypes,MPI_DOUBLE,0,world); MPI_Bcast(&C2[1],atom->nangletypes,MPI_DOUBLE,0,world); for (int i = 1; i <= atom->nangletypes; i++) setflag[i] = 1; } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void AngleFourier::write_data(FILE *fp) { for (int i = 1; i <= atom->nangletypes; i++) fprintf(fp,"%d %g %g %g %g\n",i,k[i],C0[i],C1[i],C2[i]); } /* ---------------------------------------------------------------------- */ double AngleFourier::single(int type, int i1, int i2, int i3) { double **x = atom->x; double delx1 = x[i1][0] - x[i2][0]; double dely1 = x[i1][1] - x[i2][1]; double delz1 = x[i1][2] - x[i2][2]; domain->minimum_image(delx1,dely1,delz1); double r1 = sqrt(delx1*delx1 + dely1*dely1 + delz1*delz1); double delx2 = x[i3][0] - x[i2][0]; double dely2 = x[i3][1] - x[i2][1]; double delz2 = x[i3][2] - x[i2][2]; domain->minimum_image(delx2,dely2,delz2); double r2 = sqrt(delx2*delx2 + dely2*dely2 + delz2*delz2); double c = delx1*delx2 + dely1*dely2 + delz1*delz2; c /= r1*r2; if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; double c2 = 2.0*c*c-1.0; double eng = k[type]*(C0[type]+C1[type]*c+C2[type]*c2); return eng; } diff --git a/src/USER-MISC/angle_fourier_simple.cpp b/src/USER-MISC/angle_fourier_simple.cpp index 63991f320..bd4322fe7 100644 --- a/src/USER-MISC/angle_fourier_simple.cpp +++ b/src/USER-MISC/angle_fourier_simple.cpp @@ -1,283 +1,283 @@ /* ---------------------------------------------------------------------- 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: Loukas D. Peristeras (Scienomics SARL) [ based on angle_cosine_squared.cpp Naveen Michaud-Agrawal (Johns Hopkins U)] ------------------------------------------------------------------------- */ #include #include #include "angle_fourier_simple.h" #include "atom.h" #include "neighbor.h" #include "domain.h" #include "comm.h" #include "force.h" #include "math_const.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace MathConst; #define SMALL 0.001 /* ---------------------------------------------------------------------- */ AngleFourierSimple::AngleFourierSimple(LAMMPS *lmp) : Angle(lmp) {} /* ---------------------------------------------------------------------- */ AngleFourierSimple::~AngleFourierSimple() { if (allocated) { memory->destroy(setflag); memory->destroy(k); memory->destroy(C); memory->destroy(N); } } /* ---------------------------------------------------------------------- */ void AngleFourierSimple::compute(int eflag, int vflag) { int i1,i2,i3,n,type; double delx1,dely1,delz1,delx2,dely2,delz2; double eangle,f1[3],f3[3]; double term,sgn; double rsq1,rsq2,r1,r2,c,cn,th,nth,a,a11,a12,a22; eangle = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; int **anglelist = neighbor->anglelist; int nanglelist = neighbor->nanglelist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < nanglelist; n++) { i1 = anglelist[n][0]; i2 = anglelist[n][1]; i3 = anglelist[n][2]; type = anglelist[n][3]; // 1st bond delx1 = x[i1][0] - x[i2][0]; dely1 = x[i1][1] - x[i2][1]; delz1 = x[i1][2] - x[i2][2]; rsq1 = delx1*delx1 + dely1*dely1 + delz1*delz1; r1 = sqrt(rsq1); // 2nd bond delx2 = x[i3][0] - x[i2][0]; dely2 = x[i3][1] - x[i2][1]; delz2 = x[i3][2] - x[i2][2]; rsq2 = delx2*delx2 + dely2*dely2 + delz2*delz2; r2 = sqrt(rsq2); // angle (cos and sin) c = delx1*delx2 + dely1*dely2 + delz1*delz2; c /= r1*r2; if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; // force & energy th = acos(c); nth = N[type]*acos(c); cn = cos(nth); term = k[type]*(1.0+C[type]*cn); if (eflag) eangle = term; // handle sin(n th)/sin(th) singulatiries if ( fabs(c)-1.0 > 0.0001 ) { a = k[type]*C[type]*N[type]*sin(nth)/sin(th); } else { if ( c >= 0.0 ) { term = 1.0 - c; sgn = 1.0; } else { term = 1.0 + c; sgn = ( fmodf((float)(N[type]),2.0) == 0.0f )?-1.0:1.0; } a = N[type]+N[type]*(1.0-N[type]*N[type])*term/3.0; a = k[type]*C[type]*N[type]*(double)(sgn)*a; } a11 = a*c / rsq1; a12 = -a / (r1*r2); a22 = a*c / rsq2; f1[0] = a11*delx1 + a12*delx2; f1[1] = a11*dely1 + a12*dely2; f1[2] = a11*delz1 + a12*delz2; f3[0] = a22*delx2 + a12*delx1; f3[1] = a22*dely2 + a12*dely1; f3[2] = a22*delz2 + a12*delz1; // apply force to each of 3 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += f1[0]; f[i1][1] += f1[1]; f[i1][2] += f1[2]; } if (newton_bond || i2 < nlocal) { f[i2][0] -= f1[0] + f3[0]; f[i2][1] -= f1[1] + f3[1]; f[i2][2] -= f1[2] + f3[2]; } if (newton_bond || i3 < nlocal) { f[i3][0] += f3[0]; f[i3][1] += f3[1]; f[i3][2] += f3[2]; } if (evflag) ev_tally(i1,i2,i3,nlocal,newton_bond,eangle,f1,f3, delx1,dely1,delz1,delx2,dely2,delz2); } } /* ---------------------------------------------------------------------- */ void AngleFourierSimple::allocate() { allocated = 1; int n = atom->nangletypes; memory->create(k,n+1,"angle:k"); memory->create(C,n+1,"angle:C"); memory->create(N,n+1,"angle:N"); memory->create(setflag,n+1,"angle:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one or more types ------------------------------------------------------------------------- */ void AngleFourierSimple::coeff(int narg, char **arg) { if (narg != 4) error->all(FLERR,"Incorrect args for angle coefficients"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->nangletypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->nangletypes,ilo,ihi); double k_one = force->numeric(FLERR,arg[1]); double C_one = force->numeric(FLERR,arg[2]); double N_one = force->numeric(FLERR,arg[3]); int count = 0; for (int i = ilo; i <= ihi; i++) { k[i] = k_one; C[i] = C_one; N[i] = N_one; setflag[i] = 1; count++; } if (count == 0) error->all(FLERR,"Incorrect args for angle coefficients"); } /* ---------------------------------------------------------------------- */ double AngleFourierSimple::equilibrium_angle(int i) { return (MY_PI/N[i]); } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void AngleFourierSimple::write_restart(FILE *fp) { fwrite(&k[1],sizeof(double),atom->nangletypes,fp); fwrite(&C[1],sizeof(double),atom->nangletypes,fp); fwrite(&N[1],sizeof(double),atom->nangletypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void AngleFourierSimple::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&k[1],sizeof(double),atom->nangletypes,fp); fread(&C[1],sizeof(double),atom->nangletypes,fp); fread(&N[1],sizeof(double),atom->nangletypes,fp); } MPI_Bcast(&k[1],atom->nangletypes,MPI_DOUBLE,0,world); MPI_Bcast(&C[1],atom->nangletypes,MPI_DOUBLE,0,world); MPI_Bcast(&N[1],atom->nangletypes,MPI_DOUBLE,0,world); for (int i = 1; i <= atom->nangletypes; i++) setflag[i] = 1; } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void AngleFourierSimple::write_data(FILE *fp) { for (int i = 1; i <= atom->nangletypes; i++) fprintf(fp,"%d %g %g %g\n",i,k[i],C[i],N[i]); } /* ---------------------------------------------------------------------- */ double AngleFourierSimple::single(int type, int i1, int i2, int i3) { double **x = atom->x; double delx1 = x[i1][0] - x[i2][0]; double dely1 = x[i1][1] - x[i2][1]; double delz1 = x[i1][2] - x[i2][2]; domain->minimum_image(delx1,dely1,delz1); double r1 = sqrt(delx1*delx1 + dely1*dely1 + delz1*delz1); double delx2 = x[i3][0] - x[i2][0]; double dely2 = x[i3][1] - x[i2][1]; double delz2 = x[i3][2] - x[i2][2]; domain->minimum_image(delx2,dely2,delz2); double r2 = sqrt(delx2*delx2 + dely2*dely2 + delz2*delz2); double c = delx1*delx2 + dely1*dely2 + delz1*delz2; c /= r1*r2; if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; double cn = cos(N[type]*acos(c)); double eng = k[type]*(1.0+C[type]*cn); return eng; } diff --git a/src/USER-MISC/angle_quartic.cpp b/src/USER-MISC/angle_quartic.cpp index a1a3e4cf3..f9801edb0 100644 --- a/src/USER-MISC/angle_quartic.cpp +++ b/src/USER-MISC/angle_quartic.cpp @@ -1,287 +1,287 @@ /* ---------------------------------------------------------------------- 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: Loukas D. Peristeras (Scienomics SARL) [ based on angle_harmonic.cpp] ------------------------------------------------------------------------- */ #include #include #include "angle_quartic.h" #include "atom.h" #include "neighbor.h" #include "domain.h" #include "comm.h" #include "force.h" #include "math_const.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace MathConst; #define SMALL 0.001 /* ---------------------------------------------------------------------- */ AngleQuartic::AngleQuartic(LAMMPS *lmp) : Angle(lmp) {} /* ---------------------------------------------------------------------- */ AngleQuartic::~AngleQuartic() { if (allocated) { memory->destroy(setflag); memory->destroy(k2); memory->destroy(k3); memory->destroy(k4); memory->destroy(theta0); } } /* ---------------------------------------------------------------------- */ void AngleQuartic::compute(int eflag, int vflag) { int i1,i2,i3,n,type; double delx1,dely1,delz1,delx2,dely2,delz2; double eangle,f1[3],f3[3]; double dtheta,dtheta2,dtheta3,dtheta4,tk; double rsq1,rsq2,r1,r2,c,s,a,a11,a12,a22; eangle = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; int **anglelist = neighbor->anglelist; int nanglelist = neighbor->nanglelist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < nanglelist; n++) { i1 = anglelist[n][0]; i2 = anglelist[n][1]; i3 = anglelist[n][2]; type = anglelist[n][3]; // 1st bond delx1 = x[i1][0] - x[i2][0]; dely1 = x[i1][1] - x[i2][1]; delz1 = x[i1][2] - x[i2][2]; rsq1 = delx1*delx1 + dely1*dely1 + delz1*delz1; r1 = sqrt(rsq1); // 2nd bond delx2 = x[i3][0] - x[i2][0]; dely2 = x[i3][1] - x[i2][1]; delz2 = x[i3][2] - x[i2][2]; rsq2 = delx2*delx2 + dely2*dely2 + delz2*delz2; r2 = sqrt(rsq2); // angle (cos and sin) c = delx1*delx2 + dely1*dely2 + delz1*delz2; c /= r1*r2; if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; s = sqrt(1.0 - c*c); if (s < SMALL) s = SMALL; s = 1.0/s; // force & energy dtheta = acos(c) - theta0[type]; dtheta2 = dtheta * dtheta; dtheta3 = dtheta2 * dtheta; tk = 2.0 * k2[type] * dtheta + 3.0 * k3[type] * dtheta2 + 4.0 * k4[type] * dtheta3; if (eflag) { dtheta4 = dtheta3 * dtheta; eangle = k2[type] * dtheta2 + k3[type] * dtheta3 + k4[type] * dtheta4; } a = -tk * s; a11 = a*c / rsq1; a12 = -a / (r1*r2); a22 = a*c / rsq2; f1[0] = a11*delx1 + a12*delx2; f1[1] = a11*dely1 + a12*dely2; f1[2] = a11*delz1 + a12*delz2; f3[0] = a22*delx2 + a12*delx1; f3[1] = a22*dely2 + a12*dely1; f3[2] = a22*delz2 + a12*delz1; // apply force to each of 3 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += f1[0]; f[i1][1] += f1[1]; f[i1][2] += f1[2]; } if (newton_bond || i2 < nlocal) { f[i2][0] -= f1[0] + f3[0]; f[i2][1] -= f1[1] + f3[1]; f[i2][2] -= f1[2] + f3[2]; } if (newton_bond || i3 < nlocal) { f[i3][0] += f3[0]; f[i3][1] += f3[1]; f[i3][2] += f3[2]; } if (evflag) ev_tally(i1,i2,i3,nlocal,newton_bond,eangle,f1,f3, delx1,dely1,delz1,delx2,dely2,delz2); } } /* ---------------------------------------------------------------------- */ void AngleQuartic::allocate() { allocated = 1; int n = atom->nangletypes; memory->create(k2,n+1,"angle:k2"); memory->create(k3,n+1,"angle:k3"); memory->create(k4,n+1,"angle:k4"); memory->create(theta0,n+1,"angle:theta0"); memory->create(setflag,n+1,"angle:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one or more types ------------------------------------------------------------------------- */ void AngleQuartic::coeff(int narg, char **arg) { if (narg != 5) error->all(FLERR,"Incorrect args for angle coefficients"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->nangletypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->nangletypes,ilo,ihi); double theta0_one = force->numeric(FLERR,arg[1]); double k2_one = force->numeric(FLERR,arg[2]); double k3_one = force->numeric(FLERR,arg[3]); double k4_one = force->numeric(FLERR,arg[4]); // convert theta0 from degrees to radians int count = 0; for (int i = ilo; i <= ihi; i++) { k2[i] = k2_one; k3[i] = k3_one; k4[i] = k4_one; theta0[i] = theta0_one/180.0 * MY_PI; setflag[i] = 1; count++; } if (count == 0) error->all(FLERR,"Incorrect args for angle coefficients"); } /* ---------------------------------------------------------------------- */ double AngleQuartic::equilibrium_angle(int i) { return theta0[i]; } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void AngleQuartic::write_restart(FILE *fp) { fwrite(&k2[1],sizeof(double),atom->nangletypes,fp); fwrite(&k3[1],sizeof(double),atom->nangletypes,fp); fwrite(&k4[1],sizeof(double),atom->nangletypes,fp); fwrite(&theta0[1],sizeof(double),atom->nangletypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void AngleQuartic::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&k2[1],sizeof(double),atom->nangletypes,fp); fread(&k3[1],sizeof(double),atom->nangletypes,fp); fread(&k4[1],sizeof(double),atom->nangletypes,fp); fread(&theta0[1],sizeof(double),atom->nangletypes,fp); } MPI_Bcast(&k2[1],atom->nangletypes,MPI_DOUBLE,0,world); MPI_Bcast(&k3[1],atom->nangletypes,MPI_DOUBLE,0,world); MPI_Bcast(&k4[1],atom->nangletypes,MPI_DOUBLE,0,world); MPI_Bcast(&theta0[1],atom->nangletypes,MPI_DOUBLE,0,world); for (int i = 1; i <= atom->nangletypes; i++) setflag[i] = 1; } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void AngleQuartic::write_data(FILE *fp) { for (int i = 1; i <= atom->nangletypes; i++) fprintf(fp,"%d %g %g %g %g\n",i,theta0[i]/MY_PI*180.0,k2[i],k3[i],k4[i]); } /* ---------------------------------------------------------------------- */ double AngleQuartic::single(int type, int i1, int i2, int i3) { double **x = atom->x; double delx1 = x[i1][0] - x[i2][0]; double dely1 = x[i1][1] - x[i2][1]; double delz1 = x[i1][2] - x[i2][2]; domain->minimum_image(delx1,dely1,delz1); double r1 = sqrt(delx1*delx1 + dely1*dely1 + delz1*delz1); double delx2 = x[i3][0] - x[i2][0]; double dely2 = x[i3][1] - x[i2][1]; double delz2 = x[i3][2] - x[i2][2]; domain->minimum_image(delx2,dely2,delz2); double r2 = sqrt(delx2*delx2 + dely2*dely2 + delz2*delz2); double c = delx1*delx2 + dely1*dely2 + delz1*delz2; c /= r1*r2; if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; double dtheta = acos(c) - theta0[type]; double dtheta2 = dtheta * dtheta; double dtheta3 = dtheta2 * dtheta; double dtheta4 = dtheta3 * dtheta; return k2[type] * dtheta2 + k3[type] * dtheta3 + k4[type] * dtheta4; } diff --git a/src/USER-MISC/bond_harmonic_shift.cpp b/src/USER-MISC/bond_harmonic_shift.cpp index 6f1b67e24..c4ee00cb2 100644 --- a/src/USER-MISC/bond_harmonic_shift.cpp +++ b/src/USER-MISC/bond_harmonic_shift.cpp @@ -1,215 +1,215 @@ /* ---------------------------------------------------------------------- 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: Carsten Svaneborg, science@zqex.dk ------------------------------------------------------------------------- */ #include #include #include "bond_harmonic_shift.h" #include "atom.h" #include "neighbor.h" #include "domain.h" #include "comm.h" #include "force.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ BondHarmonicShift::BondHarmonicShift(LAMMPS *lmp) : Bond(lmp) {} /* ---------------------------------------------------------------------- */ BondHarmonicShift::~BondHarmonicShift() { if (allocated) { memory->destroy(setflag); memory->destroy(k); memory->destroy(r0); memory->destroy(r1); } } /* ---------------------------------------------------------------------- */ void BondHarmonicShift::compute(int eflag, int vflag) { int i1,i2,n,type; double delx,dely,delz,ebond,fbond; double rsq,r,dr,rk; ebond = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; int **bondlist = neighbor->bondlist; int nbondlist = neighbor->nbondlist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < nbondlist; n++) { i1 = bondlist[n][0]; i2 = bondlist[n][1]; type = bondlist[n][2]; delx = x[i1][0] - x[i2][0]; dely = x[i1][1] - x[i2][1]; delz = x[i1][2] - x[i2][2]; rsq = delx*delx + dely*dely + delz*delz; r = sqrt(rsq); dr = r - r0[type]; rk = k[type] * dr; // force & energy if (r > 0.0) fbond = -2.0*rk/r; else fbond = 0.0; if (eflag) ebond = k[type]*(dr*dr -(r0[type]-r1[type])*(r0[type]-r1[type]) ); // apply force to each of 2 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += delx*fbond; f[i1][1] += dely*fbond; f[i1][2] += delz*fbond; } if (newton_bond || i2 < nlocal) { f[i2][0] -= delx*fbond; f[i2][1] -= dely*fbond; f[i2][2] -= delz*fbond; } if (evflag) ev_tally(i1,i2,nlocal,newton_bond,ebond,fbond,delx,dely,delz); } } /* ---------------------------------------------------------------------- */ void BondHarmonicShift::allocate() { allocated = 1; int n = atom->nbondtypes; memory->create(k , n+1,"bond:k"); memory->create(r0, n+1,"bond:r0"); memory->create(r1, n+1,"bond:r1"); memory->create(setflag,n+1,"bond:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one or more types ------------------------------------------------------------------------- */ void BondHarmonicShift::coeff(int narg, char **arg) { if (narg != 4) error->all(FLERR,"Incorrect args for bond coefficients"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->nbondtypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->nbondtypes,ilo,ihi); double Umin = force->numeric(FLERR,arg[1]); // energy at minimum double r0_one = force->numeric(FLERR,arg[2]); // position of minimum double r1_one = force->numeric(FLERR,arg[3]); // position where energy = 0 if (r0_one == r1_one) error->all(FLERR,"Bond harmonic/shift r0 and r1 must be different"); int count = 0; for (int i = ilo; i <= ihi; i++) { k[i] = Umin/((r0_one-r1_one)*(r0_one-r1_one)); r0[i] = r0_one; r1[i] = r1_one; setflag[i] = 1; count++; } if (count == 0) error->all(FLERR,"Incorrect args for bond coefficients"); } /* ---------------------------------------------------------------------- return an equilbrium bond length ------------------------------------------------------------------------- */ double BondHarmonicShift::equilibrium_distance(int i) { return r0[i]; } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void BondHarmonicShift::write_restart(FILE *fp) { fwrite(&k[1],sizeof(double),atom->nbondtypes,fp); fwrite(&r0[1],sizeof(double),atom->nbondtypes,fp); fwrite(&r1[1],sizeof(double),atom->nbondtypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void BondHarmonicShift::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&k[1],sizeof(double),atom->nbondtypes,fp); fread(&r0[1],sizeof(double),atom->nbondtypes,fp); fread(&r1[1],sizeof(double),atom->nbondtypes,fp); } MPI_Bcast(&k[1],atom->nbondtypes,MPI_DOUBLE,0,world); MPI_Bcast(&r0[1],atom->nbondtypes,MPI_DOUBLE,0,world); MPI_Bcast(&r1[1],atom->nbondtypes,MPI_DOUBLE,0,world); for (int i = 1; i <= atom->nbondtypes; i++) setflag[i] = 1; } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void BondHarmonicShift::write_data(FILE *fp) { for (int i = 1; i <= atom->nbondtypes; i++) { double d2 = (r0[i]-r1[i])*(r0[i]-r1[i]); fprintf(fp,"%d %g %g %g\n",i,k[i]*d2,r0[i],r1[i]); } } /* ---------------------------------------------------------------------- */ double BondHarmonicShift::single(int type, double rsq, int i, int j, double &fforce) { double r = sqrt(rsq); double dr = r - r0[type]; double dr2=r0[type]-r1[type]; fforce = -2.0*k[type]*dr/r; return k[type]*(dr*dr - dr2*dr2); } diff --git a/src/USER-MISC/bond_harmonic_shift_cut.cpp b/src/USER-MISC/bond_harmonic_shift_cut.cpp index 1a1be1699..26fd32c1b 100644 --- a/src/USER-MISC/bond_harmonic_shift_cut.cpp +++ b/src/USER-MISC/bond_harmonic_shift_cut.cpp @@ -1,221 +1,221 @@ /* ---------------------------------------------------------------------- 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: Carsten Svaneborg, science@zqex.dk ------------------------------------------------------------------------- */ #include #include #include "bond_harmonic_shift_cut.h" #include "atom.h" #include "neighbor.h" #include "domain.h" #include "comm.h" #include "force.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ BondHarmonicShiftCut::BondHarmonicShiftCut(LAMMPS *lmp) : Bond(lmp) {} /* ---------------------------------------------------------------------- */ BondHarmonicShiftCut::~BondHarmonicShiftCut() { if (allocated) { memory->destroy(setflag); memory->destroy(k); memory->destroy(r0); memory->destroy(r1); } } /* ---------------------------------------------------------------------- */ void BondHarmonicShiftCut::compute(int eflag, int vflag) { int i1,i2,n,type; double delx,dely,delz,ebond,fbond; double rsq,r,dr,rk; ebond = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; int **bondlist = neighbor->bondlist; int nbondlist = neighbor->nbondlist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < nbondlist; n++) { i1 = bondlist[n][0]; i2 = bondlist[n][1]; type = bondlist[n][2]; delx = x[i1][0] - x[i2][0]; dely = x[i1][1] - x[i2][1]; delz = x[i1][2] - x[i2][2]; rsq = delx*delx + dely*dely + delz*delz; r = sqrt(rsq); if (r>r1[type]) continue; dr = r - r0[type]; rk = k[type] * dr; // force & energy if (r > 0.0) fbond = -2.0*rk/r; else fbond = 0.0; if (eflag) ebond = k[type]*(dr*dr -(r0[type]-r1[type])*(r0[type]-r1[type])); // apply force to each of 2 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += delx*fbond; f[i1][1] += dely*fbond; f[i1][2] += delz*fbond; } if (newton_bond || i2 < nlocal) { f[i2][0] -= delx*fbond; f[i2][1] -= dely*fbond; f[i2][2] -= delz*fbond; } if (evflag) ev_tally(i1,i2,nlocal,newton_bond,ebond,fbond,delx,dely,delz); } } /* ---------------------------------------------------------------------- */ void BondHarmonicShiftCut::allocate() { allocated = 1; int n = atom->nbondtypes; memory->create(k , n+1,"bond:k"); memory->create(r0, n+1,"bond:r0"); memory->create(r1, n+1,"bond:r1"); memory->create(setflag,n+1,"bond:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one or more types ------------------------------------------------------------------------- */ void BondHarmonicShiftCut::coeff(int narg, char **arg) { if (narg != 4) error->all(FLERR,"Incorrect args for bond coefficients"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->nbondtypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->nbondtypes,ilo,ihi); double Umin = force->numeric(FLERR,arg[1]); // energy at minimum double r0_one = force->numeric(FLERR,arg[2]); // position of minimum double r1_one = force->numeric(FLERR,arg[3]); // position where energy = 0 = cutoff if (r0_one == r1_one) error->all(FLERR,"Bond harmonic/shift/cut r0 and r1 must be different"); int count = 0; for (int i = ilo; i <= ihi; i++) { k[i] = Umin/((r0_one-r1_one)*(r0_one-r1_one)); r0[i] = r0_one; r1[i] = r1_one; setflag[i] = 1; count++; } if (count == 0) error->all(FLERR,"Incorrect args for bond coefficients"); } /* ---------------------------------------------------------------------- return an equilbrium bond length ------------------------------------------------------------------------- */ double BondHarmonicShiftCut::equilibrium_distance(int i) { return r0[i]; } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void BondHarmonicShiftCut::write_restart(FILE *fp) { fwrite(&k[1],sizeof(double),atom->nbondtypes,fp); fwrite(&r0[1],sizeof(double),atom->nbondtypes,fp); fwrite(&r1[1],sizeof(double),atom->nbondtypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void BondHarmonicShiftCut::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&k[1],sizeof(double),atom->nbondtypes,fp); fread(&r0[1],sizeof(double),atom->nbondtypes,fp); fread(&r1[1],sizeof(double),atom->nbondtypes,fp); } MPI_Bcast(&k[1],atom->nbondtypes,MPI_DOUBLE,0,world); MPI_Bcast(&r0[1],atom->nbondtypes,MPI_DOUBLE,0,world); MPI_Bcast(&r1[1],atom->nbondtypes,MPI_DOUBLE,0,world); for (int i = 1; i <= atom->nbondtypes; i++) setflag[i] = 1; } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void BondHarmonicShiftCut::write_data(FILE *fp) { for (int i = 1; i <= atom->nbondtypes; i++) { double d2 = (r0[i]-r1[i])*(r0[i]-r1[i]); fprintf(fp,"%d %g %g %g\n",i,k[i]*d2,r0[i],r1[i]); } } /* ---------------------------------------------------------------------- */ double BondHarmonicShiftCut::single(int type, double rsq, int i, int j, double &fforce) { fforce = 0.0; double r = sqrt(rsq); if (r>r1[type]) return 0.0; double dr = r - r0[type]; double dr2=r0[type]-r1[type]; fforce = -2.0*k[type]*dr/r; return k[type]*(dr*dr - dr2*dr2); } diff --git a/src/USER-MISC/dihedral_cosine_shift_exp.cpp b/src/USER-MISC/dihedral_cosine_shift_exp.cpp index 8706b5fb1..85ff4b271 100644 --- a/src/USER-MISC/dihedral_cosine_shift_exp.cpp +++ b/src/USER-MISC/dihedral_cosine_shift_exp.cpp @@ -1,340 +1,340 @@ /* ---------------------------------------------------------------------- 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: Carsten Svaneborg, science@zqex.dk ------------------------------------------------------------------------- */ #include #include #include #include "dihedral_cosine_shift_exp.h" #include "atom.h" #include "comm.h" #include "neighbor.h" #include "domain.h" #include "force.h" #include "update.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define TOLERANCE 0.05 #define SMALL 0.001 /* ---------------------------------------------------------------------- */ DihedralCosineShiftExp::DihedralCosineShiftExp(LAMMPS *lmp) : Dihedral(lmp) {} /* ---------------------------------------------------------------------- */ DihedralCosineShiftExp::~DihedralCosineShiftExp() { if (allocated) { memory->destroy(setflag); memory->destroy(umin); memory->destroy(a); memory->destroy(opt1); memory->destroy(cost); memory->destroy(sint); memory->destroy(theta); memory->destroy(doExpansion); } } /* ---------------------------------------------------------------------- */ void DihedralCosineShiftExp::compute(int eflag, int vflag) { int i1,i2,i3,i4,n,type; double vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z,vb2xm,vb2ym,vb2zm; double edihedral,f1[3],f2[3],f3[3],f4[3]; double ax,ay,az,bx,by,bz,rasq,rbsq,rgsq,rg,rginv,ra2inv,rb2inv,rabinv; double df,fg,hg,fga,hgb,gaa,gbb; double dtfx,dtfy,dtfz,dtgx,dtgy,dtgz,dthx,dthy,dthz; double c,s,sx2,sy2,sz2; double cccpsss,cssmscc,exp2; edihedral = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; int **dihedrallist = neighbor->dihedrallist; int ndihedrallist = neighbor->ndihedrallist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < ndihedrallist; n++) { i1 = dihedrallist[n][0]; i2 = dihedrallist[n][1]; i3 = dihedrallist[n][2]; i4 = dihedrallist[n][3]; type = dihedrallist[n][4]; // 1st bond vb1x = x[i1][0] - x[i2][0]; vb1y = x[i1][1] - x[i2][1]; vb1z = x[i1][2] - x[i2][2]; // 2nd bond vb2x = x[i3][0] - x[i2][0]; vb2y = x[i3][1] - x[i2][1]; vb2z = x[i3][2] - x[i2][2]; vb2xm = -vb2x; vb2ym = -vb2y; vb2zm = -vb2z; // 3rd bond vb3x = x[i4][0] - x[i3][0]; vb3y = x[i4][1] - x[i3][1]; vb3z = x[i4][2] - x[i3][2]; // c,s calculation ax = vb1y*vb2zm - vb1z*vb2ym; ay = vb1z*vb2xm - vb1x*vb2zm; az = vb1x*vb2ym - vb1y*vb2xm; bx = vb3y*vb2zm - vb3z*vb2ym; by = vb3z*vb2xm - vb3x*vb2zm; bz = vb3x*vb2ym - vb3y*vb2xm; rasq = ax*ax + ay*ay + az*az; rbsq = bx*bx + by*by + bz*bz; rgsq = vb2xm*vb2xm + vb2ym*vb2ym + vb2zm*vb2zm; rg = sqrt(rgsq); rginv = ra2inv = rb2inv = 0.0; if (rg > 0) rginv = 1.0/rg; if (rasq > 0) ra2inv = 1.0/rasq; if (rbsq > 0) rb2inv = 1.0/rbsq; rabinv = sqrt(ra2inv*rb2inv); c = (ax*bx + ay*by + az*bz)*rabinv; s = rg*rabinv*(ax*vb3x + ay*vb3y + az*vb3z); // error check if (c > 1.0 + TOLERANCE || c < (-1.0 - TOLERANCE)) { int me; MPI_Comm_rank(world,&me); if (screen) { char str[128]; sprintf(str,"Dihedral problem: %d " BIGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT, me,update->ntimestep, atom->tag[i1],atom->tag[i2],atom->tag[i3],atom->tag[i4]); error->warning(FLERR,str,0); fprintf(screen," 1st atom: %d %g %g %g\n", me,x[i1][0],x[i1][1],x[i1][2]); fprintf(screen," 2nd atom: %d %g %g %g\n", me,x[i2][0],x[i2][1],x[i2][2]); fprintf(screen," 3rd atom: %d %g %g %g\n", me,x[i3][0],x[i3][1],x[i3][2]); fprintf(screen," 4th atom: %d %g %g %g\n", me,x[i4][0],x[i4][1],x[i4][2]); } } if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; double aa=a[type]; double uumin=umin[type]; cccpsss = c*cost[type]+s*sint[type]; cssmscc = c*sint[type]-s*cost[type]; // eflag=1; if (doExpansion[type]) { // |a|<0.001 so use expansions relative precision <1e-5 if (eflag) edihedral = -0.125*(1+cccpsss)*(4+aa*(cccpsss-1))*uumin; df=0.5*uumin*( cssmscc + 0.5*aa*cccpsss); } else { exp2=exp(0.5*aa*(1+cccpsss)); if (eflag) edihedral = opt1[type]*(1-exp2); df= 0.5*opt1[type]*aa* ( exp2*cssmscc ); } fg = vb1x*vb2xm + vb1y*vb2ym + vb1z*vb2zm; hg = vb3x*vb2xm + vb3y*vb2ym + vb3z*vb2zm; fga = fg*ra2inv*rginv; hgb = hg*rb2inv*rginv; gaa = -ra2inv*rg; gbb = rb2inv*rg; dtfx = gaa*ax; dtfy = gaa*ay; dtfz = gaa*az; dtgx = fga*ax - hgb*bx; dtgy = fga*ay - hgb*by; dtgz = fga*az - hgb*bz; dthx = gbb*bx; dthy = gbb*by; dthz = gbb*bz; sx2 = df*dtgx; sy2 = df*dtgy; sz2 = df*dtgz; f1[0] = df*dtfx; f1[1] = df*dtfy; f1[2] = df*dtfz; f2[0] = sx2 - f1[0]; f2[1] = sy2 - f1[1]; f2[2] = sz2 - f1[2]; f4[0] = df*dthx; f4[1] = df*dthy; f4[2] = df*dthz; f3[0] = -sx2 - f4[0]; f3[1] = -sy2 - f4[1]; f3[2] = -sz2 - f4[2]; // apply force to each of 4 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += f1[0]; f[i1][1] += f1[1]; f[i1][2] += f1[2]; } if (newton_bond || i2 < nlocal) { f[i2][0] += f2[0]; f[i2][1] += f2[1]; f[i2][2] += f2[2]; } if (newton_bond || i3 < nlocal) { f[i3][0] += f3[0]; f[i3][1] += f3[1]; f[i3][2] += f3[2]; } if (newton_bond || i4 < nlocal) { f[i4][0] += f4[0]; f[i4][1] += f4[1]; f[i4][2] += f4[2]; } if (evflag) ev_tally(i1,i2,i3,i4,nlocal,newton_bond,edihedral,f1,f3,f4, vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z); } } /* ---------------------------------------------------------------------- */ void DihedralCosineShiftExp::allocate() { allocated = 1; int n = atom->ndihedraltypes; memory->create(doExpansion, n+1, "dihedral:doExpansion"); memory->create(umin,n+1,"dihedral:umin"); memory->create(a,n+1,"dihedral:a"); memory->create(sint,n+1,"dihedral:sind"); memory->create(cost,n+1,"dihedral:cosd"); memory->create(opt1,n+1,"dihedral:opt1"); memory->create(theta,n+1,"dihedral:opt1"); memory->create(setflag, n+1,"dihedral:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one type ------------------------------------------------------------------------- */ void DihedralCosineShiftExp::coeff(int narg, char **arg) { if (narg != 4) error->all(FLERR,"Incorrect args for dihedral coefficients"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->ndihedraltypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->ndihedraltypes,ilo,ihi); double umin_ = force->numeric(FLERR,arg[1]); double theta0_ = force->numeric(FLERR,arg[2]); double a_ = force->numeric(FLERR,arg[3]); int count = 0; for (int i = ilo; i <= ihi; i++) { doExpansion[i]=(fabs(a_)<0.001); umin[i] = umin_; a[i] = a_; cost[i] = cos(theta0_*3.14159265/180); sint[i] = sin(theta0_*3.14159265/180); theta[i] = theta0_*3.14159265/180; if (!doExpansion[i]) opt1[i]=umin_/(exp(a_)-1); setflag[i] = 1; count++; } if (count == 0) error->all(FLERR,"Incorrect args for dihedral coefficients"); } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void DihedralCosineShiftExp::write_restart(FILE *fp) { fwrite(&umin[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&a[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&cost[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&sint[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&theta[1],sizeof(double),atom->ndihedraltypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void DihedralCosineShiftExp::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&umin[1],sizeof(double),atom->ndihedraltypes,fp); fread(&a[1],sizeof(double),atom->ndihedraltypes,fp); fread(&cost[1],sizeof(double),atom->ndihedraltypes,fp); fread(&sint[1],sizeof(double),atom->ndihedraltypes,fp); fread(&theta[1],sizeof(double),atom->ndihedraltypes,fp); } MPI_Bcast(&umin[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&a[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&cost[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&sint[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&theta[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); for (int i = 1; i <= atom->ndihedraltypes; i++) { setflag[i] = 1; doExpansion[i]=(fabs(a[i])<0.01); if (!doExpansion[i]) opt1[i]=umin[i]/(exp(a[i])-1); } } diff --git a/src/USER-MISC/dihedral_fourier.cpp b/src/USER-MISC/dihedral_fourier.cpp index 93e818183..86ab8894d 100644 --- a/src/USER-MISC/dihedral_fourier.cpp +++ b/src/USER-MISC/dihedral_fourier.cpp @@ -1,403 +1,403 @@ /* ---------------------------------------------------------------------- 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: Loukas D. Peristeras (Scienomics SARL) [ based on dihedral_charmm.cpp Paul Crozier (SNL) ] ------------------------------------------------------------------------- */ #include #include #include #include "dihedral_fourier.h" #include "atom.h" #include "comm.h" #include "neighbor.h" #include "domain.h" #include "force.h" #include "pair.h" #include "update.h" #include "math_const.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace MathConst; #define TOLERANCE 0.05 /* ---------------------------------------------------------------------- */ DihedralFourier::DihedralFourier(LAMMPS *lmp) : Dihedral(lmp) {} /* ---------------------------------------------------------------------- */ DihedralFourier::~DihedralFourier() { if (allocated) { memory->destroy(setflag); memory->destroy(nterms); for (int i=1; i<= atom->ndihedraltypes; i++) { if ( k[i] ) delete [] k[i]; if ( multiplicity[i] ) delete [] multiplicity[i]; if ( shift[i] ) delete [] shift[i]; if ( cos_shift[i] ) delete [] cos_shift[i]; if ( sin_shift[i] ) delete [] sin_shift[i]; } delete [] k; delete [] multiplicity; delete [] shift; delete [] cos_shift; delete [] sin_shift; } } /* ---------------------------------------------------------------------- */ void DihedralFourier::compute(int eflag, int vflag) { int i1,i2,i3,i4,i,j,m,n,type; double vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z,vb2xm,vb2ym,vb2zm; double edihedral,f1[3],f2[3],f3[3],f4[3]; double ax,ay,az,bx,by,bz,rasq,rbsq,rgsq,rg,rginv,ra2inv,rb2inv,rabinv; double df,df1_,ddf1_,fg,hg,fga,hgb,gaa,gbb; double dtfx,dtfy,dtfz,dtgx,dtgy,dtgz,dthx,dthy,dthz; double c,s,p_,sx2,sy2,sz2; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; int **dihedrallist = neighbor->dihedrallist; int ndihedrallist = neighbor->ndihedrallist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < ndihedrallist; n++) { i1 = dihedrallist[n][0]; i2 = dihedrallist[n][1]; i3 = dihedrallist[n][2]; i4 = dihedrallist[n][3]; type = dihedrallist[n][4]; // 1st bond vb1x = x[i1][0] - x[i2][0]; vb1y = x[i1][1] - x[i2][1]; vb1z = x[i1][2] - x[i2][2]; // 2nd bond vb2x = x[i3][0] - x[i2][0]; vb2y = x[i3][1] - x[i2][1]; vb2z = x[i3][2] - x[i2][2]; vb2xm = -vb2x; vb2ym = -vb2y; vb2zm = -vb2z; // 3rd bond vb3x = x[i4][0] - x[i3][0]; vb3y = x[i4][1] - x[i3][1]; vb3z = x[i4][2] - x[i3][2]; ax = vb1y*vb2zm - vb1z*vb2ym; ay = vb1z*vb2xm - vb1x*vb2zm; az = vb1x*vb2ym - vb1y*vb2xm; bx = vb3y*vb2zm - vb3z*vb2ym; by = vb3z*vb2xm - vb3x*vb2zm; bz = vb3x*vb2ym - vb3y*vb2xm; rasq = ax*ax + ay*ay + az*az; rbsq = bx*bx + by*by + bz*bz; rgsq = vb2xm*vb2xm + vb2ym*vb2ym + vb2zm*vb2zm; rg = sqrt(rgsq); rginv = ra2inv = rb2inv = 0.0; if (rg > 0) rginv = 1.0/rg; if (rasq > 0) ra2inv = 1.0/rasq; if (rbsq > 0) rb2inv = 1.0/rbsq; rabinv = sqrt(ra2inv*rb2inv); c = (ax*bx + ay*by + az*bz)*rabinv; s = rg*rabinv*(ax*vb3x + ay*vb3y + az*vb3z); // error check if (c > 1.0 + TOLERANCE || c < (-1.0 - TOLERANCE)) { int me; MPI_Comm_rank(world,&me); if (screen) { char str[128]; sprintf(str,"Dihedral problem: %d " BIGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT, me,update->ntimestep, atom->tag[i1],atom->tag[i2],atom->tag[i3],atom->tag[i4]); error->warning(FLERR,str,0); fprintf(screen," 1st atom: %d %g %g %g\n", me,x[i1][0],x[i1][1],x[i1][2]); fprintf(screen," 2nd atom: %d %g %g %g\n", me,x[i2][0],x[i2][1],x[i2][2]); fprintf(screen," 3rd atom: %d %g %g %g\n", me,x[i3][0],x[i3][1],x[i3][2]); fprintf(screen," 4th atom: %d %g %g %g\n", me,x[i4][0],x[i4][1],x[i4][2]); } } if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; // force and energy // p = sum(i=1,nterms) k_i*(1+cos(n_i*phi-d_i) // dp = dp / dphi edihedral = 0.0; df = 0.0; for (j=0; jndihedraltypes; memory->create(nterms,n+1,"dihedral:nterms"); k = new double * [n+1]; multiplicity = new int * [n+1]; shift = new double * [n+1]; cos_shift = new double * [n+1]; sin_shift = new double * [n+1]; for (int i = 1; i <= n; i++) { k[i] = shift[i] = cos_shift[i] = sin_shift[i] = 0; multiplicity[i] = 0; } memory->create(setflag,n+1,"dihedral:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one type ------------------------------------------------------------------------- */ void DihedralFourier::coeff(int narg, char **arg) { if (narg < 4) error->all(FLERR,"Incorrect args for dihedral coefficients"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->ndihedraltypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->ndihedraltypes,ilo,ihi); // require integer values of shift for backwards compatibility // arbitrary phase angle shift could be allowed, but would break // backwards compatibility and is probably not needed double k_one; int multiplicity_one; double shift_one; int nterms_one = force->inumeric(FLERR,arg[1]); if (nterms_one < 1) error->all(FLERR,"Incorrect number of terms arg for dihedral coefficients"); if (2+3*nterms_one < narg) error->all(FLERR,"Incorrect number of arguments for dihedral coefficients"); int count = 0; for (int i = ilo; i <= ihi; i++) { nterms[i] = nterms_one; k[i] = new double [nterms_one]; multiplicity[i] = new int [nterms_one]; shift[i] = new double [nterms_one]; cos_shift[i] = new double [nterms_one]; sin_shift[i] = new double [nterms_one]; for (int j = 0; jnumeric(FLERR,arg[offset+1]); multiplicity_one = force->inumeric(FLERR,arg[offset+2]); shift_one = force->numeric(FLERR,arg[offset+3]); k[i][j] = k_one; multiplicity[i][j] = multiplicity_one; shift[i][j] = shift_one; cos_shift[i][j] = cos(MY_PI*shift_one/180.0); sin_shift[i][j] = sin(MY_PI*shift_one/180.0); } setflag[i] = 1; count++; } if (count == 0) error->all(FLERR,"Incorrect args for dihedral coefficients"); } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void DihedralFourier::write_restart(FILE *fp) { fwrite(&nterms[1],sizeof(int),atom->ndihedraltypes,fp); for(int i = 1; i <= atom->ndihedraltypes; i++) { fwrite(k[i],sizeof(double),nterms[i],fp); fwrite(multiplicity[i],sizeof(int),nterms[i],fp); fwrite(shift[i],sizeof(double),nterms[i],fp); } } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void DihedralFourier::read_restart(FILE *fp) { allocate(); if (comm->me == 0) fread(&nterms[1],sizeof(int),atom->ndihedraltypes,fp); MPI_Bcast(&nterms[1],atom->ndihedraltypes,MPI_INT,0,world); // allocate for (int i=1; i<=atom->ndihedraltypes; i++) { k[i] = new double [nterms[i]]; multiplicity[i] = new int [nterms[i]]; shift[i] = new double [nterms[i]]; cos_shift[i] = new double [nterms[i]]; sin_shift[i] = new double [nterms[i]]; } if (comm->me == 0) { for (int i=1; i<=atom->ndihedraltypes; i++) { fread(k[i],sizeof(double),nterms[i],fp); fread(multiplicity[i],sizeof(int),nterms[i],fp); fread(shift[i],sizeof(double),nterms[i],fp); } } for (int i=1; i<=atom->ndihedraltypes; i++) { MPI_Bcast(k[i],nterms[i],MPI_DOUBLE,0,world); MPI_Bcast(multiplicity[i],nterms[i],MPI_INT,0,world); MPI_Bcast(shift[i],nterms[i],MPI_DOUBLE,0,world); } for (int i=1; i <= atom->ndihedraltypes; i++) { setflag[i] = 1; for (int j = 0; j < nterms[i]; j++) { cos_shift[i][j] = cos(MY_PI*shift[i][j]/180.0); sin_shift[i][j] = sin(MY_PI*shift[i][j]/180.0); } } } diff --git a/src/USER-MISC/dihedral_nharmonic.cpp b/src/USER-MISC/dihedral_nharmonic.cpp index 67b363f55..ba8af7e65 100644 --- a/src/USER-MISC/dihedral_nharmonic.cpp +++ b/src/USER-MISC/dihedral_nharmonic.cpp @@ -1,336 +1,336 @@ /* ---------------------------------------------------------------------- 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: Loukas D. Peristeras (Scienomics SARL) [ based on dihedral_multi_harmonic.cpp Mathias Puetz (SNL) and friends ] ------------------------------------------------------------------------- */ #include #include #include "dihedral_nharmonic.h" #include "atom.h" #include "neighbor.h" #include "domain.h" #include "comm.h" #include "force.h" #include "update.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define TOLERANCE 0.05 #define SMALL 0.001 /* ---------------------------------------------------------------------- */ DihedralNHarmonic::DihedralNHarmonic(LAMMPS *lmp) : Dihedral(lmp) {} /* ---------------------------------------------------------------------- */ DihedralNHarmonic::~DihedralNHarmonic() { if (allocated) { memory->destroy(setflag); for (int i = 1; i <= atom->ndihedraltypes; i++) delete [] a[i]; delete [] a; delete [] nterms; } } /* ---------------------------------------------------------------------- */ void DihedralNHarmonic::compute(int eflag, int vflag) { int i1,i2,i3,i4,n,type; double vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z,vb2xm,vb2ym,vb2zm; double edihedral,f1[3],f2[3],f3[3],f4[3]; double sb1,sb2,sb3,rb1,rb3,c0,b1mag2,b1mag,b2mag2; double b2mag,b3mag2,b3mag,ctmp,c_,r12c1,c1mag,r12c2; double c2mag,sc1,sc2,s1,s12,c,p,pd,a11,a22; double a33,a12,a13,a23,sx2,sy2,sz2; double s2,sin2; edihedral = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; int **dihedrallist = neighbor->dihedrallist; int ndihedrallist = neighbor->ndihedrallist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < ndihedrallist; n++) { i1 = dihedrallist[n][0]; i2 = dihedrallist[n][1]; i3 = dihedrallist[n][2]; i4 = dihedrallist[n][3]; type = dihedrallist[n][4]; // 1st bond vb1x = x[i1][0] - x[i2][0]; vb1y = x[i1][1] - x[i2][1]; vb1z = x[i1][2] - x[i2][2]; // 2nd bond vb2x = x[i3][0] - x[i2][0]; vb2y = x[i3][1] - x[i2][1]; vb2z = x[i3][2] - x[i2][2]; vb2xm = -vb2x; vb2ym = -vb2y; vb2zm = -vb2z; // 3rd bond vb3x = x[i4][0] - x[i3][0]; vb3y = x[i4][1] - x[i3][1]; vb3z = x[i4][2] - x[i3][2]; // c0 calculation sb1 = 1.0 / (vb1x*vb1x + vb1y*vb1y + vb1z*vb1z); sb2 = 1.0 / (vb2x*vb2x + vb2y*vb2y + vb2z*vb2z); sb3 = 1.0 / (vb3x*vb3x + vb3y*vb3y + vb3z*vb3z); rb1 = sqrt(sb1); rb3 = sqrt(sb3); c0 = (vb1x*vb3x + vb1y*vb3y + vb1z*vb3z) * rb1*rb3; // 1st and 2nd angle b1mag2 = vb1x*vb1x + vb1y*vb1y + vb1z*vb1z; b1mag = sqrt(b1mag2); b2mag2 = vb2x*vb2x + vb2y*vb2y + vb2z*vb2z; b2mag = sqrt(b2mag2); b3mag2 = vb3x*vb3x + vb3y*vb3y + vb3z*vb3z; b3mag = sqrt(b3mag2); ctmp = vb1x*vb2x + vb1y*vb2y + vb1z*vb2z; r12c1 = 1.0 / (b1mag*b2mag); c1mag = ctmp * r12c1; ctmp = vb2xm*vb3x + vb2ym*vb3y + vb2zm*vb3z; r12c2 = 1.0 / (b2mag*b3mag); c2mag = ctmp * r12c2; // cos and sin of 2 angles and final c sin2 = MAX(1.0 - c1mag*c1mag,0.0); sc1 = sqrt(sin2); if (sc1 < SMALL) sc1 = SMALL; sc1 = 1.0/sc1; sin2 = MAX(1.0 - c2mag*c2mag,0.0); sc2 = sqrt(sin2); if (sc2 < SMALL) sc2 = SMALL; sc2 = 1.0/sc2; s1 = sc1 * sc1; s2 = sc2 * sc2; s12 = sc1 * sc2; c = (c0 + c1mag*c2mag) * s12; // error check if (c > 1.0 + TOLERANCE || c < (-1.0 - TOLERANCE)) { int me; MPI_Comm_rank(world,&me); if (screen) { char str[128]; sprintf(str,"Dihedral problem: %d " BIGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT, me,update->ntimestep, atom->tag[i1],atom->tag[i2],atom->tag[i3],atom->tag[i4]); error->warning(FLERR,str,0); fprintf(screen," 1st atom: %d %g %g %g\n", me,x[i1][0],x[i1][1],x[i1][2]); fprintf(screen," 2nd atom: %d %g %g %g\n", me,x[i2][0],x[i2][1],x[i2][2]); fprintf(screen," 3rd atom: %d %g %g %g\n", me,x[i3][0],x[i3][1],x[i3][2]); fprintf(screen," 4th atom: %d %g %g %g\n", me,x[i4][0],x[i4][1],x[i4][2]); } } if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; // force & energy // p = sum (i=1,n) a_i * c**(i-1) // pd = dp/dc c_ = c; p = this->a[type][0]; pd = this->a[type][1]; for (int i = 1; i < nterms[type]-1; i++) { p += c_ * this->a[type][i]; pd += c_ * static_cast(i+1) * this->a[type][i+1]; c_ *= c; } p += c_ * this->a[type][nterms[type]-1]; if (eflag) edihedral = p; c = c * pd; s12 = s12 * pd; a11 = c*sb1*s1; a22 = -sb2 * (2.0*c0*s12 - c*(s1+s2)); a33 = c*sb3*s2; a12 = -r12c1*(c1mag*c*s1 + c2mag*s12); a13 = -rb1*rb3*s12; a23 = r12c2*(c2mag*c*s2 + c1mag*s12); sx2 = a12*vb1x + a22*vb2x + a23*vb3x; sy2 = a12*vb1y + a22*vb2y + a23*vb3y; sz2 = a12*vb1z + a22*vb2z + a23*vb3z; f1[0] = a11*vb1x + a12*vb2x + a13*vb3x; f1[1] = a11*vb1y + a12*vb2y + a13*vb3y; f1[2] = a11*vb1z + a12*vb2z + a13*vb3z; f2[0] = -sx2 - f1[0]; f2[1] = -sy2 - f1[1]; f2[2] = -sz2 - f1[2]; f4[0] = a13*vb1x + a23*vb2x + a33*vb3x; f4[1] = a13*vb1y + a23*vb2y + a33*vb3y; f4[2] = a13*vb1z + a23*vb2z + a33*vb3z; f3[0] = sx2 - f4[0]; f3[1] = sy2 - f4[1]; f3[2] = sz2 - f4[2]; // apply force to each of 4 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += f1[0]; f[i1][1] += f1[1]; f[i1][2] += f1[2]; } if (newton_bond || i2 < nlocal) { f[i2][0] += f2[0]; f[i2][1] += f2[1]; f[i2][2] += f2[2]; } if (newton_bond || i3 < nlocal) { f[i3][0] += f3[0]; f[i3][1] += f3[1]; f[i3][2] += f3[2]; } if (newton_bond || i4 < nlocal) { f[i4][0] += f4[0]; f[i4][1] += f4[1]; f[i4][2] += f4[2]; } if (evflag) ev_tally(i1,i2,i3,i4,nlocal,newton_bond,edihedral,f1,f3,f4, vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z); } } /* ---------------------------------------------------------------------- */ void DihedralNHarmonic::allocate() { allocated = 1; int n = atom->ndihedraltypes; memory->create(nterms,n+1,"dihedral:nt"); a = new double * [n+1]; memory->create(setflag,n+1,"dihedral:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one type ------------------------------------------------------------------------- */ void DihedralNHarmonic::coeff(int narg, char **arg) { if (narg < 4 ) error->all(FLERR,"Incorrect args for dihedral coefficients"); int n = force->inumeric(FLERR,arg[1]); if (narg != n + 2 ) error->all(FLERR,"Incorrect args for dihedral coefficients"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->ndihedraltypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->ndihedraltypes,ilo,ihi); int count = 0; for (int i = ilo; i <= ihi; i++) { a[i] = new double [n]; nterms[i] = n; for (int j = 0; j < n; j++ ) { a[i][j] = force->numeric(FLERR,arg[2+j]); setflag[i] = 1; } count++; } if (count == 0) error->all(FLERR,"Incorrect args for dihedral coefficients"); } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void DihedralNHarmonic::write_restart(FILE *fp) { fwrite(&nterms[1],sizeof(int),atom->ndihedraltypes,fp); for(int i = 1; i <= atom->ndihedraltypes; i++) fwrite(a[i],sizeof(double),nterms[i],fp); } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void DihedralNHarmonic::read_restart(FILE *fp) { allocate(); if (comm->me == 0) fread(&nterms[1],sizeof(int),atom->ndihedraltypes,fp); MPI_Bcast(&nterms[1],atom->ndihedraltypes,MPI_INT,0,world); // allocate for(int i = 1; i <= atom->ndihedraltypes; i++) a[i] = new double [nterms[i]]; if (comm->me == 0) { for(int i = 1; i <= atom->ndihedraltypes; i++) fread(a[i],sizeof(double),nterms[i],fp); } for (int i = 1; i <= atom->ndihedraltypes; i++ ) MPI_Bcast(a[i],nterms[i],MPI_DOUBLE,0,world); for (int i = 1; i <= atom->ndihedraltypes; i++) setflag[i] = 1; } diff --git a/src/USER-MISC/dihedral_quadratic.cpp b/src/USER-MISC/dihedral_quadratic.cpp index 3a5eac6fa..ac261153b 100644 --- a/src/USER-MISC/dihedral_quadratic.cpp +++ b/src/USER-MISC/dihedral_quadratic.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: Loukas D. Peristeras (Scienomics SARL) [ based on dihedral_helix.cpp Paul Crozier (SNL) ] ------------------------------------------------------------------------- */ #include #include #include "dihedral_quadratic.h" #include "atom.h" #include "neighbor.h" #include "domain.h" #include "comm.h" #include "force.h" #include "update.h" #include "math_const.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace MathConst; #define TOLERANCE 0.05 #define SMALL 0.001 #define SMALLER 0.00001 /* ---------------------------------------------------------------------- */ DihedralQuadratic::DihedralQuadratic(LAMMPS *lmp) : Dihedral(lmp) {} /* ---------------------------------------------------------------------- */ DihedralQuadratic::~DihedralQuadratic() { if (allocated) { memory->destroy(setflag); memory->destroy(k); memory->destroy(phi0); } } /* ---------------------------------------------------------------------- */ void DihedralQuadratic::compute(int eflag, int vflag) { int i1,i2,i3,i4,n,type; double vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z,vb2xm,vb2ym,vb2zm; double edihedral,f1[3],f2[3],f3[3],f4[3]; double sb1,sb2,sb3,rb1,rb3,c0,b1mag2,b1mag,b2mag2; double b2mag,b3mag2,b3mag,ctmp,r12c1,c1mag,r12c2; double c2mag,sc1,sc2,s1,s12,c,p,pd,a,a11,a22; double a33,a12,a13,a23,sx2,sy2,sz2; double s2,cx,cy,cz,cmag,dx,phi,si,siinv,sin2; edihedral = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; int **dihedrallist = neighbor->dihedrallist; int ndihedrallist = neighbor->ndihedrallist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < ndihedrallist; n++) { i1 = dihedrallist[n][0]; i2 = dihedrallist[n][1]; i3 = dihedrallist[n][2]; i4 = dihedrallist[n][3]; type = dihedrallist[n][4]; // 1st bond vb1x = x[i1][0] - x[i2][0]; vb1y = x[i1][1] - x[i2][1]; vb1z = x[i1][2] - x[i2][2]; // 2nd bond vb2x = x[i3][0] - x[i2][0]; vb2y = x[i3][1] - x[i2][1]; vb2z = x[i3][2] - x[i2][2]; vb2xm = -vb2x; vb2ym = -vb2y; vb2zm = -vb2z; // 3rd bond vb3x = x[i4][0] - x[i3][0]; vb3y = x[i4][1] - x[i3][1]; vb3z = x[i4][2] - x[i3][2]; // c0 calculation sb1 = 1.0 / (vb1x*vb1x + vb1y*vb1y + vb1z*vb1z); sb2 = 1.0 / (vb2x*vb2x + vb2y*vb2y + vb2z*vb2z); sb3 = 1.0 / (vb3x*vb3x + vb3y*vb3y + vb3z*vb3z); rb1 = sqrt(sb1); rb3 = sqrt(sb3); c0 = (vb1x*vb3x + vb1y*vb3y + vb1z*vb3z) * rb1*rb3; // 1st and 2nd angle b1mag2 = vb1x*vb1x + vb1y*vb1y + vb1z*vb1z; b1mag = sqrt(b1mag2); b2mag2 = vb2x*vb2x + vb2y*vb2y + vb2z*vb2z; b2mag = sqrt(b2mag2); b3mag2 = vb3x*vb3x + vb3y*vb3y + vb3z*vb3z; b3mag = sqrt(b3mag2); ctmp = vb1x*vb2x + vb1y*vb2y + vb1z*vb2z; r12c1 = 1.0 / (b1mag*b2mag); c1mag = ctmp * r12c1; ctmp = vb2xm*vb3x + vb2ym*vb3y + vb2zm*vb3z; r12c2 = 1.0 / (b2mag*b3mag); c2mag = ctmp * r12c2; // cos and sin of 2 angles and final c sin2 = MAX(1.0 - c1mag*c1mag,0.0); sc1 = sqrt(sin2); if (sc1 < SMALL) sc1 = SMALL; sc1 = 1.0/sc1; sin2 = MAX(1.0 - c2mag*c2mag,0.0); sc2 = sqrt(sin2); if (sc2 < SMALL) sc2 = SMALL; sc2 = 1.0/sc2; s1 = sc1 * sc1; s2 = sc2 * sc2; s12 = sc1 * sc2; c = (c0 + c1mag*c2mag) * s12; cx = vb1y*vb2z - vb1z*vb2y; cy = vb1z*vb2x - vb1x*vb2z; cz = vb1x*vb2y - vb1y*vb2x; cmag = sqrt(cx*cx + cy*cy + cz*cz); dx = (cx*vb3x + cy*vb3y + cz*vb3z)/cmag/b3mag; // error check if (c > 1.0 + TOLERANCE || c < (-1.0 - TOLERANCE)) { int me; MPI_Comm_rank(world,&me); if (screen) { char str[128]; sprintf(str,"Dihedral problem: %d " BIGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT, me,update->ntimestep, atom->tag[i1],atom->tag[i2],atom->tag[i3],atom->tag[i4]); error->warning(FLERR,str,0); fprintf(screen," 1st atom: %d %g %g %g\n", me,x[i1][0],x[i1][1],x[i1][2]); fprintf(screen," 2nd atom: %d %g %g %g\n", me,x[i2][0],x[i2][1],x[i2][2]); fprintf(screen," 3rd atom: %d %g %g %g\n", me,x[i3][0],x[i3][1],x[i3][2]); fprintf(screen," 4th atom: %d %g %g %g\n", me,x[i4][0],x[i4][1],x[i4][2]); } } if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; // force & energy // p = k ( phi- phi0)^2 // pd = dp/dc phi = acos(c); if (dx > 0.0) phi *= -1.0; si = sin(phi); if (fabs(si) < SMALLER) si = SMALLER; siinv = 1.0/si; double dphi = phi-phi0[type]; p = k[type]*dphi; pd = - 2.0 * p * siinv; p = p * dphi; if (eflag) edihedral = p; a = pd; c = c * a; s12 = s12 * a; a11 = c*sb1*s1; a22 = -sb2 * (2.0*c0*s12 - c*(s1+s2)); a33 = c*sb3*s2; a12 = -r12c1 * (c1mag*c*s1 + c2mag*s12); a13 = -rb1*rb3*s12; a23 = r12c2 * (c2mag*c*s2 + c1mag*s12); sx2 = a12*vb1x + a22*vb2x + a23*vb3x; sy2 = a12*vb1y + a22*vb2y + a23*vb3y; sz2 = a12*vb1z + a22*vb2z + a23*vb3z; f1[0] = a11*vb1x + a12*vb2x + a13*vb3x; f1[1] = a11*vb1y + a12*vb2y + a13*vb3y; f1[2] = a11*vb1z + a12*vb2z + a13*vb3z; f2[0] = -sx2 - f1[0]; f2[1] = -sy2 - f1[1]; f2[2] = -sz2 - f1[2]; f4[0] = a13*vb1x + a23*vb2x + a33*vb3x; f4[1] = a13*vb1y + a23*vb2y + a33*vb3y; f4[2] = a13*vb1z + a23*vb2z + a33*vb3z; f3[0] = sx2 - f4[0]; f3[1] = sy2 - f4[1]; f3[2] = sz2 - f4[2]; // apply force to each of 4 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += f1[0]; f[i1][1] += f1[1]; f[i1][2] += f1[2]; } if (newton_bond || i2 < nlocal) { f[i2][0] += f2[0]; f[i2][1] += f2[1]; f[i2][2] += f2[2]; } if (newton_bond || i3 < nlocal) { f[i3][0] += f3[0]; f[i3][1] += f3[1]; f[i3][2] += f3[2]; } if (newton_bond || i4 < nlocal) { f[i4][0] += f4[0]; f[i4][1] += f4[1]; f[i4][2] += f4[2]; } if (evflag) ev_tally(i1,i2,i3,i4,nlocal,newton_bond,edihedral,f1,f3,f4, vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z); } } /* ---------------------------------------------------------------------- */ void DihedralQuadratic::allocate() { allocated = 1; int n = atom->ndihedraltypes; memory->create(k,n+1,"dihedral:k"); memory->create(phi0,n+1,"dihedral:phi0"); memory->create(setflag,n+1,"dihedral:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one type ------------------------------------------------------------------------- */ void DihedralQuadratic::coeff(int narg, char **arg) { if (narg != 3) error->all(FLERR,"Incorrect args for dihedral coefficients"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->ndihedraltypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->ndihedraltypes,ilo,ihi); double k_one = force->numeric(FLERR,arg[1]); double phi0_one= force->numeric(FLERR,arg[2]); // require k >= 0 if (k_one < 0.0) error->all(FLERR,"Incorrect coefficient arg for dihedral coefficients"); int count = 0; for (int i = ilo; i <= ihi; i++) { k[i] = k_one; phi0[i] = phi0_one*MY_PI/180.0; setflag[i] = 1; count++; } if (count == 0) error->all(FLERR,"Incorrect args for dihedral coefficients"); } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void DihedralQuadratic::write_restart(FILE *fp) { fwrite(&k[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&phi0[1],sizeof(double),atom->ndihedraltypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void DihedralQuadratic::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&k[1],sizeof(double),atom->ndihedraltypes,fp); fread(&phi0[1],sizeof(double),atom->ndihedraltypes,fp); } MPI_Bcast(&k[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&phi0[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); for (int i = 1; i <= atom->ndihedraltypes; i++) setflag[i] = 1; } diff --git a/src/USER-MISC/dihedral_spherical.cpp b/src/USER-MISC/dihedral_spherical.cpp index e6b431b63..c3345453c 100644 --- a/src/USER-MISC/dihedral_spherical.cpp +++ b/src/USER-MISC/dihedral_spherical.cpp @@ -1,876 +1,876 @@ /* ---------------------------------------------------------------------- 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: Andrew Jewett (Caltech) [ using code borrowed from Loukas D. Peristeras (Scienomics SARL) and Paul Crozier (SNL) ] ------------------------------------------------------------------------- */ #include #include #include #include #include "atom.h" #include "comm.h" #include "neighbor.h" #include "domain.h" #include "force.h" #include "pair.h" #include "update.h" #include "math_const.h" #include "math_extra.h" #include "memory.h" #include "error.h" #include "dihedral_spherical.h" using namespace std; using namespace LAMMPS_NS; using namespace MathConst; using namespace MathExtra; /* ---------------------------------------------------------------------- */ DihedralSpherical::DihedralSpherical(LAMMPS *lmp) : Dihedral(lmp) {} /* ---------------------------------------------------------------------- */ DihedralSpherical::~DihedralSpherical() { if (allocated && !copymode) { memory->destroy(setflag); memory->destroy(nterms); for (int i=1; i<= atom->ndihedraltypes; i++) { if ( Ccoeff[i] ) delete [] Ccoeff[i]; if ( phi_mult[i] ) delete [] phi_mult[i]; if ( phi_shift[i] ) delete [] phi_shift[i]; if ( phi_offset[i] ) delete [] phi_offset[i]; if ( theta1_mult[i] ) delete [] theta1_mult[i]; if ( theta1_shift[i] ) delete [] theta1_shift[i]; if ( theta1_offset[i] ) delete [] theta1_offset[i]; if ( theta2_mult[i] ) delete [] theta2_mult[i]; if ( theta2_shift[i] ) delete [] theta2_shift[i]; if ( theta2_offset[i] ) delete [] theta2_offset[i]; } delete [] Ccoeff; delete [] phi_mult; delete [] phi_shift; delete [] phi_offset; delete [] theta1_mult; delete [] theta1_shift; delete [] theta1_offset; delete [] theta2_mult; delete [] theta2_shift; delete [] theta2_offset; } } static void norm3safe(double *v) { double inv_scale = sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]); double scale = 1.0; if (inv_scale > 0.0) scale = 1.0 / inv_scale; v[0] *= scale; v[1] *= scale; v[2] *= scale; } // -------------------------------------------- // ------- Calculate the dihedral angle ------- // -------------------------------------------- static const int g_dim=3; static double Phi(double const *x1, //array holding x,y,z coords atom 1 double const *x2, // : : : : 2 double const *x3, // : : : : 3 double const *x4, // : : : : 4 Domain *domain, //<-periodic boundary information double *vb12, //<-preallocated vector will store x2-x1 double *vb23, //<-preallocated vector will store x3-x2 double *vb34, //<-preallocated vector will store x4-x3 double *n123, //<-will store normal to plane x1,x2,x3 double *n234) //<-will store normal to plane x2,x3,x4 { for (int d=0; d < g_dim; ++d) { vb12[d] = x2[d] - x1[d]; // 1st bond vb23[d] = x3[d] - x2[d]; // 2nd bond vb34[d] = x4[d] - x3[d]; // 3rd bond } //Consider periodic boundary conditions: domain->minimum_image(vb12[0],vb12[1],vb12[2]); domain->minimum_image(vb23[0],vb23[1],vb23[2]); domain->minimum_image(vb34[0],vb34[1],vb34[2]); //--- Compute the normal to the planes formed by atoms 1,2,3 and 2,3,4 --- cross3(vb23, vb12, n123); // <- n123=vb23 x vb12 cross3(vb23, vb34, n234); // <- n234=vb23 x vb34 norm3safe(n123); norm3safe(n234); double cos_phi = -dot3(n123, n234); if (cos_phi > 1.0) cos_phi = 1.0; else if (cos_phi < -1.0) cos_phi = -1.0; double phi = acos(cos_phi); if (dot3(n123, vb34) > 0.0) { phi = -phi; //(Note: Negative dihedral angles are possible only in 3-D.) phi += MY_2PI; //<- This insure phi is always in the range 0 to 2*PI } return phi; } // DihedralSpherical::Phi() /* ---------------------------------------------------------------------- */ void DihedralSpherical::compute(int eflag, int vflag) { int i1,i2,i3,i4,n,type; double edihedral,f1[3],f2[3],f3[3],f4[3]; double **x = atom->x; double **f = atom->f; int **dihedrallist = neighbor->dihedrallist; int ndihedrallist = neighbor->ndihedrallist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; // The dihedral angle "phi" is the angle between n123 and n234 // the planes defined by atoms i1,i2,i3, and i2,i3,i4. // // Definitions of vectors: vb12, vb23, vb34, perp12on23 // proj12on23, perp43on32, proj43on32 // // Note: The positions of the 4 atoms are labeled x[i1], x[i2], x[i3], x[i4] // (which are also vectors) // // proj12on23 proj34on23 // ---------> -----------> // // // // x[i2] x[i3] // . __@----------vb23-------->@ . // /|\ /| \ | // | / \ | // | / \ | // perp12on23 / \ | // | / \ perp34on23 // | vb12 \ | // | / vb34 | // | / \ | // | / \ | // | / \ | // @ \ | // _\| \|/ // x[i1] @ // // x[i4] // double vb12[g_dim]; // displacement vector from atom i1 towards atom i2 // vb12[d] = x[i2][d] - x[i1][d] (for d=0,1,2) double vb23[g_dim]; // displacement vector from atom i2 towards atom i3 // vb23[d] = x[i3][d] - x[i2][d] (for d=0,1,2) double vb34[g_dim]; // displacement vector from atom i3 towards atom i4 // vb34[d] = x[i4][d] - x[i3][d] (for d=0,1,2) // n123 & n234: These two unit vectors are normal to the planes // defined by atoms 1,2,3 and 2,3,4. double n123[g_dim]; //n123=vb23 x vb12 / |vb23 x vb12| ("x" is cross product) double n234[g_dim]; //n234=vb23 x vb34 / |vb23 x vb34| ("x" is cross product) // The next 4 vectors are needed to calculate dphi_dx = d phi / dx double proj12on23[g_dim]; // proj12on23[d] = (vb23[d]/|vb23|) * dot3(vb12,vb23)/|vb12|*|vb23| double proj34on23[g_dim]; // proj34on23[d] = (vb34[d]/|vb23|) * dot3(vb34,vb23)/|vb34|*|vb23| double perp12on23[g_dim]; // perp12on23[d] = v12[d] - proj12on23[d] double perp34on23[g_dim]; // perp34on23[d] = v34[d] - proj34on23[d] edihedral = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; for (n = 0; n < ndihedrallist; n++) { i1 = dihedrallist[n][0]; i2 = dihedrallist[n][1]; i3 = dihedrallist[n][2]; i4 = dihedrallist[n][3]; type = dihedrallist[n][4]; // ------ Step 1: Compute the dihedral angle "phi" ------ // // Phi() calculates the dihedral angle. // This function also calculates the vectors: // vb12, vb23, vb34, n123, and n234, which we will need later. double phi = Phi(x[i1], x[i2], x[i3], x[i4], domain, vb12, vb23, vb34, n123, n234); // Step 2: Compute the gradients of phi, theta1, theta2 with atom position: // ===================== Step2a) phi dependence: ======================== // // Gradient variables: // // dphi_dx1, dphi_dx2, dphi_dx3, dphi_dx4 are the gradients of phi with // respect to the atomic positions of atoms i1, i2, i3, i4, respectively. // As an example, consider dphi_dx1. The d'th element is: double dphi_dx1[g_dim]; // d phi double dphi_dx2[g_dim]; // dphi_dx1[d] = ---------- (partial derivatives) double dphi_dx3[g_dim]; // d x[i1][d] double dphi_dx4[g_dim]; //where d=0,1,2 corresponds to x,y,z (g_dim==3) double dot123 = dot3(vb12, vb23); double dot234 = dot3(vb23, vb34); double L23sqr = dot3(vb23, vb23); double L23 = sqrt(L23sqr); // (central bond length) double inv_L23sqr = 0.0; double inv_L23 = 0.0; if (L23sqr != 0.0) { inv_L23sqr = 1.0 / L23sqr; inv_L23 = 1.0 / L23; } double neg_inv_L23 = -inv_L23; double dot123_over_L23sqr = dot123 * inv_L23sqr; double dot234_over_L23sqr = dot234 * inv_L23sqr; for (int d=0; d < g_dim; ++d) { // See figure above for a visual definitions of these vectors: proj12on23[d] = vb23[d] * dot123_over_L23sqr; proj34on23[d] = vb23[d] * dot234_over_L23sqr; perp12on23[d] = vb12[d] - proj12on23[d]; perp34on23[d] = vb34[d] - proj34on23[d]; } // --- Compute the gradient vectors dphi/dx1 and dphi/dx4: --- // These two gradients point in the direction of n123 and n234, // and are scaled by the distances of atoms 1 and 4 from the central axis. // Distance of atom 1 to central axis: double perp12on23_len = sqrt(dot3(perp12on23, perp12on23)); // Distance of atom 4 to central axis: double perp34on23_len = sqrt(dot3(perp34on23, perp34on23)); double inv_perp12on23 = 0.0; if (perp12on23_len != 0.0) inv_perp12on23 = 1.0 / perp12on23_len; double inv_perp34on23 = 0.0; if (perp34on23_len != 0.0) inv_perp34on23 = 1.0 / perp34on23_len; for (int d=0; d < g_dim; ++d) { dphi_dx1[d] = n123[d] * inv_perp12on23; dphi_dx4[d] = n234[d] * inv_perp34on23; } // --- Compute the gradient vectors dphi/dx2 and dphi/dx3: --- // // This is more tricky because atoms 2 and 3 are shared by both planes // 123 and 234 (the angle between which defines "phi"). Moving either // one of these atoms effects both the 123 and 234 planes // Both the 123 and 234 planes intersect with the plane perpendicular to the // central bond axis (vb23). The two lines where these intersections occur // will shift when you move either atom 2 or atom 3. The angle between // these lines is the dihedral angle, phi. We can define four quantities: // dphi123_dx2 is the change in "phi" due to the movement of the 123 plane // ...as a result of moving atom 2. // dphi234_dx2 is the change in "phi" due to the movement of the 234 plane // ...as a result of moving atom 2. // dphi123_dx3 is the change in "phi" due to the movement of the 123 plane // ...as a result of moving atom 3. // dphi234_dx3 is the change in "phi" due to the movement of the 234 plane // ...as a result of moving atom 3. double proj12on23_len = dot123 * inv_L23; double proj34on23_len = dot234 * inv_L23; // Interpretation: //The magnitude of "proj12on23_len" is the length of the proj12on23 vector. //The sign is positive if it points in the same direction as the central //bond (vb23). Otherwise it is negative. The same goes for "proj34on23". //(In the example figure in the comment above, both variables are positive.) // The following 8 lines of code are used to calculate the gradient of phi // with respect to the two "middle" atom positions (x[i2] and x[i3]). // For an explanation of the formula used below, download the file // "dihedral_table_2011-8-02.tar.gz" at the bottom of this post: // http://lammps.sandia.gov/threads/msg22233.html // Unpack it and go to this subdirectory: // "supporting_information/doc/gradient_formula_explanation/" double dphi123_dx2_coef = neg_inv_L23 * (L23 + proj12on23_len); double dphi234_dx2_coef = inv_L23 * proj34on23_len; double dphi234_dx3_coef = neg_inv_L23 * (L23 + proj34on23_len); double dphi123_dx3_coef = inv_L23 * proj12on23_len; for (int d=0; d < g_dim; ++d) { // Recall that the n123 and n234 plane normal vectors are proportional to // the dphi/dx1 and dphi/dx2 gradients vectors // It turns out we can save slightly more CPU cycles by expressing // dphi/dx2 and dphi/dx3 as linear combinations of dphi/dx1 and dphi/dx2 // which we computed already (instead of n123 & n234). dphi_dx2[d] = dphi123_dx2_coef*dphi_dx1[d] + dphi234_dx2_coef*dphi_dx4[d]; dphi_dx3[d] = dphi123_dx3_coef*dphi_dx1[d] + dphi234_dx3_coef*dphi_dx4[d]; } // ============= Step2b) theta1 and theta2 dependence: ============= // --- Compute the gradient vectors dtheta1/dx1 and dtheta2/dx4: --- // These two gradients point in the direction of n123 and n234, // and are scaled by the distances of atoms 1 and 4 from the central axis. // Distance of atom 1 to central axis: double dth1_dx1[g_dim]; // d theta1 (partial double dth1_dx2[g_dim]; // dth1_dx1[d] = ---------- derivative) double dth1_dx3[g_dim]; // d x[i1][d] //Note dth1_dx4 = 0 //Note dth2_dx1 = 0 double dth2_dx2[g_dim]; // d theta2 (partial double dth2_dx3[g_dim]; // dth2_dx1[d] = ---------- derivative) double dth2_dx4[g_dim]; // d x[i1][d] //where d=0,1,2 corresponds to x,y,z (g_dim==3) double L12sqr = dot3(vb12, vb12); double L12 = sqrt(L12sqr); double L34sqr = dot3(vb34, vb34); double L34 = sqrt(L34sqr); double inv_L12sqr = 0.0; double inv_L12 = 0.0; double inv_L34sqr = 0.0; double inv_L34 = 0.0; if (L12sqr != 0.0) { inv_L12sqr = 1.0 / L12sqr; inv_L12 = 1.0 / L12; } if (L34sqr != 0.0) { inv_L34sqr = 1.0 / L34sqr; inv_L34 = 1.0 / L34; } // The next 2 vectors are needed for calculating dth1_dx = d theta1 / d x double proj23on12[g_dim]; // proj23on12[d] = (vb12[d]/|vb12|) * dot3(vb23,vb12)/|vb23|*|vb12| double perp23on12[g_dim]; // perp23on12[d] = v23[d] - proj23on12[d] // The next 2 vectors are needed for calculating dth2_dx = d theta2 / d x double proj23on34[g_dim]; // proj23on34[d] = (vb23[d]/|vb34|) * dot3(vb23,vb34)/|vb23|*|vb34| double perp23on34[g_dim]; // perp23on34[d] = v23[d] - proj23on34[d] double dot123_over_L12sqr = dot123 * inv_L12sqr; double dot234_over_L34sqr = dot234 * inv_L34sqr; /* __ . * proj23on12 .\ . * . . proj23on34 * . . * . . * x[i2] . _./ x[i3] * __@----------vb23-------->@ * /| / \ \ * / theta1 theta2 \ * / <-' `-> \ * / \ * / \ * vb12 \ * / vb34 * / \ * / \ * / \ * @ \ * _\| * x[i1] @ * * x[i4] */ for (int d=0; d < g_dim; ++d) { // See figure above for a visual definitions of these vectors: proj23on12[d] = vb12[d] * dot123_over_L12sqr; proj23on34[d] = vb34[d] * dot234_over_L34sqr; perp23on12[d] = vb23[d] - proj23on12[d]; perp23on34[d] = vb23[d] - proj23on34[d]; } double perp23on12_len = sqrt(dot3(perp23on12, perp23on12)); double perp23on34_len = sqrt(dot3(perp23on34, perp23on34)); double inv_perp23on12 = 0.0; if (perp23on12_len != 0.0) inv_perp23on12 = 1.0 / perp23on12_len; double inv_perp23on34 = 0.0; if (perp23on34_len != 0.0) inv_perp23on34 = 1.0 / perp23on34_len; double coeff_dth1_dx1 = -inv_perp23on12 * inv_L12; double coeff_dth1_dx3 = inv_perp12on23 * inv_L23; double coeff_dth2_dx2 = -inv_perp34on23 * inv_L23; double coeff_dth2_dx4 = inv_perp23on34 * inv_L34; for (int d=0; d < g_dim; ++d) { dth1_dx1[d] = perp23on12[d] * coeff_dth1_dx1; dth1_dx3[d] = perp12on23[d] * coeff_dth1_dx3; dth1_dx2[d] = -(dth1_dx1[d] + dth1_dx3[d]); //dtheta1_dx4 = 0 //dtheta2_dx1 = 0 dth2_dx2[d] = perp34on23[d] * coeff_dth2_dx2; dth2_dx4[d] = perp23on34[d] * coeff_dth2_dx4; dth2_dx3[d] = -(dth2_dx2[d] + dth2_dx4[d]); } double ct1 = -dot123 * inv_L12 * inv_L23; if (ct1 < -1.0) ct1 = -1.0; else if (ct1 > 1.0) ct1 = 1.0; double theta1 = acos(ct1); double ct2 = -dot234 * inv_L23 * inv_L34; if (ct2 < -1.0) ct2 = -1.0; else if (ct2 > 1.0) ct2 = 1.0; double theta2 = acos(ct2); // - Step 3: Calculate the energy and force in the phi & theta1/2 directions double u=0.0; // u = energy double m_du_dth1 = 0.0; // m_du_dth1 = -du / d theta1 double m_du_dth2 = 0.0; // m_du_dth2 = -du / d theta2 double m_du_dphi = 0.0; // m_du_dphi = -du / d phi u = CalcGeneralizedForces(type, phi, theta1, theta2, &m_du_dth1, &m_du_dth2, &m_du_dphi); if (eflag) edihedral = u; // ----- Step 4: Calculate the force direction in real space ----- // chain rule: // d U d U d phi d U d theta1 d U d theta2 // -f = ----- = ----- * ----- + -------*------- + --------*-------- // d x d phi d x d theta1 d X d theta2 d X for(int d=0; d < g_dim; ++d) { f1[d] = m_du_dphi*dphi_dx1[d]+m_du_dth1*dth1_dx1[d]; //note: dth2_dx1[d]=0 f2[d] = m_du_dphi*dphi_dx2[d]+m_du_dth1*dth1_dx2[d]+m_du_dth2*dth2_dx2[d]; f3[d] = m_du_dphi*dphi_dx3[d]+m_du_dth1*dth1_dx3[d]+m_du_dth2*dth2_dx3[d]; f4[d] = m_du_dphi*dphi_dx4[d] + m_du_dth2*dth2_dx4[d]; //note: dth1_dx4[d] = 0 } // apply force to each of 4 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += f1[0]; f[i1][1] += f1[1]; f[i1][2] += f1[2]; } if (newton_bond || i2 < nlocal) { f[i2][0] += f2[0]; f[i2][1] += f2[1]; f[i2][2] += f2[2]; } if (newton_bond || i3 < nlocal) { f[i3][0] += f3[0]; f[i3][1] += f3[1]; f[i3][2] += f3[2]; } if (newton_bond || i4 < nlocal) { f[i4][0] += f4[0]; f[i4][1] += f4[1]; f[i4][2] += f4[2]; } if (evflag) ev_tally(i1,i2,i3,i4, nlocal,newton_bond,edihedral, f1,f3,f4, vb12[0],vb12[1],vb12[2], vb23[0],vb23[1],vb23[2], vb34[0],vb34[1],vb34[2]); } } // void DihedralSpherical::compute() // --- CalcGeneralizedForces() --- // --- Calculate the energy as a function of theta1, theta2, and phi --- // --- as well as its derivatives (with respect to theta1, theta2, and phi) --- // The code above above is sufficiently general that it can work with any // any function of the angles theta1, theta2, and phi. However the // function below calculates the energy and force according to this specific // formula: // // E(\theta_1,\theta_2,\phi) = // \sum_{i=1}^N C_i \Theta_{1i}(\theta_1) \Theta_{2i}(\theta_2) \Phi_i(\phi) // where: // \Theta_{1i}(\theta_1) = cos((\theta_1-a_i)K_i) + u_i // \Theta_{2i}(\theta_2) = cos((\theta_2-b_i)L_i) + v_i // \Phi_i(\phi) = cos((\phi - c_i)M_i) + w_i double DihedralSpherical:: CalcGeneralizedForces(int type, double phi, double theta1, double theta2, double *m_du_dth1, double *m_du_dth2, double *m_du_dphi) { double energy = 0.0; assert(m_du_dphi && m_du_dphi && m_du_dphi); *m_du_dphi = 0.0; *m_du_dth1 = 0.0; *m_du_dth2 = 0.0; int i = type; for (int j = 0; j < nterms[i]; j++) { // (It's common that some terms in an expansion have phi_multi[i][j]=0. // When this happens, perhaps it will speed up the calculation to avoid // unnecessary calls to the cos() and sin() functions. Check this below) // I also check whether theta1_mult[i][j] and theta2_mult[i][j] are 0. double cp = 1.0; double sp = 0.0; if (phi_mult[i][j] != 0.0) { double p = phi_mult[i][j] * (phi - phi_shift[i][j]); cp = cos(p); sp = sin(p); } double ct1 = 1.0; double st1 = 0.0; if (theta1_mult[i][j] != 0.0) { double t1 = theta1_mult[i][j]*(theta1 - theta1_shift[i][j]); ct1 = cos(t1); st1 = sin(t1); } double ct2 = 1.0; double st2 = 0.0; if (theta2_mult[i][j] != 0.0) { double t2 = theta2_mult[i][j]*(theta2 - theta2_shift[i][j]); ct2 = cos(t2); st2 = sin(t2); } energy += Ccoeff[i][j] * (phi_offset[i][j] - cp) * (theta1_offset[i][j] - ct1) * (theta2_offset[i][j] - ct2); // Forces: *m_du_dphi += -Ccoeff[i][j] * sp * phi_mult[i][j] * (theta1_offset[i][j] - ct1) * (theta2_offset[i][j] - ct2); *m_du_dth1 += -Ccoeff[i][j] * (phi_offset[i][j] - cp) * st1 * theta1_mult[i][j] * (theta2_offset[i][j] - ct2); *m_du_dth2 += -Ccoeff[i][j] * (phi_offset[i][j] - cp) * (theta1_offset[i][j] - ct1) * st2 * theta2_mult[i][j]; // Things to consider later: // To speed up the computation, one could try to simplify the expansion: // IE by factoring out common terms, and precomputing trig functions once: // cos(K*theta1), sin(K*theta1), // cos(L*theta2), sin(L*theta2), and // cos(M*phi), sin(M*phi) // Also: For integer K,L,M, the trig functions cos(M*phi) and sin(M*phi) // can be calculated more efficiently using polynomials of // cos(phi) and sin(phi) } //for (int j = 0; j < nterms[i]; j++) { return energy; } //CalcGeneralizedForces() void DihedralSpherical::allocate() { allocated = 1; int n = atom->ndihedraltypes; memory->create(nterms,n+1,"dihedral:nterms"); Ccoeff = new double * [n+1]; phi_mult = new double * [n+1]; phi_shift = new double * [n+1]; phi_offset = new double * [n+1]; theta1_mult = new double * [n+1]; theta1_shift = new double * [n+1]; theta1_offset = new double * [n+1]; theta2_mult = new double * [n+1]; theta2_shift = new double * [n+1]; theta2_offset = new double * [n+1]; for (int i = 1; i <= n; i++) { Ccoeff[i] = NULL; phi_mult[i] = NULL; phi_shift[i] = NULL; phi_offset[i] = NULL; theta1_mult[i] = NULL; theta1_shift[i] = NULL; theta1_offset[i] = NULL; theta2_mult[i] = NULL; theta2_shift[i] = NULL; theta2_offset[i] = NULL; } memory->create(setflag,n+1,"dihedral:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one type ------------------------------------------------------------------------- */ void DihedralSpherical::coeff(int narg, char **arg) { if (narg < 4) error->all(FLERR,"Incorrect args for dihedral coefficients"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->ndihedraltypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->ndihedraltypes,ilo,ihi); int nterms_one = force->inumeric(FLERR,arg[1]); if (nterms_one < 1) error->all(FLERR,"Incorrect number of terms arg for dihedral coefficients"); if (2+10*nterms_one < narg) error->all(FLERR,"Incorrect number of arguments for dihedral coefficients"); int count = 0; for (int i = ilo; i <= ihi; i++) { nterms[i] = nterms_one; Ccoeff[i] = new double [nterms_one]; phi_mult[i] = new double [nterms_one]; phi_shift[i] = new double [nterms_one]; phi_offset[i] = new double [nterms_one]; theta1_mult[i] = new double [nterms_one]; theta1_shift[i] = new double [nterms_one]; theta1_offset[i] = new double [nterms_one]; theta2_mult[i] = new double [nterms_one]; theta2_shift[i] = new double [nterms_one]; theta2_offset[i] = new double [nterms_one]; for (int j = 0; j < nterms_one; j++) { int offset = 1+10*j; Ccoeff[i][j] = force->numeric(FLERR,arg[offset+1]); phi_mult[i][j] = force->numeric(FLERR,arg[offset+2]); phi_shift[i][j] = force->numeric(FLERR,arg[offset+3]) * MY_PI/180.0; phi_offset[i][j] = force->numeric(FLERR,arg[offset+4]); theta1_mult[i][j] = force->numeric(FLERR,arg[offset+5]); theta1_shift[i][j] = force->numeric(FLERR,arg[offset+6]) * MY_PI/180.0; theta1_offset[i][j] = force->numeric(FLERR,arg[offset+7]); theta2_mult[i][j] = force->numeric(FLERR,arg[offset+8]); theta2_shift[i][j] = force->numeric(FLERR,arg[offset+9]) * MY_PI/180.0; theta2_offset[i][j] = force->numeric(FLERR,arg[offset+10]); } setflag[i] = 1; count++; } if (count == 0) error->all(FLERR,"Incorrect args for dihedral coefficients"); } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void DihedralSpherical::write_restart(FILE *fp) { fwrite(&nterms[1],sizeof(int),atom->ndihedraltypes,fp); for(int i = 1; i <= atom->ndihedraltypes; i++) { fwrite(Ccoeff[i],sizeof(double),nterms[i],fp); fwrite(phi_mult[i],sizeof(double),nterms[i],fp); fwrite(phi_shift[i],sizeof(double),nterms[i],fp); fwrite(phi_offset[i],sizeof(double),nterms[i],fp); fwrite(theta1_mult[i],sizeof(double),nterms[i],fp); fwrite(theta1_shift[i],sizeof(double),nterms[i],fp); fwrite(theta1_offset[i],sizeof(double),nterms[i],fp); fwrite(theta2_mult[i],sizeof(double),nterms[i],fp); fwrite(theta2_shift[i],sizeof(double),nterms[i],fp); fwrite(theta2_offset[i],sizeof(double),nterms[i],fp); } } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void DihedralSpherical::read_restart(FILE *fp) { allocate(); if (comm->me == 0) fread(&nterms[1],sizeof(int),atom->ndihedraltypes,fp); MPI_Bcast(&nterms[1],atom->ndihedraltypes,MPI_INT,0,world); // allocate for (int i=1; i<=atom->ndihedraltypes; i++) { Ccoeff[i] = new double [nterms[i]]; phi_mult[i] = new double [nterms[i]]; phi_shift[i] = new double [nterms[i]]; phi_offset[i] = new double [nterms[i]]; theta1_mult[i] = new double [nterms[i]]; theta1_shift[i] = new double [nterms[i]]; theta1_offset[i] = new double [nterms[i]]; theta2_mult[i] = new double [nterms[i]]; theta2_shift[i] = new double [nterms[i]]; theta2_offset[i] = new double [nterms[i]]; } if (comm->me == 0) { for (int i=1; i<=atom->ndihedraltypes; i++) { fread(Ccoeff[i],sizeof(double),nterms[i],fp); fread(phi_mult[i],sizeof(double),nterms[i],fp); fread(phi_shift[i],sizeof(double),nterms[i],fp); fread(phi_offset[i],sizeof(double),nterms[i],fp); fread(theta1_mult[i],sizeof(double),nterms[i],fp); fread(theta1_shift[i],sizeof(double),nterms[i],fp); fread(theta1_offset[i],sizeof(double),nterms[i],fp); fread(theta2_mult[i],sizeof(double),nterms[i],fp); fread(theta2_shift[i],sizeof(double),nterms[i],fp); fread(theta2_offset[i],sizeof(double),nterms[i],fp); } } for (int i=1; i<=atom->ndihedraltypes; i++) { MPI_Bcast(Ccoeff[i],nterms[i],MPI_DOUBLE,0,world); MPI_Bcast(phi_mult[i],nterms[i],MPI_DOUBLE,0,world); MPI_Bcast(phi_shift[i],nterms[i],MPI_DOUBLE,0,world); MPI_Bcast(phi_offset[i],nterms[i],MPI_DOUBLE,0,world); MPI_Bcast(theta1_mult[i],nterms[i],MPI_DOUBLE,0,world); MPI_Bcast(theta1_shift[i],nterms[i],MPI_DOUBLE,0,world); MPI_Bcast(theta1_offset[i],nterms[i],MPI_DOUBLE,0,world); MPI_Bcast(theta2_mult[i],nterms[i],MPI_DOUBLE,0,world); MPI_Bcast(theta2_shift[i],nterms[i],MPI_DOUBLE,0,world); MPI_Bcast(theta2_offset[i],nterms[i],MPI_DOUBLE,0,world); } for (int i = 1; i <= atom->ndihedraltypes; i++) setflag[i] = 1; } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void DihedralSpherical::write_data(FILE *fp) { for (int i = 1; i <= atom->ndihedraltypes; i++) { fprintf(fp,"%d %d ", i , nterms[i]); for (int j = 0; j < nterms[i]; j++) { fprintf(fp, "%g %g %g %g %g %g %g %g %g ", phi_mult[i][j], phi_shift[i][j], phi_offset[i][j], theta1_mult[i][j], theta1_shift[i][j], theta1_offset[i][j], theta2_mult[i][j], theta2_shift[i][j], theta2_offset[i][j]); } fprintf(fp,"\n"); } } // Not needed? // single() calculates the dihedral-angle energy of atoms i1, i2, i3, i4. //double DihedralSpherical::single(int type, int i1, int i2, int i3, int i4) //{ // //variables we will need // double vb12[g_dim]; // double vb23[g_dim]; // double vb34[g_dim]; // // // Some functions calculate numbers we don't care about. Store in variables: // double n123[g_dim]; // (will be ignored) // double n234[g_dim]; // (will be ignored) // double m_du_dth1; // (will be ignored) // double m_du_dth2; // (will be ignored) // double m_du_dphi; // (will be ignored) // // double **x = atom->x; // // // Calculate the 4-body angle: phi // double phi = Phi(x[i1], x[i2], x[i3], x[i4], domain, // vb12, vb23, vb34, n123, n234); // // // Calculate the 3-body angles: theta1 and theta2 // double L12 = sqrt(dot3(vb12, vb12)); // double L23 = sqrt(dot3(vb23, vb23)); // double L34 = sqrt(dot3(vb34, vb34)); // // double ct1 = -dot3(vb12, vb23) / (L12 * L23); // if (ct1 < -1.0) ct1 = -1.0; // else if (ct1 > 1.0) ct1 = 1.0; // double theta1 = acos(ct1); // // double ct2 = -dot3(vb23, vb34) / (L23 * L34); // if (ct2 < -1.0) ct2 = -1.0; // else if (ct2 > 1.0) ct2 = 1.0; // double theta2 = acos(ct2); // // double u = CalcGeneralizedForces(type, // phi, theta1, theta2, // &m_du_dth1, &m_du_dth2, &m_du_dphi); // return u; //} diff --git a/src/USER-MISC/dihedral_table.cpp b/src/USER-MISC/dihedral_table.cpp index 4e3b05bc4..f84814cc5 100644 --- a/src/USER-MISC/dihedral_table.cpp +++ b/src/USER-MISC/dihedral_table.cpp @@ -1,1421 +1,1421 @@ /* ---------------------------------------------------------------------- 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: Andrew Jewett (jewett.aij g m ail) The cyclic tridiagonal matrix solver was borrowed from the "tridiag.c" written by Gerard Jungman for GSL ------------------------------------------------------------------------- */ #include #include #include #include #include #include #include #include #include "atom.h" #include "comm.h" #include "neighbor.h" #include "domain.h" #include "force.h" #include "update.h" #include "memory.h" #include "error.h" #include "dihedral_table.h" #include "math_const.h" #include "math_extra.h" using namespace std; using namespace LAMMPS_NS; using namespace MathConst; using namespace MathExtra; // ------------------------------------------------------------------------ // The following auxiliary functions were left out of the // DihedralTable class either because they require template parameters, // or because they have nothing to do with dihedral angles. // ------------------------------------------------------------------------ // ------------------------------------------------------------------- // --------- The function was stolen verbatim from the --------- // --------- GNU Scientific Library (GSL, version 1.15) --------- // ------------------------------------------------------------------- /* Author: Gerard Jungman */ /* for description of method see [Engeln-Mullges + Uhlig, p. 96] * * diag[0] offdiag[0] 0 ..... offdiag[N-1] * offdiag[0] diag[1] offdiag[1] ..... * 0 offdiag[1] diag[2] * 0 0 offdiag[2] ..... * ... ... * offdiag[N-1] ... * */ // -- (A non-symmetric version of this function is also available.) -- enum { //GSL status return codes. GSL_FAILURE = -1, GSL_SUCCESS = 0, GSL_ENOMEM = 8, GSL_EZERODIV = 12, GSL_EBADLEN = 19 }; static int solve_cyc_tridiag( const double diag[], size_t d_stride, const double offdiag[], size_t o_stride, const double b[], size_t b_stride, double x[], size_t x_stride, size_t N, bool warn) { int status = GSL_SUCCESS; double * delta = (double *) malloc (N * sizeof (double)); double * gamma = (double *) malloc (N * sizeof (double)); double * alpha = (double *) malloc (N * sizeof (double)); double * c = (double *) malloc (N * sizeof (double)); double * z = (double *) malloc (N * sizeof (double)); if (delta == 0 || gamma == 0 || alpha == 0 || c == 0 || z == 0) { if (warn) fprintf(stderr,"Internal Cyclic Spline Error: failed to allocate working space\n"); if (delta) free(delta); if (gamma) free(gamma); if (alpha) free(alpha); if (c) free(c); if (z) free(z); return GSL_ENOMEM; } else { size_t i, j; double sum = 0.0; /* factor */ if (N == 1) { x[0] = b[0] / diag[0]; free(delta); free(gamma); free(alpha); free(c); free(z); return GSL_SUCCESS; } alpha[0] = diag[0]; gamma[0] = offdiag[0] / alpha[0]; delta[0] = offdiag[o_stride * (N-1)] / alpha[0]; if (alpha[0] == 0) { status = GSL_EZERODIV; } for (i = 1; i < N - 2; i++) { alpha[i] = diag[d_stride * i] - offdiag[o_stride * (i-1)] * gamma[i - 1]; gamma[i] = offdiag[o_stride * i] / alpha[i]; delta[i] = -delta[i - 1] * offdiag[o_stride * (i-1)] / alpha[i]; if (alpha[i] == 0) { status = GSL_EZERODIV; } } for (i = 0; i < N - 2; i++) { sum += alpha[i] * delta[i] * delta[i]; } alpha[N - 2] = diag[d_stride * (N - 2)] - offdiag[o_stride * (N - 3)] * gamma[N - 3]; gamma[N - 2] = (offdiag[o_stride * (N - 2)] - offdiag[o_stride * (N - 3)] * delta[N - 3]) / alpha[N - 2]; alpha[N - 1] = diag[d_stride * (N - 1)] - sum - alpha[(N - 2)] * gamma[N - 2] * gamma[N - 2]; /* update */ z[0] = b[0]; for (i = 1; i < N - 1; i++) { z[i] = b[b_stride * i] - z[i - 1] * gamma[i - 1]; } sum = 0.0; for (i = 0; i < N - 2; i++) { sum += delta[i] * z[i]; } z[N - 1] = b[b_stride * (N - 1)] - sum - gamma[N - 2] * z[N - 2]; for (i = 0; i < N; i++) { c[i] = z[i] / alpha[i]; } /* backsubstitution */ x[x_stride * (N - 1)] = c[N - 1]; x[x_stride * (N - 2)] = c[N - 2] - gamma[N - 2] * x[x_stride * (N - 1)]; if (N >= 3) { for (i = N - 3, j = 0; j <= N - 3; j++, i--) { x[x_stride * i] = c[i] - gamma[i] * x[x_stride * (i + 1)] - delta[i] * x[x_stride * (N - 1)]; } } } free (z); free (c); free (alpha); free (gamma); free (delta); if ((status == GSL_EZERODIV) && warn) fprintf(stderr, "Internal Cyclic Spline Error: Matrix must be positive definite.\n"); return status; } //solve_cyc_tridiag() /* ---------------------------------------------------------------------- spline and splint routines modified from Numerical Recipes ------------------------------------------------------------------------- */ static int cyc_spline(double const *xa, double const *ya, int n, double period, double *y2a, bool warn) { double *diag = new double[n]; double *offdiag = new double[n]; double *rhs = new double[n]; double xa_im1, xa_ip1; // In the cyclic case, there are n equations with n unknows. // The for loop sets up the equations we need to solve. // Later we invoke the GSL tridiagonal matrix solver to solve them. for(int i=0; i < n; i++) { // I have to lookup xa[i+1] and xa[i-1]. This gets tricky because of // periodic boundary conditions. We handle that now. int im1 = i-1; if (im1<0) { im1 += n; xa_im1 = xa[im1] - period; } else xa_im1 = xa[im1]; int ip1 = i+1; if (ip1>=n) { ip1 -= n; xa_ip1 = xa[ip1] + period; } else xa_ip1 = xa[ip1]; // Recall that we want to find the y2a[] parameters (there are n of them). // To solve for them, we have a linear equation with n unknowns // (in the cyclic case that is). For details, the non-cyclic case is // explained in equation 3.3.7 in Numerical Recipes in C, p. 115. diag[i] = (xa_ip1 - xa_im1) / 3.0; offdiag[i] = (xa_ip1 - xa[i]) / 6.0; rhs[i] = ((ya[ip1] - ya[i]) / (xa_ip1 - xa[i])) - ((ya[i] - ya[im1]) / (xa[i] - xa_im1)); } // Because this matrix is tridiagonal (and cyclic), we can use the following // cheap method to invert it. if (solve_cyc_tridiag(diag, 1, offdiag, 1, rhs, 1, y2a, 1, n, warn) != GSL_SUCCESS) { if (warn) fprintf(stderr,"Error in inverting matrix for splines.\n"); delete [] diag; delete [] offdiag; delete [] rhs; return 1; } delete [] diag; delete [] offdiag; delete [] rhs; return 0; } // cyc_spline() /* ---------------------------------------------------------------------- */ // cyc_splint(): Evaluates a spline at position x, with n control // points located at xa[], ya[], and with parameters y2a[] // The xa[] must be monotonically increasing and their // range should not exceed period (ie xa[n-1] < xa[0] + period). // x must lie in the range: [(xa[n-1]-period), (xa[0]+period)] // "period" is typically 2*PI. static double cyc_splint(double const *xa, double const *ya, double const *y2a, int n, double period, double x) { int klo = -1; int khi = n; int k; double xlo = xa[n-1] - period; double xhi = xa[0] + period; while (khi-klo > 1) { k = (khi+klo) >> 1; //(k=(khi+klo)/2) if (xa[k] > x) { khi = k; xhi = xa[k]; } else { klo = k; xlo = xa[k]; } } if (khi == n) khi = 0; if (klo ==-1) klo = n-1; double h = xhi-xlo; double a = (xhi-x) / h; double b = (x-xlo) / h; double 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; } // cyc_splint() static double cyc_lin(double const *xa, double const *ya, int n, double period, double x) { int klo = -1; int khi = n; int k; double xlo = xa[n-1] - period; double xhi = xa[0] + period; while (khi-klo > 1) { k = (khi+klo) >> 1; //(k=(khi+klo)/2) if (xa[k] > x) { khi = k; xhi = xa[k]; } else { klo = k; xlo = xa[k]; } } if (khi == n) khi = 0; if (klo ==-1) klo = n-1; double h = xhi-xlo; double a = (xhi-x) / h; double b = (x-xlo) / h; double y = a*ya[klo] + b*ya[khi]; return y; } // cyc_lin() // cyc_splintD(): Evaluate the deriviative of a cyclic spline at position x, // with n control points at xa[], ya[], with parameters y2a[]. // The xa[] must be monotonically increasing and their // range should not exceed period (ie xa[n-1] < xa[0] + period). // x must lie in the range: [(xa[n-1]-period), (xa[0]+period)] // "period" is typically 2*PI. static double cyc_splintD(double const *xa, double const *ya, double const *y2a, int n, double period, double x) { int klo = -1; int khi = n; // (not n-1) int k; double xlo = xa[n-1] - period; double xhi = xa[0] + period; while (khi-klo > 1) { k = (khi+klo) >> 1; //(k=(khi+klo)/2) if (xa[k] > x) { khi = k; xhi = xa[k]; } else { klo = k; xlo = xa[k]; } } if (khi == n) khi = 0; if (klo ==-1) klo = n-1; double yhi = ya[khi]; double ylo = ya[klo]; double h = xhi-xlo; double g = yhi-ylo; double a = (xhi-x) / h; double b = (x-xlo) / h; // Formula below taken from equation 3.3.5 of "numerical recipes in c" // "yD" = the derivative of y double yD = g/h - ( (3.0*a*a-1.0)*y2a[klo] - (3.0*b*b-1.0)*y2a[khi] ) * h/6.0; // For rerefence: y = a*ylo + b*yhi + // ((a*a*a-a)*y2a[klo] + (b*b*b-b)*y2a[khi]) * (h*h)/6.0; return yD; } // cyc_splintD() // -------------------------------------------- // ------- Calculate the dihedral angle ------- // -------------------------------------------- static const int g_dim=3; static double Phi(double const *x1, //array holding x,y,z coords atom 1 double const *x2, // : : : : 2 double const *x3, // : : : : 3 double const *x4, // : : : : 4 Domain *domain, //<-periodic boundary information // The following arrays are of doubles with g_dim elements. // (g_dim is a constant known at compile time, usually 3). // Their contents is calculated by this function. // Space for these vectors must be allocated in advance. // (This is not hidden internally because these vectors // may be needed outside the function, later on.) double *vb12, // will store x2-x1 double *vb23, // will store x3-x2 double *vb34, // will store x4-x3 double *n123, // will store normal to plane x1,x2,x3 double *n234) // will store normal to plane x2,x3,x4 { for (int d=0; d < g_dim; ++d) { vb12[d] = x2[d] - x1[d]; // 1st bond vb23[d] = x3[d] - x2[d]; // 2nd bond vb34[d] = x4[d] - x3[d]; // 3rd bond } //Consider periodic boundary conditions: domain->minimum_image(vb12[0],vb12[1],vb12[2]); domain->minimum_image(vb23[0],vb23[1],vb23[2]); domain->minimum_image(vb34[0],vb34[1],vb34[2]); //--- Compute the normal to the planes formed by atoms 1,2,3 and 2,3,4 --- cross3(vb23, vb12, n123); // <- n123=vb23 x vb12 cross3(vb23, vb34, n234); // <- n234=vb23 x vb34 norm3(n123); norm3(n234); double cos_phi = -dot3(n123, n234); if (cos_phi > 1.0) cos_phi = 1.0; else if (cos_phi < -1.0) cos_phi = -1.0; double phi = acos(cos_phi); if (dot3(n123, vb34) > 0.0) { phi = -phi; //(Note: Negative dihedral angles are possible only in 3-D.) phi += MY_2PI; //<- This insure phi is always in the range 0 to 2*PI } return phi; } // DihedralTable::Phi() /* ---------------------------------------------------------------------- */ DihedralTable::DihedralTable(LAMMPS *lmp) : Dihedral(lmp) { ntables = 0; tables = NULL; checkU_fname = checkF_fname = NULL; } /* ---------------------------------------------------------------------- */ DihedralTable::~DihedralTable() { for (int m = 0; m < ntables; m++) free_table(&tables[m]); memory->sfree(tables); memory->sfree(checkU_fname); memory->sfree(checkF_fname); if (allocated) { memory->destroy(setflag); //memory->destroy(phi0); <- equilibrium angles not supported memory->destroy(tabindex); } } /* ---------------------------------------------------------------------- */ void DihedralTable::compute(int eflag, int vflag) { int i1,i2,i3,i4,n,type; double edihedral,f1[3],f2[3],f3[3],f4[3]; double **x = atom->x; double **f = atom->f; int **dihedrallist = neighbor->dihedrallist; int ndihedrallist = neighbor->ndihedrallist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; // The dihedral angle "phi" is the angle between n123 and n234 // the planes defined by atoms i1,i2,i3, and i2,i3,i4. // // Definitions of vectors: vb12, vb23, vb34, perp12on23 // proj12on23, perp43on32, proj43on32 // // Note: The positions of the 4 atoms are labeled x[i1], x[i2], x[i3], x[i4] // (which are also vectors) // // proj12on23 proj34on23 // ---------> -----------> // . // . // . // x[i2] . x[i3] // . __@----------vb23-------->@ . . . . . // /|\ /| \ | // | / \ | // | / \ | // perp12vs23 / \ | // | / \ perp34vs23 // | vb12 \ | // | / vb34 | // | / \ | // | / \ | // | / \ | // @ \ | // _\| \|/ // x[i1] @ // // x[i4] // double vb12[g_dim]; // displacement vector from atom i1 towards atom i2 // vb12[d] = x[i2][d] - x[i1][d] (for d=0,1,2) double vb23[g_dim]; // displacement vector from atom i2 towards atom i3 // vb23[d] = x[i3][d] - x[i2][d] (for d=0,1,2) double vb34[g_dim]; // displacement vector from atom i3 towards atom i4 // vb34[d] = x[i4][d] - x[i3][d] (for d=0,1,2) // n123 & n234: These two unit vectors are normal to the planes // defined by atoms 1,2,3 and 2,3,4. double n123[g_dim]; //n123=vb23 x vb12 / |vb23 x vb12| ("x" is cross product) double n234[g_dim]; //n234=vb23 x vb34 / |vb23 x vb34| ("x" is cross product) double proj12on23[g_dim]; // proj12on23[d] = (vb23[d]/|vb23|) * dot3(vb12,vb23)/|vb12|*|vb23| double proj34on23[g_dim]; // proj34on23[d] = (vb34[d]/|vb23|) * dot3(vb34,vb23)/|vb34|*|vb23| double perp12on23[g_dim]; // perp12on23[d] = v12[d] - proj12on23[d] double perp34on23[g_dim]; // perp34on23[d] = v34[d] - proj34on23[d] edihedral = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; for (n = 0; n < ndihedrallist; n++) { i1 = dihedrallist[n][0]; i2 = dihedrallist[n][1]; i3 = dihedrallist[n][2]; i4 = dihedrallist[n][3]; type = dihedrallist[n][4]; // ------ Step 1: Compute the dihedral angle "phi" ------ // // Phi() calculates the dihedral angle. // This function also calculates the vectors: // vb12, vb23, vb34, n123, and n234, which we will need later. double phi = Phi(x[i1], x[i2], x[i3], x[i4], domain, vb12, vb23, vb34, n123, n234); // ------ Step 2: Compute the gradient of phi with atomic position: ------ // // Gradient variables: // // dphi_dx1, dphi_dx2, dphi_dx3, dphi_dx4 are the gradients of phi with // respect to the atomic positions of atoms i1, i2, i3, i4, respectively. // As an example, consider dphi_dx1. The d'th element is: double dphi_dx1[g_dim]; // d phi double dphi_dx2[g_dim]; // dphi_dx1[d] = ---------- (partial derivatives) double dphi_dx3[g_dim]; // d x[i1][d] double dphi_dx4[g_dim]; //where d=0,1,2 corresponds to x,y,z (if g_dim==3) double dot123 = dot3(vb12, vb23); double dot234 = dot3(vb23, vb34); double L23sqr = dot3(vb23, vb23); double L23 = sqrt(L23sqr); // (central bond length) double inv_L23sqr = 0.0; double inv_L23 = 0.0; if (L23sqr != 0.0) { inv_L23sqr = 1.0 / L23sqr; inv_L23 = 1.0 / L23; } double neg_inv_L23 = -inv_L23; double dot123_over_L23sqr = dot123 * inv_L23sqr; double dot234_over_L23sqr = dot234 * inv_L23sqr; for (int d=0; d < g_dim; ++d) { // See figure above for a visual definitions of these vectors: proj12on23[d] = vb23[d] * dot123_over_L23sqr; proj34on23[d] = vb23[d] * dot234_over_L23sqr; perp12on23[d] = vb12[d] - proj12on23[d]; perp34on23[d] = vb34[d] - proj34on23[d]; } // --- Compute the gradient vectors dphi/dx1 and dphi/dx4: --- // These two gradients point in the direction of n123 and n234, // and are scaled by the distances of atoms 1 and 4 from the central axis. // Distance of atom 1 to central axis: double perp12on23_len = sqrt(dot3(perp12on23, perp12on23)); // Distance of atom 4 to central axis: double perp34on23_len = sqrt(dot3(perp34on23, perp34on23)); double inv_perp12on23 = 0.0; if (perp12on23_len != 0.0) inv_perp12on23 = 1.0 / perp12on23_len; double inv_perp34on23 = 0.0; if (perp34on23_len != 0.0) inv_perp34on23 = 1.0 / perp34on23_len; for (int d=0; d < g_dim; ++d) { dphi_dx1[d] = n123[d] * inv_perp12on23; dphi_dx4[d] = n234[d] * inv_perp34on23; } // --- Compute the gradient vectors dphi/dx2 and dphi/dx3: --- // // This is more tricky because atoms 2 and 3 are shared by both planes // 123 and 234 (the angle between which defines "phi"). Moving either // one of these atoms effects both the 123 and 234 planes // Both the 123 and 234 planes intersect with the plane perpendicular to the // central bond axis (vb23). The two lines where these intersections occur // will shift when you move either atom 2 or atom 3. The angle between // these lines is the dihedral angle, phi. We can define four quantities: // dphi123_dx2 is the change in "phi" due to the movement of the 123 plane // ...as a result of moving atom 2. // dphi234_dx2 is the change in "phi" due to the movement of the 234 plane // ...as a result of moving atom 2. // dphi123_dx3 is the change in "phi" due to the movement of the 123 plane // ...as a result of moving atom 3. // dphi234_dx3 is the change in "phi" due to the movement of the 234 plane // ...as a result of moving atom 3. double proj12on23_len = dot123 * inv_L23; double proj34on23_len = dot234 * inv_L23; // Interpretation: //The magnitude of "proj12on23_len" is the length of the proj12on23 vector. //The sign is positive if it points in the same direction as the central //bond (vb23). Otherwise it is negative. The same goes for "proj34on23". //(In the example figure in the comment above, both variables are positive.) // The forumula used in the 8 lines below explained here: // "supporting_information/doc/gradient_formula_explanation/" double dphi123_dx2_coef = neg_inv_L23 * (L23 + proj12on23_len); double dphi234_dx2_coef = inv_L23 * proj34on23_len; double dphi234_dx3_coef = neg_inv_L23 * (L23 + proj34on23_len); double dphi123_dx3_coef = inv_L23 * proj12on23_len; for (int d=0; d < g_dim; ++d) { // Recall that the n123 and n234 plane normal vectors are proportional to // the dphi/dx1 and dphi/dx2 gradients vectors // It turns out we can save slightly more CPU cycles by expressing // dphi/dx2 and dphi/dx3 as linear combinations of dphi/dx1 and dphi/dx2 // which we computed already (instead of n123 & n234). dphi_dx2[d] = dphi123_dx2_coef*dphi_dx1[d] + dphi234_dx2_coef*dphi_dx4[d]; dphi_dx3[d] = dphi123_dx3_coef*dphi_dx1[d] + dphi234_dx3_coef*dphi_dx4[d]; } // ----- Step 3: Calculate the energy and force in the phi direction ----- // tabulated force & energy double u=0.0, m_du_dphi=0.0; //u = energy. m_du_dphi = "minus" du/dphi uf_lookup(type, phi, u, m_du_dphi); if (eflag) edihedral = u; // ----- Step 4: Calculate the force direction in real space ----- // chain rule: // d U d U d phi // -f = ----- = ----- * ----- // d x d phi d x for(int d=0; d < g_dim; ++d) { f1[d] = m_du_dphi * dphi_dx1[d]; f2[d] = m_du_dphi * dphi_dx2[d]; f3[d] = m_du_dphi * dphi_dx3[d]; f4[d] = m_du_dphi * dphi_dx4[d]; } // apply force to each of 4 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += f1[0]; f[i1][1] += f1[1]; f[i1][2] += f1[2]; } if (newton_bond || i2 < nlocal) { f[i2][0] += f2[0]; f[i2][1] += f2[1]; f[i2][2] += f2[2]; } if (newton_bond || i3 < nlocal) { f[i3][0] += f3[0]; f[i3][1] += f3[1]; f[i3][2] += f3[2]; } if (newton_bond || i4 < nlocal) { f[i4][0] += f4[0]; f[i4][1] += f4[1]; f[i4][2] += f4[2]; } if (evflag) ev_tally(i1,i2,i3,i4, nlocal,newton_bond,edihedral, f1,f3,f4, vb12[0],vb12[1],vb12[2], vb23[0],vb23[1],vb23[2], vb34[0],vb34[1],vb34[2]); } } // void DihedralTable::compute() // single() calculates the dihedral-angle energy of atoms i1, i2, i3, i4. double DihedralTable::single(int type, int i1, int i2, int i3, int i4) { double vb12[g_dim]; double vb23[g_dim]; double vb34[g_dim]; double n123[g_dim]; double n234[g_dim]; double **x = atom->x; double phi = Phi(x[i1], x[i2], x[i3], x[i4], domain, vb12, vb23, vb34, n123, n234); double u=0.0; u_lookup(type, phi, u); //Calculate the energy, and store it in "u" return u; } /* ---------------------------------------------------------------------- */ void DihedralTable::allocate() { allocated = 1; int n = atom->ndihedraltypes; memory->create(tabindex,n+1,"dihedral:tabindex"); //memory->create(phi0,n+1,"dihedral:phi0"); <-equilibrium angles not supported memory->create(setflag,n+1,"dihedral:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void DihedralTable::settings(int narg, char **arg) { if (narg != 2) error->all(FLERR,"Illegal dihedral_style command"); if (strcmp(arg[0],"linear") == 0) tabstyle = LINEAR; else if (strcmp(arg[0],"spline") == 0) tabstyle = SPLINE; else error->all(FLERR,"Unknown table style in dihedral style table"); tablength = force->inumeric(FLERR,arg[1]); if (tablength < 3) error->all(FLERR,"Illegal number of dihedral 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(tabindex); } allocated = 0; ntables = 0; tables = NULL; } /* ---------------------------------------------------------------------- set coeffs for one type ------------------------------------------------------------------------- */ void DihedralTable::coeff(int narg, char **arg) { if (narg != 3) error->all(FLERR,"Illegal dihedral_coeff command"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->ndihedraltypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->ndihedraltypes,ilo,ihi); int me; MPI_Comm_rank(world,&me); tables = (Table *) memory->srealloc(tables,(ntables+1)*sizeof(Table), "dihedral:tables"); Table *tb = &tables[ntables]; null_table(tb); if (me == 0) read_table(tb,arg[1],arg[2]); bcast_table(tb); // --- check the angle data for range errors --- // --- and resolve issues with periodicity --- if (tb->ninput < 2) { string err_msg; err_msg = string("Invalid dihedral table length (") + string(arg[2]) + string(")."); error->one(FLERR,err_msg.c_str()); } else if ((tb->ninput == 2) && (tabstyle == SPLINE)) { string err_msg; err_msg = string("Invalid dihedral spline table length. (Try linear)\n (") + string(arg[2]) + string(")."); error->one(FLERR,err_msg.c_str()); } // check for monotonicity for (int i=0; i < tb->ninput-1; i++) { if (tb->phifile[i] >= tb->phifile[i+1]) { stringstream i_str; i_str << i+1; string err_msg = string("Dihedral table values are not increasing (") + string(arg[2]) + string(", ")+i_str.str()+string("th entry)"); if (i==0) err_msg += string("\n(This is probably a mistake with your table format.)\n"); error->all(FLERR,err_msg.c_str()); } } // check the range of angles double philo = tb->phifile[0]; double phihi = tb->phifile[tb->ninput-1]; if (tb->use_degrees) { if ((phihi - philo) >= 360) { string err_msg; err_msg = string("Dihedral table angle range must be < 360 degrees (") +string(arg[2]) + string(")."); error->all(FLERR,err_msg.c_str()); } } else { if ((phihi - philo) >= MY_2PI) { string err_msg; err_msg = string("Dihedral table angle range must be < 2*PI radians (") + string(arg[2]) + string(")."); error->all(FLERR,err_msg.c_str()); } } // convert phi from degrees to radians if (tb->use_degrees) { for (int i=0; i < tb->ninput; i++) { tb->phifile[i] *= MY_PI/180.0; // I assume that if angles are in degrees, then the forces (f=dU/dphi) // are specified with "phi" in degrees as well. tb->ffile[i] *= 180.0/MY_PI; } } // We want all the phi dihedral angles to lie in the range from 0 to 2*PI. // But I don't want to restrict users to input their data in this range. // We also want the angles to be sorted in increasing order. // This messy code fixes these problems with the user's data: { double *phifile_tmp = new double [tb->ninput]; //temporary arrays double *ffile_tmp = new double [tb->ninput]; //used for sorting double *efile_tmp = new double [tb->ninput]; // After re-imaging, does the range of angles cross the 0 or 2*PI boundary? // If so, find the discontinuity: int i_discontinuity = tb->ninput; for (int i=0; i < tb->ninput; i++) { double phi = tb->phifile[i]; // Add a multiple of 2*PI to phi until it lies in the range [0, 2*PI). phi -= MY_2PI * floor(phi/MY_2PI); phifile_tmp[i] = phi; efile_tmp[i] = tb->efile[i]; ffile_tmp[i] = tb->ffile[i]; if ((i>0) && (phifile_tmp[i] < phifile_tmp[i-1])) { //There should only be at most one discontinuity, because we have //insured that the data was sorted before imaging, and because the //range of angle values does not exceed 2*PI. i_discontinuity = i; } } int I = 0; for (int i = i_discontinuity; i < tb->ninput; i++) { tb->phifile[I] = phifile_tmp[i]; tb->efile[I] = efile_tmp[i]; tb->ffile[I] = ffile_tmp[i]; I++; } for (int i = 0; i < i_discontinuity; i++) { tb->phifile[I] = phifile_tmp[i]; tb->efile[I] = efile_tmp[i]; tb->ffile[I] = ffile_tmp[i]; I++; } // clean up temporary storage delete[] phifile_tmp; delete[] ffile_tmp; delete[] efile_tmp; } // spline read-in and compute r,e,f vectors within table spline_table(tb); compute_table(tb); // Optional: allow the user to print out the interpolated spline tables if (me == 0) { if (checkU_fname && (strlen(checkU_fname) != 0)) { ofstream checkU_file; checkU_file.open(checkU_fname, ios::out); for (int i=0; i < tablength; i++) { double phi = i*MY_2PI/tablength; double u = tb->e[i]; if (tb->use_degrees) phi *= 180.0/MY_PI; checkU_file << phi << " " << u << "\n"; } checkU_file.close(); } if (checkF_fname && (strlen(checkF_fname) != 0)) { ofstream checkF_file; checkF_file.open(checkF_fname, ios::out); for (int i=0; i < tablength; i++) { double phi = i*MY_2PI/tablength; double f; if ((tabstyle == SPLINE) && (tb->f_unspecified)) { double dU_dphi = // (If the user did not specify the forces now, AND the user // selected the "spline" option, (as opposed to "linear") // THEN the tb->f array is uninitialized, so there's // no point to print out the contents of the tb->f[] array. // Instead, later on, we will calculate the force using the // -cyc_splintD() routine to calculate the derivative of the // energy spline, using the energy data (tb->e[]). // To be nice and report something, I do the same thing here.) cyc_splintD(tb->phi, tb->e, tb->e2, tablength, MY_2PI,phi); f = -dU_dphi; } else // Otherwise we calculated the tb->f[] array. Report its contents. f = tb->f[i]; if (tb->use_degrees) { phi *= 180.0/MY_PI; // If the user wants degree angle units, we should convert our // internal force tables (in energy/radians) to (energy/degrees) f *= MY_PI/180.0; } checkF_file << phi << " " << f << "\n"; } checkF_file.close(); } // if (checkF_fname && (strlen(checkF_fname) != 0)) } // if (me == 0) // store ptr to table in tabindex int count = 0; for (int i = ilo; i <= ihi; i++) { tabindex[i] = ntables; //phi0[i] = tb->phi0; <- equilibrium dihedral angles not supported setflag[i] = 1; count++; } ntables++; if (count == 0) error->all(FLERR,"Illegal dihedral_coeff command"); } //DihedralTable::coeff() /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void DihedralTable::write_restart(FILE *fp) { fwrite(&tabstyle,sizeof(int),1,fp); fwrite(&tablength,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void DihedralTable::read_restart(FILE *fp) { if (comm->me == 0) { fread(&tabstyle,sizeof(int),1,fp); fread(&tablength,sizeof(int),1,fp); } MPI_Bcast(&tabstyle,1,MPI_INT,0,world); MPI_Bcast(&tablength,1,MPI_INT,0,world); allocate(); } /* ---------------------------------------------------------------------- */ void DihedralTable::null_table(Table *tb) { tb->phifile = tb->efile = tb->ffile = NULL; tb->e2file = tb->f2file = NULL; tb->phi = tb->e = tb->de = NULL; tb->f = tb->df = tb->e2 = tb->f2 = NULL; } /* ---------------------------------------------------------------------- */ void DihedralTable::free_table(Table *tb) { memory->destroy(tb->phifile); memory->destroy(tb->efile); memory->destroy(tb->ffile); memory->destroy(tb->e2file); memory->destroy(tb->f2file); memory->destroy(tb->phi); memory->destroy(tb->e); memory->destroy(tb->de); memory->destroy(tb->f); memory->destroy(tb->df); memory->destroy(tb->e2); memory->destroy(tb->f2); } /* ---------------------------------------------------------------------- read table file, only called by proc 0 ------------------------------------------------------------------------- */ static const int MAXLINE=2048; void DihedralTable::read_table(Table *tb, char *file, char *keyword) { char line[MAXLINE]; // open file FILE *fp = force->open_potential(file); if (fp == NULL) { string err_msg = string("Cannot open file ") + string(file); error->one(FLERR,err_msg.c_str()); } // loop until section found with matching keyword while (1) { if (fgets(line,MAXLINE,fp) == NULL) { string err_msg=string("Did not find keyword \"") +string(keyword)+string("\" in dihedral table file."); error->one(FLERR, err_msg.c_str()); } if (strspn(line," \t\n\r") == strlen(line)) continue; // blank line if (line[0] == '#') continue; // comment char *word = strtok(line," \t\n\r"); if (strcmp(word,keyword) == 0) 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->phifile,tb->ninput,"dihedral:phifile"); memory->create(tb->efile,tb->ninput,"dihedral:efile"); memory->create(tb->ffile,tb->ninput,"dihedral:ffile"); // read a,e,f table values from file int itmp; for (int i = 0; i < tb->ninput; i++) { // Read the next line. Make sure the file is long enough. if (! fgets(line,MAXLINE,fp)) error->one(FLERR, "Dihedral table does not contain enough entries."); // Skip blank lines and delete text following a '#' character char *pe = strchr(line, '#'); if (pe != NULL) *pe = '\0'; //terminate string at '#' character char *pc = line; while ((*pc != '\0') && isspace(*pc)) pc++; if (*pc != '\0') { //If line is not a blank line stringstream line_ss(line); if (tb->f_unspecified) { //sscanf(line,"%d %lg %lg", // &itmp,&tb->phifile[i],&tb->efile[i]); line_ss >> itmp; line_ss >> tb->phifile[i]; line_ss >> tb->efile[i]; } else { //sscanf(line,"%d %lg %lg %lg", // &itmp,&tb->phifile[i],&tb->efile[i],&tb->ffile[i]); line_ss >> itmp; line_ss >> tb->phifile[i]; line_ss >> tb->efile[i]; line_ss >> tb->ffile[i]; } if (! line_ss) { stringstream err_msg; err_msg << "Read error in table "<< keyword<<", near line "<f_unspecified) && (i==0)) err_msg << "\n (This sometimes occurs if users forget to specify the \"NOF\" option.)\n"; error->one(FLERR, err_msg.str().c_str()); } } else //if it is a blank line, then skip it. i--; } //for (int i = 0; (i < tb->ninput) && fp; i++) { fclose(fp); } /* ---------------------------------------------------------------------- build spline representation of e,f over entire range of read-in table this function sets these values in e2file,f2file. I also perform a crude check for force & energy consistency. ------------------------------------------------------------------------- */ void DihedralTable::spline_table(Table *tb) { memory->create(tb->e2file,tb->ninput,"dihedral:e2file"); memory->create(tb->f2file,tb->ninput,"dihedral:f2file"); if (cyc_spline(tb->phifile, tb->efile, tb->ninput, MY_2PI,tb->e2file,comm->me == 0)) error->one(FLERR,"Error computing dihedral spline tables"); if (! tb->f_unspecified) { if (cyc_spline(tb->phifile, tb->ffile, tb->ninput, MY_2PI, tb->f2file, comm->me == 0)) error->one(FLERR,"Error computing dihedral spline tables"); } // CHECK to help make sure the user calculated forces in a way // which is grossly numerically consistent with the energy table. if (! tb->f_unspecified) { int num_disagreements = 0; for (int i=0; ininput; i++) { // Calculate what the force should be at the control points // by using linear interpolation of the derivatives of the energy: double phi_i = tb->phifile[i]; // First deal with periodicity double phi_im1, phi_ip1; int im1 = i-1; if (im1 < 0) { im1 += tb->ninput; phi_im1 = tb->phifile[im1] - MY_2PI; } else phi_im1 = tb->phifile[im1]; int ip1 = i+1; if (ip1 >= tb->ninput) { ip1 -= tb->ninput; phi_ip1 = tb->phifile[ip1] + MY_2PI; } else phi_ip1 = tb->phifile[ip1]; // Now calculate the midpoints above and below phi_i = tb->phifile[i] double phi_lo= 0.5*(phi_im1 + phi_i); //midpoint between phi_im1 and phi_i double phi_hi= 0.5*(phi_i + phi_ip1); //midpoint between phi_i and phi_ip1 // Use a linear approximation to the derivative at these two midpoints double dU_dphi_lo = (tb->efile[i] - tb->efile[im1]) / (phi_i - phi_im1); double dU_dphi_hi = (tb->efile[ip1] - tb->efile[i]) / (phi_ip1 - phi_i); // Now calculate the derivative at position // phi_i (=tb->phifile[i]) using linear interpolation double a = (phi_i - phi_lo) / (phi_hi - phi_lo); double b = (phi_hi - phi_i) / (phi_hi - phi_lo); double dU_dphi = a*dU_dphi_lo + b*dU_dphi_hi; double f = -dU_dphi; // Alternately, we could use spline interpolation instead: // double f = - splintD(tb->phifile, tb->efile, tb->e2file, // tb->ninput, MY_2PI, tb->phifile[i]); // This is the way I originally did it, but I trust // the ugly simple linear way above better. // Recall this entire block of code doess not calculate // anything important. It does not have to be perfect. // We are only checking for stupid user errors here. if ((f != 0.0) && (tb->ffile[i] != 0.0) && ((f/tb->ffile[i] < 0.5) || (f/tb->ffile[i] > 2.0))) { num_disagreements++; } } // for (int i=0; ininput; i++) if ((num_disagreements > tb->ninput/2) && (num_disagreements > 2)) { string msg("Dihedral table has inconsistent forces and energies. (Try \"NOF\".)\n"); error->all(FLERR,msg.c_str()); } } // check for consistency if (! tb->f_unspecified) } // DihedralTable::spline_table() /* ---------------------------------------------------------------------- compute a,e,f vectors from splined values ------------------------------------------------------------------------- */ void DihedralTable::compute_table(Table *tb) { //delta = table spacing in dihedral angle for tablength (cyclic) bins tb->delta = MY_2PI / tablength; tb->invdelta = 1.0/tb->delta; tb->deltasq6 = tb->delta*tb->delta / 6.0; // N evenly spaced bins in dihedral angle from 0 to 2*PI // phi,e,f = value at lower edge of bin // de,df values = delta values of e,f (cyclic, in this case) // phi,e,f,de,df are arrays containing "tablength" number of entries memory->create(tb->phi,tablength,"dihedral:phi"); memory->create(tb->e,tablength,"dihedral:e"); memory->create(tb->de,tablength,"dihedral:de"); memory->create(tb->f,tablength,"dihedral:f"); memory->create(tb->df,tablength,"dihedral:df"); memory->create(tb->e2,tablength,"dihedral:e2"); memory->create(tb->f2,tablength,"dihedral:f2"); if (tabstyle == SPLINE) { // Use cubic spline interpolation to calculate the entries in the // internal table. (This is true regardless...even if tabstyle!=SPLINE.) for (int i = 0; i < tablength; i++) { double phi = i*tb->delta; tb->phi[i] = phi; tb->e[i]= cyc_splint(tb->phifile,tb->efile,tb->e2file,tb->ninput,MY_2PI,phi); if (! tb->f_unspecified) tb->f[i] = cyc_splint(tb->phifile,tb->ffile,tb->f2file,tb->ninput,MY_2PI,phi); } } // if (tabstyle == SPLINE) else if (tabstyle == LINEAR) { if (! tb->f_unspecified) { for (int i = 0; i < tablength; i++) { double phi = i*tb->delta; tb->phi[i] = phi; tb->e[i]= cyc_lin(tb->phifile,tb->efile,tb->ninput,MY_2PI,phi); tb->f[i]= cyc_lin(tb->phifile,tb->ffile,tb->ninput,MY_2PI,phi); } } else { for (int i = 0; i < tablength; i++) { double phi = i*tb->delta; tb->phi[i] = phi; tb->e[i]= cyc_lin(tb->phifile,tb->efile,tb->ninput,MY_2PI,phi); } // In the linear case, if the user did not specify the forces, then we // must generate the "f" array. Do this using linear interpolation // of the e array (which itself was generated above) for (int i = 0; i < tablength; i++) { int im1 = i-1; if (im1 < 0) im1 += tablength; int ip1 = i+1; if (ip1 >= tablength) ip1 -= tablength; double dedx = (tb->e[ip1] - tb->e[im1]) / (2.0 * tb->delta); // (This is the average of the linear slopes on either side of the node. // Note that the nodes in the internal table are evenly spaced.) tb->f[i] = -dedx; } } // Fill the linear interpolation tables (de, df) for (int i = 0; i < tablength; i++) { int ip1 = i+1; if (ip1 >= tablength) ip1 -= tablength; tb->de[i] = tb->e[ip1] - tb->e[i]; tb->df[i] = tb->f[ip1] - tb->f[i]; } } // else if (tabstyle == LINEAR) cyc_spline(tb->phi, tb->e, tablength, MY_2PI, tb->e2, comm->me == 0); if (! tb->f_unspecified) cyc_spline(tb->phi, tb->f, tablength, MY_2PI, tb->f2, comm->me == 0); } /* ---------------------------------------------------------------------- extract attributes from parameter line in table section format of line: N value NOF DEGREES RADIANS N is required, other params are optional ------------------------------------------------------------------------- */ void DihedralTable::param_extract(Table *tb, char *line) { //tb->theta0 = 180.0; <- equilibrium angles not supported tb->ninput = 0; tb->f_unspecified = false; //default tb->use_degrees = true; //default 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,"NOF") == 0) { tb->f_unspecified = true; } else if ((strcmp(word,"DEGREES") == 0) || (strcmp(word,"degrees") == 0)) { tb->use_degrees = true; } else if ((strcmp(word,"RADIANS") == 0) || (strcmp(word,"radians") == 0)) { tb->use_degrees = false; } else if (strcmp(word,"CHECKU") == 0) { word = strtok(NULL," \t\n\r\f"); memory->sfree(checkU_fname); memory->create(checkU_fname,strlen(word)+1,"dihedral_table:checkU"); strcpy(checkU_fname, word); } else if (strcmp(word,"CHECKF") == 0) { word = strtok(NULL," \t\n\r\f"); memory->sfree(checkF_fname); memory->create(checkF_fname,strlen(word)+1,"dihedral_table:checkF"); strcpy(checkF_fname, word); } // COMMENTING OUT: equilibrium angles are not supported //else if (strcmp(word,"EQ") == 0) { // word = strtok(NULL," \t\n\r\f"); // tb->theta0 = atof(word); //} else { string err_msg("Invalid keyword in dihedral angle table parameters"); err_msg += string(" (") + string(word) + string(")"); error->one(FLERR,err_msg.c_str()); } word = strtok(NULL," \t\n\r\f"); } if (tb->ninput == 0) error->one(FLERR,"Dihedral table parameters did not set N"); } // DihedralTable::param_extract() /* ---------------------------------------------------------------------- broadcast read-in table info from proc 0 to other procs this function communicates these values in Table: ninput,phifile,efile,ffile, f_unspecified,use_degrees ------------------------------------------------------------------------- */ void DihedralTable::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->phifile,tb->ninput,"dihedral:phifile"); memory->create(tb->efile,tb->ninput,"dihedral:efile"); memory->create(tb->ffile,tb->ninput,"dihedral:ffile"); } MPI_Bcast(tb->phifile,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->f_unspecified,1,MPI_INT,0,world); MPI_Bcast(&tb->use_degrees,1,MPI_INT,0,world); // COMMENTING OUT: equilibrium angles are not supported //MPI_Bcast(&tb->theta0,1,MPI_DOUBLE,0,world); } diff --git a/src/USER-MISC/improper_cossq.cpp b/src/USER-MISC/improper_cossq.cpp index 77033381e..223df4a76 100644 --- a/src/USER-MISC/improper_cossq.cpp +++ b/src/USER-MISC/improper_cossq.cpp @@ -1,314 +1,314 @@ /* ---------------------------------------------------------------------- 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: Georgios G. Vogiatzis (CoMSE, NTU Athens), gvog@chemeng.ntua.gr ------------------------------------------------------------------------- */ #include #include #include #include "improper_cossq.h" #include "atom.h" #include "comm.h" #include "neighbor.h" #include "domain.h" #include "force.h" #include "update.h" #include "memory.h" #include "error.h" #include "math_const.h" using namespace LAMMPS_NS; using namespace MathConst; #define TOLERANCE 0.05 #define SMALL 0.001 /* ---------------------------------------------------------------------- */ ImproperCossq::ImproperCossq(LAMMPS *lmp) : Improper(lmp) {} /* ---------------------------------------------------------------------- */ ImproperCossq::~ImproperCossq() { if (allocated) { memory->destroy(setflag); memory->destroy(k); memory->destroy(chi); } } /* ---------------------------------------------------------------------- */ void ImproperCossq::compute(int eflag, int vflag) { int i1,i2,i3,i4,n,type; double vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z ; double eimproper,f1[3],f2[3],f3[3],f4[3]; double rjisq, rji, rlksq, rlk, cosphi, angfac; double cjiji, clkji, clklk, cfact1, cfact2, cfact3; eimproper = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; int **improperlist = neighbor->improperlist; int nimproperlist = neighbor->nimproperlist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < nimproperlist; n++) { /* Ask the improper list for the atom types. */ i1 = improperlist[n][0]; i2 = improperlist[n][1]; i3 = improperlist[n][2]; i4 = improperlist[n][3]; type = improperlist[n][4]; /* separation vector between i1 and i2, (i2-i1) */ vb1x = x[i2][0] - x[i1][0]; vb1y = x[i2][1] - x[i1][1]; vb1z = x[i2][2] - x[i1][2]; rjisq = vb1x*vb1x + vb1y*vb1y + vb1z*vb1z ; rji = sqrt(rjisq); /* separation vector between i2 and i3 (i3-i2) */ vb2x = x[i3][0] - x[i2][0]; vb2y = x[i3][1] - x[i2][1]; vb2z = x[i3][2] - x[i2][2]; /* separation vector between i3 and i4, (i4-i3) */ vb3x = x[i4][0] - x[i3][0]; vb3y = x[i4][1] - x[i3][1]; vb3z = x[i4][2] - x[i3][2]; rlksq = vb3x*vb3x + vb3y*vb3y + vb3z*vb3z ; rlk = sqrt(rlksq); cosphi = (vb3x*vb1x + vb3y*vb1y + vb3z*vb1z)/(rji * rlk); /* Check that cos(phi) is in the correct limits. */ if (cosphi > 1.0 + TOLERANCE || cosphi < (-1.0 - TOLERANCE)) { int me; MPI_Comm_rank(world,&me); if (screen) { char str[128]; sprintf(str,"Improper problem: %d " BIGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT, me,update->ntimestep, atom->tag[i1],atom->tag[i2],atom->tag[i3],atom->tag[i4]); error->warning(FLERR,str,0); fprintf(screen," 1st atom: %d %g %g %g\n",me,x[i1][0],x[i1][1],x[i1][2]); fprintf(screen," 2nd atom: %d %g %g %g\n",me,x[i2][0],x[i2][1],x[i2][2]); fprintf(screen," 3rd atom: %d %g %g %g\n",me,x[i3][0],x[i3][1],x[i3][2]); fprintf(screen," 4th atom: %d %g %g %g\n",me,x[i4][0],x[i4][1],x[i4][2]); } } /* Apply corrections to round-off errors. */ if (cosphi > 1.0) cosphi -= SMALL; if (cosphi < -1.0) cosphi += SMALL; /* Calculate the angle: */ double torangle = acos(cosphi); cosphi = cos(torangle - chi[type]); if (eflag) eimproper = 0.5 * k[type] * cosphi * cosphi; /* printf("The tags: %d-%d-%d-%d, of type %d .\n",atom->tag[i1],atom->tag[i2],atom->tag[i3],atom->tag[i4],type); printf("The ji vector: %f, %f, %f.\nThe lk vector: %f, %f, %f.\n", vb1x,vb1y,vb1z,vb3x,vb3y,vb3z); printf("The cosine of the angle: %-1.16e.\n", cosphi); printf("The energy of the improper: %-1.16e with prefactor %-1.16e.\n", eimproper, 0.5*k[type]); */ /* Work out forces. */ angfac = - k[type] * cosphi; cjiji = rjisq; clklk = rlksq; /*CLKJI = RXLK * RXJI + RYLK * RYJI + RZLK * RZJI */ clkji = vb3x*vb1x + vb3y*vb1y + vb3z*vb1z; /*CFACT1 = CLKLK * CJIJI CFACT1 = SQRT(CFACT1) CFACT1 = ANGFAC / CFACT1*/ cfact1 = angfac / sqrt(clklk * cjiji); /*CFACT2 = CLKJI / CLKLK*/ cfact2 = clkji / clklk; /*CFACT3 = CLKJI / CJIJI*/ cfact3 = clkji / cjiji; /*FIX = -RXLK + CFACT3 * RXJI FIY = -RYLK + CFACT3 * RYJI FIZ = -RZLK + CFACT3 * RZJI*/ f1[0] = - vb3x + cfact3 * vb1x; f1[1] = - vb3y + cfact3 * vb1y; f1[2] = - vb3z + cfact3 * vb1z; /*FJX = -FIX FJY = -FIY FJZ = -FIZ*/ f2[0] = - f1[0]; f2[1] = - f1[1]; f2[2] = - f1[2]; /*FKX = CFACT2 * RXLK - RXJI FKY = CFACT2 * RYLK - RYJI FKZ = CFACT2 * RZLK - RZJI*/ f3[0] = cfact2 * vb3x - vb1x; f3[1] = cfact2 * vb3y - vb1y; f3[2] = cfact2 * vb3z - vb1z; /*FLX = -FKX FLY = -FKY FLZ = -FKZ*/ f4[0] = - f3[0]; f4[1] = - f3[1]; f4[2] = - f3[2]; /*FIX = FIX * CFACT1 FIY = FIY * CFACT1 FIZ = FIZ * CFACT1*/ f1[0] *= cfact1; f1[1] *= cfact1; f1[2] *= cfact1; /*FJX = FJX * CFACT1 FJY = FJY * CFACT1 FJZ = FJZ * CFACT1*/ f2[0] *= cfact1; f2[1] *= cfact1; f2[2] *= cfact1; /*FKX = FKX * CFACT1 FKY = FKY * CFACT1 FKZ = FKZ * CFACT1*/ f3[0] *= cfact1; f3[1] *= cfact1; f3[2] *= cfact1; /*FLX = FLX * CFACT1 FLY = FLY * CFACT1 FLZ = FLZ * CFACT1*/ f4[0] *= cfact1; f4[1] *= cfact1; f4[2] *= cfact1; /* Apply force to each of 4 atoms */ if (newton_bond || i1 < nlocal) { f[i1][0] += f1[0]; f[i1][1] += f1[1]; f[i1][2] += f1[2]; } if (newton_bond || i2 < nlocal) { f[i2][0] += f2[0]; f[i2][1] += f2[1]; f[i2][2] += f2[2]; } if (newton_bond || i3 < nlocal) { f[i3][0] += f3[0]; f[i3][1] += f3[1]; f[i3][2] += f3[2]; } if (newton_bond || i4 < nlocal) { f[i4][0] += f4[0]; f[i4][1] += f4[1]; f[i4][2] += f4[2]; } if (evflag) ev_tally(i1,i2,i3,i4,nlocal,newton_bond,eimproper,f1,f3,f4, -vb1x,-vb1y,-vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z); } } /* ---------------------------------------------------------------------- */ void ImproperCossq::allocate() { allocated = 1; int n = atom->nimpropertypes; memory->create(k,n+1,"improper:k"); memory->create(chi,n+1,"improper:chi"); memory->create(setflag,n+1,"improper:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one type ------------------------------------------------------------------------- */ void ImproperCossq::coeff(int narg, char **arg) { /* Check whether there exist sufficient number of arguments. 0: type of improper to be applied to 1: energetic constant 2: equilibrium angle in degrees */ if (narg != 3) error->all(FLERR,"Incorrect args for cossq improper coefficients"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->nimpropertypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->nimpropertypes,ilo,ihi); double k_one = force->numeric(FLERR,arg[1]); double chi_one = force->numeric(FLERR,arg[2]); int count = 0; for (int i = ilo; i <= ihi; i++) { k[i] = k_one; chi[i] = ((chi_one * MY_PI)/180.0); setflag[i] = 1; count++; } if (count == 0) error->all(FLERR,"Incorrect args for improper coefficients"); } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void ImproperCossq::write_restart(FILE *fp) { fwrite(&k[1],sizeof(double),atom->nimpropertypes,fp); fwrite(&chi[1],sizeof(double),atom->nimpropertypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void ImproperCossq::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&k[1],sizeof(double),atom->nimpropertypes,fp); fread(&chi[1],sizeof(double),atom->nimpropertypes,fp); } MPI_Bcast(&k[1],atom->nimpropertypes,MPI_DOUBLE,0,world); MPI_Bcast(&chi[1],atom->nimpropertypes,MPI_DOUBLE,0,world); for (int i = 1; i <= atom->nimpropertypes; i++) setflag[i] = 1; } diff --git a/src/USER-MISC/improper_distance.cpp b/src/USER-MISC/improper_distance.cpp index a98005a24..ce6441d67 100644 --- a/src/USER-MISC/improper_distance.cpp +++ b/src/USER-MISC/improper_distance.cpp @@ -1,261 +1,261 @@ /* ---------------------------------------------------------------------- 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: Paolo Raiteri (Curtin University) ------------------------------------------------------------------------- */ #include #include #include #include "improper_distance.h" #include "atom.h" #include "comm.h" #include "neighbor.h" #include "domain.h" #include "force.h" #include "update.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define TOLERANCE 0.05 #define SMALL 0.001 /* ---------------------------------------------------------------------- */ ImproperDistance::ImproperDistance(LAMMPS *lmp) : Improper(lmp) {} /* ---------------------------------------------------------------------- */ ImproperDistance::~ImproperDistance() { if (allocated) { memory->destroy(setflag); memory->destroy(k); memory->destroy(chi); } } /* ---------------------------------------------------------------------- */ void ImproperDistance::compute(int eflag, int vflag) { int i1,i2,i3,i4,n,type; double xab, yab, zab; // bond 1-2 double xac, yac, zac; // bond 1-3 double xad, yad, zad; // bond 1-4 double xbc, ybc, zbc; // bond 2-3 double xbd, ybd, zbd; // bond 2-4 double xna, yna, zna, rna; // normal double da; double eimproper,f1[3],f2[3],f3[3],f4[3]; // double ss1,ss2,ss3,r1,r2,r3,c0,c1,c2,s1,s2; // double s12,c,s,domega,a,a11,a22,a33,a12,a13,a23; double domega,a; eimproper = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; int **improperlist = neighbor->improperlist; int nimproperlist = neighbor->nimproperlist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < nimproperlist; n++) { i1 = improperlist[n][0]; i2 = improperlist[n][1]; i3 = improperlist[n][2]; i4 = improperlist[n][3]; type = improperlist[n][4]; // geometry of 4-body // 1 is the central atom // 2-3-4 are ment to be equivalent // I need the bonds between 2-3 and 2-4 to get the plane normal // Then I need the bond 1-2 to project it onto the normal to the plane // bond 1->2 xab = x[i2][0] - x[i1][0]; yab = x[i2][1] - x[i1][1]; zab = x[i2][2] - x[i1][2]; domain->minimum_image(xab,yab,zab); // bond 1->3 xac = x[i3][0] - x[i1][0]; yac = x[i3][1] - x[i1][1]; zac = x[i3][2] - x[i1][2]; domain->minimum_image(xac,yac,zac); // bond 1->4 xad = x[i4][0] - x[i1][0]; yad = x[i4][1] - x[i1][1]; zad = x[i4][2] - x[i1][2]; domain->minimum_image(xad,yad,zad); // bond 2-3 xbc = x[i3][0] - x[i2][0]; ybc = x[i3][1] - x[i2][1]; zbc = x[i3][2] - x[i2][2]; domain->minimum_image(xbc,ybc,zbc); // bond 2-4 xbd = x[i4][0] - x[i2][0]; ybd = x[i4][1] - x[i2][1]; zbd = x[i4][2] - x[i2][2]; domain->minimum_image(xbd,ybd,zbd); xna = ybc*zbd - zbc*ybd; yna = -(xbc*zbd - zbc*xbd); zna = xbc*ybd - ybc*xbd; rna = 1.0 / sqrt(xna*xna+yna*yna+zna*zna); xna *= rna; yna *= rna; zna *= rna; da = xna*xab + yna*yab + zna*zab; domega = k[type]*da*da + chi[type]*da*da*da*da; //printf("%3i %3i %3i %3i %10.5f %10.5f \n",i1,i2,i3,i4,da,domega); a = 2.0* (k[type]*da + 2.0*chi[type]*da*da*da); if (eflag) eimproper = domega; f1[0] = a*( xna); f1[1] = a*( yna); f1[2] = a*( zna); f2[0] = a*( -xna -yab*(zbd-zbc)*rna +zab*(ybd-ybc)*rna -da*( -yna*(zbd-zbc) + zna*(ybd-ybc) )*rna); f2[1] = a*( +xab*(zbd-zbc)*rna -yna +zab*(xbc-xbd)*rna -da*( +xna*(zbd-zbc) + zna*(xbc-xbd) )*rna); f2[2] = a*( -xab*(ybd-ybc)*rna -yab*(xbc-xbd)*rna -zna -da*( +xna*(ybc-ybd) - yna*(xbc-xbd) )*rna); f3[0] = a*( ( yab*zbd -zab*ybd ) *rna +da*( -yna*zbd +zna*ybd )*rna); f3[1] = a*( ( -xab*zbd +zab*xbd ) *rna +da*( +xna*zbd -zna*xbd )*rna); f3[2] = a*( ( +xab*ybd -yab*xbd ) *rna +da*( -xna*ybd +yna*xbd )*rna); f4[0] = a*( ( -yab*zbc +zab*ybc ) *rna -da*( -yna*zbc +zna*ybc )*rna); f4[1] = a*( ( +xab*zbc -zab*xbc ) *rna -da*( +xna*zbc -zna*xbc )*rna); f4[2] = a*( ( -xab*ybc +yab*xbc ) *rna -da*( -xna*ybc +yna*xbc )*rna); //printf("%10.5f %10.5f %10.5f \n",f1[0],f1[1],f1[2]); //printf("%10.5f %10.5f %10.5f \n",f2[0],f2[1],f2[2]); //printf("%10.5f %10.5f %10.5f \n",f3[0],f3[1],f3[2]); //printf("%10.5f %10.5f %10.5f \n",f4[0],f4[1],f4[2]); // apply force to each of 4 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += f1[0]; f[i1][1] += f1[1]; f[i1][2] += f1[2]; } if (newton_bond || i2 < nlocal) { f[i2][0] += f2[0]; f[i2][1] += f2[1]; f[i2][2] += f2[2]; } if (newton_bond || i3 < nlocal) { f[i3][0] += f3[0]; f[i3][1] += f3[1]; f[i3][2] += f3[2]; } if (newton_bond || i4 < nlocal) { f[i4][0] += f4[0]; f[i4][1] += f4[1]; f[i4][2] += f4[2]; } if (evflag) ev_tally(i1,i2,i3,i4,nlocal,newton_bond,eimproper,f2,f3,f4, xab,yab,zab,xac,yac,zac,xad-xac,yad-yac,zad-zac); } } /* ---------------------------------------------------------------------- */ void ImproperDistance::allocate() { allocated = 1; int n = atom->nimpropertypes; memory->create(k,n+1,"improper:k"); memory->create(chi,n+1,"improper:chi"); memory->create(setflag,n+1,"improper:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one type ------------------------------------------------------------------------- */ void ImproperDistance::coeff(int narg, char **arg) { // if (which > 0) return; if (narg != 3) error->all(FLERR,"Incorrect args for improper coefficients"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->nimpropertypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->nimpropertypes,ilo,ihi); double k_one = force->numeric(FLERR,arg[1]); double chi_one = force->numeric(FLERR,arg[2]); // convert chi from degrees to radians int count = 0; for (int i = ilo; i <= ihi; i++) { k[i] = k_one; //chi[i] = chi_one/180.0 * PI; chi[i] = chi_one; setflag[i] = 1; count++; } if (count == 0) error->all(FLERR,"Incorrect args for improper coefficients"); } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void ImproperDistance::write_restart(FILE *fp) { fwrite(&k[1],sizeof(double),atom->nimpropertypes,fp); fwrite(&chi[1],sizeof(double),atom->nimpropertypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void ImproperDistance::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&k[1],sizeof(double),atom->nimpropertypes,fp); fread(&chi[1],sizeof(double),atom->nimpropertypes,fp); } MPI_Bcast(&k[1],atom->nimpropertypes,MPI_DOUBLE,0,world); MPI_Bcast(&chi[1],atom->nimpropertypes,MPI_DOUBLE,0,world); for (int i = 1; i <= atom->nimpropertypes; i++) setflag[i] = 1; } diff --git a/src/USER-MISC/improper_fourier.cpp b/src/USER-MISC/improper_fourier.cpp index ea5f78662..b139fdad5 100644 --- a/src/USER-MISC/improper_fourier.cpp +++ b/src/USER-MISC/improper_fourier.cpp @@ -1,345 +1,345 @@ /* ---------------------------------------------------------------------- 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: Loukas D. Peristeras (Scienomics SARL) [ based on improper_umbrella.cpp Tod A Pascal (Caltech) ] ------------------------------------------------------------------------- */ #include #include #include #include #include "improper_fourier.h" #include "atom.h" #include "comm.h" #include "neighbor.h" #include "domain.h" #include "force.h" #include "update.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define TOLERANCE 0.05 #define SMALL 0.001 /* ---------------------------------------------------------------------- */ ImproperFourier::ImproperFourier(LAMMPS *lmp) : Improper(lmp) {} /* ---------------------------------------------------------------------- */ ImproperFourier::~ImproperFourier() { if (allocated) { memory->destroy(setflag); memory->destroy(k); memory->destroy(C0); memory->destroy(C1); memory->destroy(C2); } } /* ---------------------------------------------------------------------- */ void ImproperFourier::compute(int eflag, int vflag) { int i1,i2,i3,i4,n,type; double vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; int **improperlist = neighbor->improperlist; int nimproperlist = neighbor->nimproperlist; for (n = 0; n < nimproperlist; n++) { i1 = improperlist[n][0]; i2 = improperlist[n][1]; i3 = improperlist[n][2]; i4 = improperlist[n][3]; type = improperlist[n][4]; // 1st bond vb1x = x[i2][0] - x[i1][0]; vb1y = x[i2][1] - x[i1][1]; vb1z = x[i2][2] - x[i1][2]; // 2nd bond vb2x = x[i3][0] - x[i1][0]; vb2y = x[i3][1] - x[i1][1]; vb2z = x[i3][2] - x[i1][2]; // 3rd bond vb3x = x[i4][0] - x[i1][0]; vb3y = x[i4][1] - x[i1][1]; vb3z = x[i4][2] - x[i1][2]; addone(i1,i2,i3,i4, type,evflag,eflag, vb1x, vb1y, vb1z, vb2x, vb2y, vb2z, vb3x, vb3y, vb3z); if ( all[type] ) { addone(i1,i4,i2,i3, type,evflag,eflag, vb3x, vb3y, vb3z, vb1x, vb1y, vb1z, vb2x, vb2y, vb2z); addone(i1,i3,i4,i2, type,evflag,eflag, vb2x, vb2y, vb2z, vb3x, vb3y, vb3z, vb1x, vb1y, vb1z); } } } void ImproperFourier::addone(const int &i1,const int &i2,const int &i3,const int &i4, const int &type,const int &evflag,const int &eflag, const double &vb1x, const double &vb1y, const double &vb1z, const double &vb2x, const double &vb2y, const double &vb2z, const double &vb3x, const double &vb3y, const double &vb3z) { double eimproper,f1[3],f2[3],f3[3],f4[3]; double c,c2,a,s,projhfg,dhax,dhay,dhaz,dahx,dahy,dahz,cotphi; double ax,ay,az,ra2,rh2,ra,rh,rar,rhr,arx,ary,arz,hrx,hry,hrz; double **x = atom->x; double **f = atom->f; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; eimproper = 0.0; // c0 calculation // A = vb1 X vb2 is perpendicular to IJK plane ax = vb1y*vb2z-vb1z*vb2y; ay = vb1z*vb2x-vb1x*vb2z; az = vb1x*vb2y-vb1y*vb2x; ra2 = ax*ax+ay*ay+az*az; rh2 = vb3x*vb3x+vb3y*vb3y+vb3z*vb3z; ra = sqrt(ra2); rh = sqrt(rh2); if (ra < SMALL) ra = SMALL; if (rh < SMALL) rh = SMALL; rar = 1/ra; rhr = 1/rh; arx = ax*rar; ary = ay*rar; arz = az*rar; hrx = vb3x*rhr; hry = vb3y*rhr; hrz = vb3z*rhr; c = arx*hrx+ary*hry+arz*hrz; // error check if (c > 1.0 + TOLERANCE || c < (-1.0 - TOLERANCE)) { int me; MPI_Comm_rank(world,&me); if (screen) { char str[128]; sprintf(str,"Improper problem: %d " BIGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT, me,update->ntimestep, atom->tag[i1],atom->tag[i2],atom->tag[i3],atom->tag[i4]); error->warning(FLERR,str,0); fprintf(screen," 1st atom: %d %g %g %g\n", me,x[i1][0],x[i1][1],x[i1][2]); fprintf(screen," 2nd atom: %d %g %g %g\n", me,x[i2][0],x[i2][1],x[i2][2]); fprintf(screen," 3rd atom: %d %g %g %g\n", me,x[i3][0],x[i3][1],x[i3][2]); fprintf(screen," 4th atom: %d %g %g %g\n", me,x[i4][0],x[i4][1],x[i4][2]); } } if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; s = sqrt(1.0 - c*c); if (s < SMALL) s = SMALL; cotphi = c/s; projhfg = (vb3x*vb1x+vb3y*vb1y+vb3z*vb1z) / sqrt(vb1x*vb1x+vb1y*vb1y+vb1z*vb1z); projhfg += (vb3x*vb2x+vb3y*vb2y+vb3z*vb2z) / sqrt(vb2x*vb2x+vb2y*vb2y+vb2z*vb2z); if (projhfg > 0.0) { s *= -1.0; cotphi *= -1.0; } // force and energy // E = k ( C0 + C1 cos(w) + C2 cos(w) c2 = 2.0*s*s-1.0; if (eflag) eimproper = k[type]*(C0[type]+C1[type]*s+C2[type]*c2); // dhax = diffrence between H and A in X direction, etc a = k[type]*(C1[type]+4.0*C2[type]*s)*cotphi; dhax = hrx-c*arx; dhay = hry-c*ary; dhaz = hrz-c*arz; dahx = arx-c*hrx; dahy = ary-c*hry; dahz = arz-c*hrz; f2[0] = (dhay*vb1z - dhaz*vb1y)*rar; f2[1] = (dhaz*vb1x - dhax*vb1z)*rar; f2[2] = (dhax*vb1y - dhay*vb1x)*rar; f3[0] = (-dhay*vb2z + dhaz*vb2y)*rar; f3[1] = (-dhaz*vb2x + dhax*vb2z)*rar; f3[2] = (-dhax*vb2y + dhay*vb2x)*rar; f4[0] = dahx*rhr; f4[1] = dahy*rhr; f4[2] = dahz*rhr; f1[0] = -(f2[0] + f3[0] + f4[0]); f1[1] = -(f2[1] + f3[1] + f4[1]); f1[2] = -(f2[2] + f3[2] + f4[2]); // apply force to each of 4 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += f1[0]*a; f[i1][1] += f1[1]*a; f[i1][2] += f1[2]*a; } if (newton_bond || i2 < nlocal) { f[i2][0] += f3[0]*a; f[i2][1] += f3[1]*a; f[i2][2] += f3[2]*a; } if (newton_bond || i3 < nlocal) { f[i3][0] += f2[0]*a; f[i3][1] += f2[1]*a; f[i3][2] += f2[2]*a; } if (newton_bond || i4 < nlocal) { f[i4][0] += f4[0]*a; f[i4][1] += f4[1]*a; f[i4][2] += f4[2]*a; } if (evflag) ev_tally(i1,i2,i3,i4,nlocal,newton_bond,eimproper,f1,f3,f4, vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z); } /* ---------------------------------------------------------------------- */ void ImproperFourier::allocate() { allocated = 1; int n = atom->nimpropertypes; memory->create(k,n+1,"improper:k"); memory->create(C0,n+1,"improper:C0"); memory->create(C1,n+1,"improper:C1"); memory->create(C2,n+1,"improper:C2"); memory->create(all,n+1,"improper:C2"); memory->create(setflag,n+1,"improper:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one type ------------------------------------------------------------------------- */ void ImproperFourier::coeff(int narg, char **arg) { if ( narg != 5 && narg != 6 ) error->all(FLERR,"Incorrect args for improper coefficients"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->nimpropertypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->nimpropertypes,ilo,ihi); double k_one = force->numeric(FLERR,arg[1]); double C0_one = force->numeric(FLERR,arg[2]); double C1_one = force->numeric(FLERR,arg[3]); double C2_one = force->numeric(FLERR,arg[4]); int all_one = 1; if ( narg == 6 ) all_one = force->inumeric(FLERR,arg[5]); // convert w0 from degrees to radians int count = 0; for (int i = ilo; i <= ihi; i++) { k[i] = k_one; C0[i] = C0_one; C1[i] = C1_one; C2[i] = C2_one; all[i] = all_one; setflag[i] = 1; count++; } if (count == 0) error->all(FLERR,"Incorrect args for improper coefficients"); } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void ImproperFourier::write_restart(FILE *fp) { fwrite(&k[1],sizeof(double),atom->nimpropertypes,fp); fwrite(&C0[1],sizeof(double),atom->nimpropertypes,fp); fwrite(&C1[1],sizeof(double),atom->nimpropertypes,fp); fwrite(&C2[1],sizeof(double),atom->nimpropertypes,fp); fwrite(&all[1],sizeof(int),atom->nimpropertypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void ImproperFourier::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&k[1],sizeof(double),atom->nimpropertypes,fp); fread(&C0[1],sizeof(double),atom->nimpropertypes,fp); fread(&C1[1],sizeof(double),atom->nimpropertypes,fp); fread(&C2[1],sizeof(double),atom->nimpropertypes,fp); fread(&all[1],sizeof(int),atom->nimpropertypes,fp); } MPI_Bcast(&k[1],atom->nimpropertypes,MPI_DOUBLE,0,world); MPI_Bcast(&C0[1],atom->nimpropertypes,MPI_DOUBLE,0,world); MPI_Bcast(&C1[1],atom->nimpropertypes,MPI_DOUBLE,0,world); MPI_Bcast(&C2[1],atom->nimpropertypes,MPI_DOUBLE,0,world); MPI_Bcast(&all[1],atom->nimpropertypes,MPI_INT,0,world); for (int i = 1; i <= atom->nimpropertypes; i++) setflag[i] = 1; } diff --git a/src/USER-MISC/improper_ring.cpp b/src/USER-MISC/improper_ring.cpp index 4134b4b17..5b5341f50 100644 --- a/src/USER-MISC/improper_ring.cpp +++ b/src/USER-MISC/improper_ring.cpp @@ -1,339 +1,339 @@ /* ---------------------------------------------------------------------- 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: Georgios G. Vogiatzis (CoMSE, NTU Athens), gvog@chemeng.ntua.gr ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Description: This file implements the improper potential introduced by Destree et al., in Equation 9 of: - M. Destree, F. Laupretre, A. Lyulin, and J.-P. Ryckaert, J. Chem. Phys. 112, 9632 (2000), and subsequently referred in: - A.V. Lyulin, M.A.J Michels, Macromolecules, 35, 1463, (2002) This potential does not affect small amplitude vibrations but is used in an ad hoc way to prevent the onset of accidentially large amplitude fluctuations leading to the occurrence of a planar conformation of the three bonds i, i + 1 and i', an intermediate conformation toward the chiral inversion of a methine carbon. In the "Impropers" section of data file four atoms: i, j, k and l are specified with i,j and l lying on the backbone of the chain and k specifying the chirality of j. ------------------------------------------------------------------------- */ #include #include #include #include "improper_ring.h" #include "atom.h" #include "comm.h" #include "neighbor.h" #include "domain.h" #include "force.h" #include "update.h" #include "math_const.h" #include "math_special.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace MathConst; using namespace MathSpecial; #define TOLERANCE 0.05 #define SMALL 0.001 /* ---------------------------------------------------------------------- */ ImproperRing::ImproperRing(LAMMPS *lmp) : Improper(lmp) {} /* ---------------------------------------------------------------------- */ ImproperRing::~ImproperRing() { if (allocated) { memory->destroy(setflag); memory->destroy(k); memory->destroy(chi); } } /* ---------------------------------------------------------------------- */ void ImproperRing::compute(int eflag, int vflag) { /* Be careful!: "chi" is the equilibrium angle in radians. */ int i1,i2,i3,i4,n,type; double eimproper ; /* Compatibility variables. */ double vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z; double f1[3], f3[3], f4[3]; /* Actual computation variables. */ int at1[3], at2[3], at3[3], icomb; double bvec1x[3], bvec1y[3], bvec1z[3], bvec2x[3], bvec2y[3], bvec2z[3], bvec1n[3], bvec2n[3], bend_angle[3]; double angle_summer, angfac, cfact1, cfact2, cfact3; double cjiji, ckjji, ckjkj, fix, fiy, fiz, fjx, fjy, fjz, fkx, fky, fkz; eimproper = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; /* References to simulation data. */ double **x = atom->x; double **f = atom->f; int **improperlist = neighbor->improperlist; int nimproperlist = neighbor->nimproperlist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; /* A description of the potential can be found in Macromolecules 35, pp. 1463-1472 (2002). */ for (n = 0; n < nimproperlist; n++) { /* Take the ids of the atoms contributing to the improper potential. */ i1 = improperlist[n][0]; /* Atom "1" of Figure 1 from the above reference.*/ i2 = improperlist[n][1]; /* Atom "2" ... */ i3 = improperlist[n][2]; /* Atom "3" ... */ i4 = improperlist[n][3]; /* Atom "9" ... */ type = improperlist[n][4]; /* Calculate the necessary variables for LAMMPS implementation. if (evflag) ev_tally(i1,i2,i3,i4,nlocal,newton_bond,eimproper,f1,f3,f4, vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z); Although, they are irrelevant to the calculation of the potential, we keep them for maximal compatibility. */ vb1x = x[i1][0] - x[i2][0]; vb1y = x[i1][1] - x[i2][1]; vb1z = x[i1][2] - x[i2][2]; vb2x = x[i3][0] - x[i2][0]; vb2y = x[i3][1] - x[i2][1]; vb2z = x[i3][2] - x[i2][2]; vb3x = x[i4][0] - x[i3][0]; vb3y = x[i4][1] - x[i3][1]; vb3z = x[i4][2] - x[i3][2]; /* Pass the atom tags to form the necessary combinations. */ at1[0] = i1; at2[0] = i2; at3[0] = i4; /* ids: 1-2-9 */ at1[1] = i1; at2[1] = i2; at3[1] = i3; /* ids: 1-2-3 */ at1[2] = i4; at2[2] = i2; at3[2] = i3; /* ids: 9-2-3 */ /* Initialize the sum of the angles differences. */ angle_summer = 0.0; /* Take a loop over the three angles, defined by each triad: */ for (icomb = 0; icomb < 3; icomb ++) { /* Bond vector connecting the first and the second atom. */ bvec1x[icomb] = x[at2[icomb]][0] - x[at1[icomb]][0]; bvec1y[icomb] = x[at2[icomb]][1] - x[at1[icomb]][1]; bvec1z[icomb] = x[at2[icomb]][2] - x[at1[icomb]][2]; /* also calculate the norm of the vector: */ bvec1n[icomb] = sqrt( bvec1x[icomb]*bvec1x[icomb] + bvec1y[icomb]*bvec1y[icomb] + bvec1z[icomb]*bvec1z[icomb]); /* Bond vector connecting the second and the third atom. */ bvec2x[icomb] = x[at3[icomb]][0] - x[at2[icomb]][0]; bvec2y[icomb] = x[at3[icomb]][1] - x[at2[icomb]][1]; bvec2z[icomb] = x[at3[icomb]][2] - x[at2[icomb]][2]; /* also calculate the norm of the vector: */ bvec2n[icomb] = sqrt( bvec2x[icomb]*bvec2x[icomb] + bvec2y[icomb]*bvec2y[icomb] + bvec2z[icomb]*bvec2z[icomb]); /* Calculate the bending angle of the atom triad: */ bend_angle[icomb] = ( bvec2x[icomb]*bvec1x[icomb] + bvec2y[icomb]*bvec1y[icomb] + bvec2z[icomb]*bvec1z[icomb]); bend_angle[icomb] /= (bvec1n[icomb] * bvec2n[icomb]); if (bend_angle[icomb] > 1.0) bend_angle[icomb] -= SMALL; if (bend_angle[icomb] < -1.0) bend_angle[icomb] += SMALL; /* Append the current angle to the sum of angle differences. */ angle_summer += (bend_angle[icomb] - chi[type]); } if (eflag) eimproper = (1.0/6.0) *k[type] * powint(angle_summer,6); /* printf("The tags: %d-%d-%d-%d, of type %d .\n",atom->tag[i1],atom->tag[i2],atom->tag[i3],atom->tag[i4],type); // printf("The coordinates of the first: %f, %f, %f.\n", x[i1][0], x[i1][1], x[i1][2]); // printf("The coordinates of the second: %f, %f, %f.\n", x[i2][0], x[i2][1], x[i2][2]); // printf("The coordinates of the third: %f, %f, %f.\n", x[i3][0], x[i3][1], x[i3][2]); // printf("The coordinates of the fourth: %f, %f, %f.\n", x[i4][0], x[i4][1], x[i4][2]); printf("The angles are: %f / %f / %f equilibrium: %f.\n", bend_angle[0], bend_angle[1], bend_angle[2],chi[type]); printf("The energy of the improper: %f with prefactor %f.\n", eimproper,(1.0/6.0)*k[type]); printf("The sum of the angles: %f.\n", angle_summer); */ /* Force calculation acting on all atoms. Calculate the derivatives of the potential. */ angfac = k[type] * powint(angle_summer,5); f1[0] = 0.0; f1[1] = 0.0; f1[2] = 0.0; f3[0] = 0.0; f3[1] = 0.0; f3[2] = 0.0; f4[0] = 0.0; f4[1] = 0.0; f4[2] = 0.0; /* Take a loop over the three angles, defined by each triad: */ for (icomb = 0; icomb < 3; icomb ++) { /* Calculate the squares of the distances. */ cjiji = bvec1n[icomb] * bvec1n[icomb]; ckjkj = bvec2n[icomb] * bvec2n[icomb]; ckjji = bvec2x[icomb] * bvec1x[icomb] + bvec2y[icomb] * bvec1y[icomb] + bvec2z[icomb] * bvec1z[icomb] ; cfact1 = angfac / (sqrt(ckjkj * cjiji)); cfact2 = ckjji / ckjkj; cfact3 = ckjji / cjiji; /* Calculate the force acted on the thrid atom of the angle. */ fkx = cfact2 * bvec2x[icomb] - bvec1x[icomb]; fky = cfact2 * bvec2y[icomb] - bvec1y[icomb]; fkz = cfact2 * bvec2z[icomb] - bvec1z[icomb]; /* Calculate the force acted on the first atom of the angle. */ fix = bvec2x[icomb] - cfact3 * bvec1x[icomb]; fiy = bvec2y[icomb] - cfact3 * bvec1y[icomb]; fiz = bvec2z[icomb] - cfact3 * bvec1z[icomb]; /* Finally, calculate the force acted on the middle atom of the angle.*/ fjx = - fix - fkx; fjy = - fiy - fky; fjz = - fiz - fkz; /* Consider the appropriate scaling of the forces: */ fix *= cfact1; fiy *= cfact1; fiz *= cfact1; fjx *= cfact1; fjy *= cfact1; fjz *= cfact1; fkx *= cfact1; fky *= cfact1; fkz *= cfact1; if (at1[icomb] == i1) {f1[0] += fix; f1[1] += fiy; f1[2] += fiz;} else if (at2[icomb] == i1) {f1[0] += fjx; f1[1] += fjy; f1[2] += fjz;} else if (at3[icomb] == i1) {f1[0] += fkx; f1[1] += fky; f1[2] += fkz;} if (at1[icomb] == i3) {f3[0] += fix; f3[1] += fiy; f3[2] += fiz;} else if (at2[icomb] == i3) {f3[0] += fjx; f3[1] += fjy; f3[2] += fjz;} else if (at3[icomb] == i3) {f3[0] += fkx; f3[1] += fky; f3[2] += fkz;} if (at1[icomb] == i4) {f4[0] += fix; f4[1] += fiy; f4[2] += fiz;} else if (at2[icomb] == i4) {f4[0] += fjx; f4[1] += fjy; f4[2] += fjz;} else if (at3[icomb] == i4) {f4[0] += fkx; f4[1] += fky; f4[2] += fkz;} /* Store the contribution to the global arrays: */ /* Take the id of the atom from the at1[icomb] element, i1 = at1[icomb]. */ if (newton_bond || at1[icomb] < nlocal) { f[at1[icomb]][0] += fix; f[at1[icomb]][1] += fiy; f[at1[icomb]][2] += fiz; } /* Take the id of the atom from the at2[icomb] element, i2 = at2[icomb]. */ if (newton_bond || at2[icomb] < nlocal) { f[at2[icomb]][0] += fjx; f[at2[icomb]][1] += fjy; f[at2[icomb]][2] += fjz; } /* Take the id of the atom from the at3[icomb] element, i3 = at3[icomb]. */ if (newton_bond || at3[icomb] < nlocal) { f[at3[icomb]][0] += fkx; f[at3[icomb]][1] += fky; f[at3[icomb]][2] += fkz; } } if (evflag) ev_tally(i1,i2,i3,i4,nlocal,newton_bond,eimproper,f1,f3,f4, vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z); } } /* ---------------------------------------------------------------------- */ void ImproperRing::allocate() { allocated = 1; int n = atom->nimpropertypes; memory->create(k,n+1,"improper:k"); memory->create(chi,n+1,"improper:chi"); memory->create(setflag,n+1,"improper:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one type ------------------------------------------------------------------------- */ void ImproperRing ::coeff(int narg, char **arg) { /* Check whether there exist sufficient number of arguments. 0: type of improper to be applied to 1: energetic constant 2: equilibrium angle in degrees */ if (narg != 3) error->all(FLERR,"Incorrect args for RING improper coefficients"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->nimpropertypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->nimpropertypes,ilo,ihi); double k_one = force->numeric(FLERR,arg[1]); double chi_one = force->numeric(FLERR,arg[2]); int count = 0; for (int i = ilo; i <= ihi; i++) { /* Read the k parameter in kcal/mol. */ k[i] = k_one; /* "chi_one" stores the equilibrium angle in degrees. Convert it to radians and store its cosine. */ chi[i] = cos((chi_one/180.0)*MY_PI); setflag[i] = 1; count++; } if (count == 0) error->all(FLERR,"Incorrect args for improper coefficients"); } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void ImproperRing ::write_restart(FILE *fp) { fwrite(&k[1],sizeof(double),atom->nimpropertypes,fp); fwrite(&chi[1],sizeof(double),atom->nimpropertypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void ImproperRing::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&k[1],sizeof(double),atom->nimpropertypes,fp); fread(&chi[1],sizeof(double),atom->nimpropertypes,fp); } MPI_Bcast(&k[1],atom->nimpropertypes,MPI_DOUBLE,0,world); MPI_Bcast(&chi[1],atom->nimpropertypes,MPI_DOUBLE,0,world); for (int i = 1; i <= atom->nimpropertypes; i++) setflag[i] = 1; } diff --git a/src/USER-MISC/pair_buck_mdf.cpp b/src/USER-MISC/pair_buck_mdf.cpp index 96f49e42d..3a433b16b 100644 --- a/src/USER-MISC/pair_buck_mdf.cpp +++ b/src/USER-MISC/pair_buck_mdf.cpp @@ -1,433 +1,433 @@ /* ---------------------------------------------------------------------- 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: Paolo Raiteri (Curtin University) ------------------------------------------------------------------------- */ #include #include #include #include #include "pair_buck_mdf.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; /* ---------------------------------------------------------------------- */ PairBuckMDF::PairBuckMDF(LAMMPS *lmp) : Pair(lmp) {} /* ---------------------------------------------------------------------- */ PairBuckMDF::~PairBuckMDF() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut); memory->destroy(cut_inner); memory->destroy(cut_inner_sq); memory->destroy(a); memory->destroy(rho); memory->destroy(c); memory->destroy(rhoinv); memory->destroy(buck1); memory->destroy(buck2); memory->destroy(offset); } } /* ---------------------------------------------------------------------- */ void PairBuckMDF::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,phibuck; int *ilist,*jlist,*numneigh,**firstneigh; double dp, d, tt, dt, dd; 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; if (rsq > cut_inner_sq[itype][jtype]) { phibuck = a[itype][jtype]*rexp - c[itype][jtype]*r6inv; dp = (cut[itype][jtype] - cut_inner[itype][jtype]); d = (r-cut_inner[itype][jtype]) / dp; dd = 1.-d; // taperig function - mdf style tt = (1. + 3.*d + 6.*d*d)*dd*dd*dd; // minus the derivative of the tapering function dt = 30.* d*d * dd*dd * r / dp; forcebuck = forcebuck*tt + phibuck*dt; } else { tt = 1; } 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; if (rsq > cut_inner_sq[itype][jtype]) evdwl *= tt; 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 PairBuckMDF::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(cut_inner,n+1,n+1,"pair:cut_inner"); memory->create(cut_inner_sq,n+1,n+1,"pair:cut_inner_sq"); 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 PairBuckMDF::settings(int narg, char **arg) { if (narg != 2) error->all(FLERR,"Illegal pair_style command"); cut_inner_global = force->numeric(FLERR,arg[0]); cut_global = force->numeric(FLERR,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[i][j] = cut_global; } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairBuckMDF::coeff(int narg, char **arg) { if (narg != 5 && narg != 7) 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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double a_one = force->numeric(FLERR,arg[2]); double rho_one = force->numeric(FLERR,arg[3]); if (rho_one <= 0) error->all(FLERR,"Incorrect args for pair coefficients"); double c_one = force->numeric(FLERR,arg[4]); double cut_inner_one = cut_inner_global; double cut_one = cut_global; if (narg == 7) { cut_inner_one = force->numeric(FLERR,arg[5]); cut_one = force->numeric(FLERR,arg[6]); } if (cut_inner_global <= 0.0 || cut_inner_global > cut_global) error->all(FLERR,"Illegal pair_style command"); 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; cut[j][i] = cut_one; cut_inner[i][j] = cut_inner_one; cut_inner[j][i] = cut_inner_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 PairBuckMDF::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; cut_inner[j][i] = cut_inner[i][j]; cut_inner_sq[i][j] = cut_inner[i][j]*cut_inner[i][j]; cut_inner_sq[j][i] = cut_inner_sq[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[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 PairBuckMDF::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 PairBuckMDF::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 PairBuckMDF::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); fwrite(&tail_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairBuckMDF::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); fread(&tail_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); MPI_Bcast(&tail_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- */ double PairBuckMDF::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; double dp, d, tt, dt, dd; 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; phibuck = a[itype][jtype]*rexp - c[itype][jtype]*r6inv; if (rsq > cut_inner_sq[itype][jtype]) { dp = (cut[itype][jtype] - cut_inner[itype][jtype]); d = (r - cut_inner[itype][jtype]) / dp; dd = 1-d; tt = (1. + 3.*d + 6.*d*d)* dd*dd*dd; dt = 30.* d*d * dd*dd * r / dp; forcebuck = forcebuck*tt + phibuck*dt; phibuck *= tt; } fforce = factor_lj*forcebuck*r2inv; return factor_lj*phibuck; } /* ---------------------------------------------------------------------- */ void *PairBuckMDF::extract(const char *str, int &dim) { dim = 2; if (strcmp(str,"aparm") == 0) return (void *) a; if (strcmp(str,"cparm") == 0) return (void *) c; return NULL; } diff --git a/src/USER-MISC/pair_coul_diel.cpp b/src/USER-MISC/pair_coul_diel.cpp index 1913e48b6..a732ace1a 100644 --- a/src/USER-MISC/pair_coul_diel.cpp +++ b/src/USER-MISC/pair_coul_diel.cpp @@ -1,348 +1,348 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributiong authors: Arben Jusufi, Axel Kohlmeyer (Temple U.) ------------------------------------------------------------------------- */ #include #include #include #include #include "pair_coul_diel.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; /* ---------------------------------------------------------------------- */ PairCoulDiel::PairCoulDiel(LAMMPS *lmp) : Pair(lmp) {} /* ---------------------------------------------------------------------- */ PairCoulDiel::~PairCoulDiel() { if (allocated) { memory->destroy(setflag); memory->destroy(sigmae); memory->destroy(rme); memory->destroy(offset); memory->destroy(cutsq); memory->destroy(cut); allocated = 0; } } /* ---------------------------------------------------------------------- */ void PairCoulDiel::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,r,rarg,th,depsdr,epsr,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]) { r = sqrt(rsq); rarg = (r-rme[itype][jtype])/sigmae[itype][jtype]; th=tanh(rarg); epsr=a_eps+b_eps*th; depsdr=b_eps * (1.0 - th*th) / sigmae[itype][jtype]; forcecoul = qqrd2e*qtmp*q[j]*((eps_s*(epsr+r*depsdr)/epsr/epsr) -1.)/rsq; fpair = factor_coul*forcecoul/r; 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 = (qqrd2e*qtmp*q[j]*((eps_s/epsr) -1.)/r) - offset[itype][jtype]; ecoul *= factor_coul; } 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 PairCoulDiel::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(sigmae,n+1,n+1,"pair:sigmae"); memory->create(rme,n+1,n+1,"pair:rme"); memory->create(offset,n+1,n+1,"pair:offset"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairCoulDiel::settings(int narg, char **arg) { if (narg != 1) error->all(FLERR,"Illegal pair_style command"); cut_global = force->numeric(FLERR,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 PairCoulDiel::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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); eps_s = force->numeric(FLERR,arg[2]); double rme_one =force->numeric(FLERR,arg[3]); double sigmae_one = force->numeric(FLERR,arg[4]); double cut_one = cut_global; if (narg == 6) cut_one = force->numeric(FLERR,arg[5]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { sigmae[i][j] = sigmae_one; rme[i][j] = rme_one; cut[i][j] = cut_one; setflag[i][j] = 1; count++; } } a_eps = 0.5*(5.2+eps_s); b_eps = 0.5*(eps_s-5.2); if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairCoulDiel::init_style() { if (!atom->q_flag) error->all(FLERR,"Pair style coul/diel requires atom attribute q"); neighbor->request(this,instance_me); } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairCoulDiel::init_one(int i, int j) { if (setflag[i][j] == 0) { error->all(FLERR,"for pair style coul/diel, parameters need to be set explicitly for all pairs."); } double *q = atom->q; double qqrd2e = force->qqrd2e; if (offset_flag) { double rarg = (cut[i][j]-rme[i][j])/sigmae[i][j]; double epsr=a_eps+b_eps*tanh(rarg); offset[i][j] = qqrd2e*q[i]*q[j]*((eps_s/epsr) -1.)/cut[i][j]; } else offset[i][j] = 0.0; sigmae[j][i] = sigmae[i][j]; rme[j][i] = rme[i][j]; offset[j][i] = offset[i][j]; cut[j][i] = cut[i][j]; return cut[i][j]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairCoulDiel::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(&rme[i][j],sizeof(double),1,fp); fwrite(&sigmae[i][j],sizeof(double),1,fp); fwrite(&cut[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairCoulDiel::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 (setflag[i][j]) { if (me == 0) { fread(&rme[i][j],sizeof(double),1,fp); fread(&sigmae[i][j],sizeof(double),1,fp); fread(&cut[i][j],sizeof(double),1,fp); } MPI_Bcast(&rme[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&sigmae[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairCoulDiel::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 PairCoulDiel::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 PairCoulDiel::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r, rarg,forcedielec,phidielec; double th,epsr,depsdr; double *q = atom->q; double qqrd2e = force->qqrd2e; r=sqrt(rsq); rarg = (r-rme[itype][jtype])/sigmae[itype][jtype]; th = tanh(rarg); epsr=a_eps+b_eps*th; depsdr=b_eps*(1.-th*th)/sigmae[itype][jtype]; forcedielec = qqrd2e*q[i]*q[j]*((eps_s*(epsr+r*depsdr)/epsr/epsr) -1.)/rsq; fforce = factor_coul*forcedielec/r; phidielec = (qqrd2e*q[i]*q[j]*((eps_s/epsr) -1.)/r)- offset[itype][jtype]; return factor_coul*phidielec; } diff --git a/src/USER-MISC/pair_gauss_cut.cpp b/src/USER-MISC/pair_gauss_cut.cpp index f9cdcb96e..f44b1bbd2 100644 --- a/src/USER-MISC/pair_gauss_cut.cpp +++ b/src/USER-MISC/pair_gauss_cut.cpp @@ -1,401 +1,401 @@ /* ---------------------------------------------------------------------- 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: Arben Jusufi, Axel Kohlmeyer (Temple U.) ------------------------------------------------------------------------- */ #include #include #include #include #include "pair_gauss_cut.h" #include "atom.h" #include "comm.h" #include "force.h" #include "neighbor.h" #include "neigh_list.h" #include "update.h" #include "integrate.h" #include "memory.h" #include "error.h" #include "math_const.h" using namespace LAMMPS_NS; using namespace MathConst; /* ---------------------------------------------------------------------- */ PairGaussCut::PairGaussCut(LAMMPS *lmp) : Pair(lmp) { respa_enable = 0; writedata = 1; } /* ---------------------------------------------------------------------- */ PairGaussCut::~PairGaussCut() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut); memory->destroy(hgauss); memory->destroy(sigmah); memory->destroy(rmh); memory->destroy(pgauss); memory->destroy(offset); } } /* ---------------------------------------------------------------------- */ void PairGaussCut::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,r,rexp,ugauss,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); rexp = (r-rmh[itype][jtype])/sigmah[itype][jtype]; ugauss = pgauss[itype][jtype]*exp(-0.5*rexp*rexp); fpair = factor_lj*rexp/r*ugauss/sigmah[itype][jtype]; 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 = ugauss - 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 PairGaussCut::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(hgauss,n+1,n+1,"pair:hgauss"); memory->create(sigmah,n+1,n+1,"pair:sigmah"); memory->create(rmh,n+1,n+1,"pair:rmh"); memory->create(pgauss,n+1,n+1,"pair:pgauss"); memory->create(offset,n+1,n+1,"pair:offset"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairGaussCut::settings(int narg, char **arg) { if (narg != 1) error->all(FLERR,"Illegal pair_style command"); cut_global = force->numeric(FLERR,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 PairGaussCut::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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double hgauss_one = force->numeric(FLERR,arg[2]); double rmh_one = force->numeric(FLERR,arg[3]); double sigmah_one = force->numeric(FLERR,arg[4]); double cut_one = cut_global; if (narg == 6) cut_one = force->numeric(FLERR,arg[5]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { hgauss[i][j] = hgauss_one; sigmah[i][j] = sigmah_one; rmh[i][j] = rmh_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 PairGaussCut::init_one(int i, int j) { if (setflag[i][j] == 0) { hgauss[i][j] = mix_energy(fabs(hgauss[i][i]), fabs(hgauss[j][j]), fabs(sigmah[i][i]), fabs(sigmah[j][j])); // If either of the particles is repulsive (ie, if hgauss > 0), // then the interaction between both is repulsive. double sign_hi = (hgauss[i][i] >= 0.0) ? 1.0 : -1.0; double sign_hj = (hgauss[j][j] >= 0.0) ? 1.0 : -1.0; hgauss[i][j] *= MAX(sign_hi, sign_hj); sigmah[i][j] = mix_distance(sigmah[i][i], sigmah[j][j]); rmh[i][j] = mix_distance(rmh[i][i], rmh[j][j]); cut[i][j] = mix_distance(cut[i][i], cut[j][j]); } pgauss[i][j] = hgauss[i][j] / sqrt(MY_2PI) / sigmah[i][j]; if (offset_flag) { double rexp = (cut[i][j]-rmh[i][j])/sigmah[i][j]; offset[i][j] = pgauss[i][j] * exp(-0.5*rexp*rexp); } else offset[i][j] = 0.0; hgauss[j][i] = hgauss[i][j]; sigmah[j][i] = sigmah[i][j]; rmh[j][i] = rmh[i][j]; pgauss[j][i] = pgauss[i][j]; offset[j][i] = offset[i][j]; cut[j][i] = cut[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); } return cut[i][j]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairGaussCut::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(&hgauss[i][j],sizeof(double),1,fp); fwrite(&rmh[i][j],sizeof(double),1,fp); fwrite(&sigmah[i][j],sizeof(double),1,fp); fwrite(&cut[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairGaussCut::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(&hgauss[i][j],sizeof(double),1,fp); fread(&rmh[i][j],sizeof(double),1,fp); fread(&sigmah[i][j],sizeof(double),1,fp); fread(&cut[i][j],sizeof(double),1,fp); } MPI_Bcast(&hgauss[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&rmh[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&sigmah[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairGaussCut::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 PairGaussCut::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); } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void PairGaussCut::write_data(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) fprintf(fp,"%d %g %g %g\n",i,hgauss[i][i],rmh[i][i],sigmah[i][i]); } /* ---------------------------------------------------------------------- proc 0 writes all pairs to data file ------------------------------------------------------------------------- */ void PairGaussCut::write_data_all(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) fprintf(fp,"%d %d %g %g %g %g\n",i,j,hgauss[i][j],rmh[i][j],sigmah[i][j],cut[i][j]); } /* ---------------------------------------------------------------------- */ double PairGaussCut::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r, rexp,ugauss,phigauss; r=sqrt(rsq); rexp = (r-rmh[itype][jtype])/sigmah[itype][jtype]; ugauss = pgauss[itype][jtype]*exp(-0.5*rexp*rexp); fforce = factor_lj*rexp/r*ugauss/sigmah[itype][jtype]; phigauss = ugauss - offset[itype][jtype]; return factor_lj*phigauss; } /* ---------------------------------------------------------------------- */ double PairGaussCut::memory_usage() { const int n=atom->ntypes; double bytes = Pair::memory_usage(); bytes += 7*((n+1)*(n+1) * sizeof(double) + (n+1)*sizeof(double *)); bytes += 1*((n+1)*(n+1) * sizeof(int) + (n+1)*sizeof(int *)); return bytes; } diff --git a/src/USER-MISC/pair_lennard_mdf.cpp b/src/USER-MISC/pair_lennard_mdf.cpp index 81c443596..3a8195519 100644 --- a/src/USER-MISC/pair_lennard_mdf.cpp +++ b/src/USER-MISC/pair_lennard_mdf.cpp @@ -1,395 +1,395 @@ /* ---------------------------------------------------------------------- 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: Paolo Raiteri (Curtin University) ------------------------------------------------------------------------- */ #include #include #include #include #include "pair_lennard_mdf.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; /* ---------------------------------------------------------------------- */ PairLJ_AB_MDF::PairLJ_AB_MDF(LAMMPS *lmp) : Pair(lmp) {} /* ---------------------------------------------------------------------- */ PairLJ_AB_MDF::~PairLJ_AB_MDF() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut); memory->destroy(cut_inner); memory->destroy(cut_inner_sq); memory->destroy(aparm); memory->destroy(bparm); memory->destroy(lj1); memory->destroy(lj2); memory->destroy(lj3); memory->destroy(lj4); } } /* ---------------------------------------------------------------------- */ void PairLJ_AB_MDF::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; double rr, d, dd, tt, dt, dp, philj; 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]); if (rsq > cut_inner_sq[itype][jtype]) { philj = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]); rr = sqrt(rsq); dp = (cut[itype][jtype] - cut_inner[itype][jtype]); d = (rr-cut_inner[itype][jtype]) / dp; dd = 1.-d; // taperig function - mdf style tt = (1. + 3.*d + 6.*d*d)*dd*dd*dd; // minus the derivative of the tapering function dt = 30.* d*d * dd*dd * rr / dp; forcelj = forcelj*tt + philj*dt; } else { tt = 1; } 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]); if (rsq > cut_inner_sq[itype][jtype]) evdwl *= tt; 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 PairLJ_AB_MDF::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(cut_inner,n+1,n+1,"pair:cut_inner"); memory->create(cut_inner_sq,n+1,n+1,"pair:cut_inner_sq"); memory->create(aparm,n+1,n+1,"pair:aparm"); memory->create(bparm,n+1,n+1,"pair:bparm"); 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"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairLJ_AB_MDF::settings(int narg, char **arg) { if (narg != 2) error->all(FLERR,"Illegal pair_style command"); cut_inner_global = force->numeric(FLERR,arg[0]); cut_global = force->numeric(FLERR,arg[1]); if (cut_inner_global <= 0.0 || cut_inner_global > cut_global) error->all(FLERR,"Illegal pair_style command"); // 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_inner[i][j] = cut_inner_global; cut[i][j] = cut_global; } } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairLJ_AB_MDF::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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double aparm_one = force->numeric(FLERR,arg[2]); double bparm_one = force->numeric(FLERR,arg[3]); double cut_inner_one = cut_inner_global; double cut_one = cut_global; if (narg == 6) { cut_inner_one = force->numeric(FLERR,arg[4]); cut_one = force->numeric(FLERR,arg[5]); } if (cut_inner_global <= 0.0 || cut_inner_global > cut_global) error->all(FLERR,"Illegal pair_style command"); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { aparm[i][j] = aparm_one; bparm[i][j] = bparm_one; cut_inner[i][j] = cut_inner_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 PairLJ_AB_MDF::init_one(int i, int j) { if (setflag[i][j] == 0) { aparm[i][j] = mix_energy(aparm[i][i],aparm[j][j], bparm[i][i],bparm[j][j]); bparm[i][j] = mix_distance(bparm[i][i],bparm[j][j]); cut_inner[i][j] = mix_distance(cut_inner[i][i],cut_inner[j][j]); cut[i][j] = mix_distance(cut[i][i],cut[j][j]); } cut_inner_sq[i][j] = cut_inner[i][j]*cut_inner[i][j]; lj1[i][j] = 12.0 * aparm[i][j]; lj2[i][j] = 6.0 * bparm[i][j]; lj3[i][j] = aparm[i][j]; lj4[i][j] = bparm[i][j]; cut_inner[j][i] = cut_inner[i][j]; cut_inner_sq[j][i] = cut_inner_sq[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]; return cut[i][j]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJ_AB_MDF::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(&aparm[i][j],sizeof(double),1,fp); fwrite(&bparm[i][j],sizeof(double),1,fp); fwrite(&cut_inner[i][j],sizeof(double),1,fp); fwrite(&cut[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJ_AB_MDF::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(&aparm[i][j],sizeof(double),1,fp); fread(&bparm[i][j],sizeof(double),1,fp); fread(&cut_inner[i][j],sizeof(double),1,fp); fread(&cut[i][j],sizeof(double),1,fp); } MPI_Bcast(&aparm[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&bparm[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_inner[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJ_AB_MDF::write_restart_settings(FILE *fp) { fwrite(&mix_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJ_AB_MDF::read_restart_settings(FILE *fp) { int me = comm->me; if (me == 0) { fread(&mix_flag,sizeof(int),1,fp); } MPI_Bcast(&mix_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- */ double PairLJ_AB_MDF::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r2inv,r6inv,forcelj,philj; double rr, dp, d, tt, dt, dd; r2inv = 1.0/rsq; r6inv = r2inv*r2inv*r2inv; philj = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]); forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); if (rsq > cut_inner_sq[itype][jtype]) { rr = sqrt(rsq); dp = (cut[itype][jtype] - cut_inner[itype][jtype]); d = (rr - cut_inner[itype][jtype]) / dp; dd = 1-d; tt = (1. + 3.*d + 6.*d*d)* dd*dd*dd; dt = 30.* d*d * dd*dd * rr / dp; forcelj = forcelj*tt + philj*dt; philj *= dt; } fforce = factor_lj*forcelj*r2inv; return factor_lj*philj; } /* ---------------------------------------------------------------------- */ void *PairLJ_AB_MDF::extract(const char *str, int &dim) { dim = 2; if (strcmp(str,"aparm") == 0) return (void *) aparm; if (strcmp(str,"bparm") == 0) return (void *) bparm; return NULL; } diff --git a/src/USER-MISC/pair_list.cpp b/src/USER-MISC/pair_list.cpp index 5f0539263..3adbe8b69 100644 --- a/src/USER-MISC/pair_list.cpp +++ b/src/USER-MISC/pair_list.cpp @@ -1,422 +1,422 @@ /* ---------------------------------------------------------------------- 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: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ #include "pair_list.h" #include "atom.h" #include "comm.h" #include "domain.h" #include "force.h" #include "memory.h" #include "error.h" #include #include #include #include using namespace LAMMPS_NS; static const char * const stylename[] = { "none", "harmonic", "morse", "lj126", NULL }; // fast power function for integer exponent > 0 static double mypow(double x, int n) { double yy; if (x == 0.0) return 0.0; for (yy = 1.0; n != 0; n >>= 1, x *=x) if (n & 1) yy *= x; return yy; } typedef struct { double x,y,z; } dbl3_t; /* ---------------------------------------------------------------------- */ PairList::PairList(LAMMPS *lmp) : Pair(lmp) { single_enable = 0; respa_enable = 0; cut_global = 0.0; style = NULL; params = NULL; check_flag = 1; } /* ---------------------------------------------------------------------- */ PairList::~PairList() { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(style); memory->destroy(params); } /* ---------------------------------------------------------------------- in this pair style we don't use a neighbor list, but loop through a list of pairwise interactions, determines the corresponding local atom indices and compute those forces. ------------------------------------------------------------------------- */ void PairList::compute(int eflag, int vflag) { if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = eflag_global = vflag_global = eflag_atom = vflag_atom = 0; const int nlocal = atom->nlocal; const int newton_pair = force->newton_pair; const dbl3_t * _noalias const x = (dbl3_t *) atom->x[0]; dbl3_t * _noalias const f = (dbl3_t *) atom->f[0]; double fpair,epair; int i,j; int pc = 0; for (int n=0; n < npairs; ++n) { const list_parm_t &par = params[n]; i = atom->map(par.id1); j = atom->map(par.id2); // if one of the two atoms is missing on the node skip if ((i < 0) || (j < 0)) continue; // both atoms are ghosts -> skip if ((i >= nlocal) && (j >= nlocal)) continue; // with newton pair and one ghost we have to skip half the cases. // if id1 is a ghost, we skip if the sum of both ids is even. // if id2 is a ghost, we skip if the sum of both ids is odd. if (newton_pair) { if ((i >= nlocal) && ((par.id1+par.id2) & 1) == 0) continue; if ((j >= nlocal) && ((par.id1+par.id2) & 1) == 1) continue; } const double dx = x[i].x - x[j].x; const double dy = x[i].y - x[j].y; const double dz = x[i].z - x[j].z; const double rsq = dx*dx + dy*dy + dz*dz; fpair = epair = 0.0; if (check_flag) { if (newton_pair || i < nlocal) ++pc; if (newton_pair || j < nlocal) ++pc; } if (rsq < par.cutsq) { const double r2inv = 1.0/rsq; if (style[n] == HARM) { const double r = sqrt(rsq); const double dr = par.parm.harm.r0 - r; fpair = 2.0*par.parm.harm.k*dr/r; if (eflag_either) epair = par.parm.harm.k*dr*dr - par.offset; } else if (style[n] == MORSE) { const double r = sqrt(rsq); const double dr = par.parm.morse.r0 - r; const double dexp = exp(par.parm.morse.alpha * dr); fpair = 2.0*par.parm.morse.d0*par.parm.morse.alpha * (dexp*dexp - dexp) / r; if (eflag_either) epair = par.parm.morse.d0 * (dexp*dexp - 2.0*dexp) - par.offset; } else if (style[n] == LJ126) { const double r6inv = r2inv*r2inv*r2inv; const double sig6 = mypow(par.parm.lj126.sigma,6); fpair = 24.0*par.parm.lj126.epsilon*r6inv * (2.0*sig6*sig6*r6inv - sig6) * r2inv; if (eflag_either) epair = 4.0*par.parm.lj126.epsilon*r6inv * (sig6*sig6*r6inv - sig6) - par.offset; } if (newton_pair || i < nlocal) { f[i].x += dx*fpair; f[i].y += dy*fpair; f[i].z += dz*fpair; } if (newton_pair || j < nlocal) { f[j].x -= dx*fpair; f[j].y -= dy*fpair; f[j].z -= dz*fpair; } if (evflag) ev_tally(i,j,nlocal,newton_pair,epair,0.0,fpair,dx,dy,dz); } } if (vflag_fdotr) virial_fdotr_compute(); if (check_flag) { int tmp; MPI_Allreduce(&pc,&tmp,1,MPI_INT,MPI_SUM,world); if (tmp != 2*npairs) error->all(FLERR,"Not all pairs processed in pair_style list"); } } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairList::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"); } /* ---------------------------------------------------------------------- create one pair style for each arg in list ------------------------------------------------------------------------- */ void PairList::settings(int narg, char **arg) { if (narg < 2) error->all(FLERR,"Illegal pair_style command"); cut_global = force->numeric(FLERR,arg[1]); if (narg > 2) { if (strcmp(arg[2],"nocheck") == 0) check_flag = 0; if (strcmp(arg[2],"check") == 0) check_flag = 1; } FILE *fp = force->open_potential(arg[0]); char line[1024]; if (fp == NULL) error->all(FLERR,"Cannot open pair list file"); // count lines in file for upper limit of storage needed int num = 1; while(fgets(line,1024,fp)) ++num; rewind(fp); memory->create(style,num,"pair_list:style"); memory->create(params,num,"pair_list:params"); // now read and parse pair list file for real npairs = 0; char *ptr; tagint id1, id2; int nharm=0, nmorse=0, nlj126=0; while(fgets(line,1024,fp)) { ptr = strtok(line," \t\n\r\f"); // skip empty lines if (!ptr) continue; // skip comment lines starting with # if (*ptr == '#') continue; // get atom ids of pair id1 = ATOTAGINT(ptr); ptr = strtok(NULL," \t\n\r\f"); if (!ptr) error->all(FLERR,"Incorrectly formatted pair list file"); id2 = ATOTAGINT(ptr); // get potential type ptr = strtok(NULL," \t\n\r\f"); if (!ptr) error->all(FLERR,"Incorrectly formatted pair list file"); style[npairs] = NONE; list_parm_t &par = params[npairs]; par.id1 = id1; par.id2 = id2; // harmonic potential if (strcmp(ptr,stylename[HARM]) == 0) { style[npairs] = HARM; ptr = strtok(NULL," \t\n\r\f"); if ((ptr == NULL) || (*ptr == '#')) error->all(FLERR,"Incorrectly formatted harmonic pair parameters"); par.parm.harm.k = force->numeric(FLERR,ptr); ptr = strtok(NULL," \t\n\r\f"); if ((ptr == NULL) || (*ptr == '#')) error->all(FLERR,"Incorrectly formatted harmonic pair parameters"); par.parm.harm.r0 = force->numeric(FLERR,ptr); ++nharm; // morse potential } else if (strcmp(ptr,stylename[MORSE]) == 0) { style[npairs] = MORSE; ptr = strtok(NULL," \t\n\r\f"); if (!ptr) error->all(FLERR,"Incorrectly formatted morse pair parameters"); par.parm.morse.d0 = force->numeric(FLERR,ptr); ptr = strtok(NULL," \t\n\r\f"); if (!ptr) error->all(FLERR,"Incorrectly formatted morse pair parameters"); par.parm.morse.alpha = force->numeric(FLERR,ptr); ptr = strtok(NULL," \t\n\r\f"); if (!ptr) error->all(FLERR,"Incorrectly formatted morse pair parameters"); par.parm.morse.r0 = force->numeric(FLERR,ptr); ++nmorse; } else if (strcmp(ptr,stylename[LJ126]) == 0) { // 12-6 lj potential style[npairs] = LJ126; ptr = strtok(NULL," \t\n\r\f"); if (!ptr) error->all(FLERR,"Incorrectly formatted 12-6 LJ pair parameters"); par.parm.lj126.epsilon = force->numeric(FLERR,ptr); ptr = strtok(NULL," \t\n\r\f"); if (!ptr) error->all(FLERR,"Incorrectly formatted 12-6 LJ pair parameters"); par.parm.lj126.sigma = force->numeric(FLERR,ptr); ++nlj126; } else { error->all(FLERR,"Unknown pair list potential style"); } // optional cutoff parameter. if not specified use global value ptr = strtok(NULL," \t\n\r\f"); if ((ptr != NULL) && (*ptr != '#')) { double cut = force->numeric(FLERR,ptr); par.cutsq = cut*cut; } else { par.cutsq = cut_global*cut_global; } // count complete entry ++npairs; } fclose(fp); // informative output if (comm->me == 0) { if (screen) fprintf(screen,"Read %d (%d/%d/%d) interacting pairs from %s\n", npairs, nharm, nmorse, nlj126, arg[0]); if (logfile) fprintf(logfile,"Read %d (%d/%d/%d) interacting pairs from %s\n", npairs, nharm, nmorse, nlj126, arg[0]); } } /* ---------------------------------------------------------------------- there are no coeffs to be set, but we need to update setflag and pretend ------------------------------------------------------------------------- */ void PairList::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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,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++) { setflag[i][j] = 1; count++; } } if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style: compute energy offset at cutoff ------------------------------------------------------------------------- */ void PairList::init_style() { if (atom->tag_enable == 0) error->all(FLERR,"Pair style list requires atom IDs"); if (atom->map_style == 0) error->all(FLERR,"Pair style list requires an atom map"); if (offset_flag) { for (int n=0; n < npairs; ++n) { list_parm_t &par = params[n]; if (style[n] == HARM) { const double dr = sqrt(par.cutsq) - par.parm.harm.r0; par.offset = par.parm.harm.k*dr*dr; } else if (style[n] == MORSE) { const double dr = par.parm.morse.r0 - sqrt(par.cutsq); const double dexp = exp(par.parm.morse.alpha * dr); par.offset = par.parm.morse.d0 * (dexp*dexp - 2.0*dexp); } else if (style[n] == LJ126) { const double r6inv = par.cutsq*par.cutsq*par.cutsq; const double sig6 = mypow(par.parm.lj126.sigma,6); par.offset = 4.0*par.parm.lj126.epsilon*r6inv * (sig6*sig6*r6inv - sig6); } } } } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i since we don't use atom types or neighbor lists, this is a NOP. ------------------------------------------------------------------------- */ double PairList::init_one(int, int) { return cut_global; } /* ---------------------------------------------------------------------- memory usage of each sub-style ------------------------------------------------------------------------- */ double PairList::memory_usage() { double bytes = npairs * sizeof(int); bytes += npairs * sizeof(list_parm_t); const int n = atom->ntypes+1; bytes += n*(n*sizeof(int) + sizeof(int *)); bytes += n*(n*sizeof(double) + sizeof(double *)); return bytes; } diff --git a/src/USER-MISC/pair_lj_mdf.cpp b/src/USER-MISC/pair_lj_mdf.cpp index 7c3b8d586..3b52cf0b8 100644 --- a/src/USER-MISC/pair_lj_mdf.cpp +++ b/src/USER-MISC/pair_lj_mdf.cpp @@ -1,395 +1,395 @@ /* ---------------------------------------------------------------------- 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: Paolo Raiteri (Curtin University) ------------------------------------------------------------------------- */ #include #include #include #include #include "pair_lj_mdf.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; /* ---------------------------------------------------------------------- */ PairLJMDF::PairLJMDF(LAMMPS *lmp) : Pair(lmp) {} /* ---------------------------------------------------------------------- */ PairLJMDF::~PairLJMDF() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut); memory->destroy(cut_inner); memory->destroy(cut_inner_sq); memory->destroy(epsilon); memory->destroy(sigma); memory->destroy(lj1); memory->destroy(lj2); memory->destroy(lj3); memory->destroy(lj4); } } /* ---------------------------------------------------------------------- */ void PairLJMDF::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; double rr, d, dd, tt, dt, dp, philj; 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]); if (rsq > cut_inner_sq[itype][jtype]) { philj = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]); rr = sqrt(rsq); dp = (cut[itype][jtype] - cut_inner[itype][jtype]); d = (rr-cut_inner[itype][jtype]) / dp; dd = 1.-d; // taperig function - mdf style tt = (1. + 3.*d + 6.*d*d)*dd*dd*dd; // minus the derivative of the tapering function dt = 30.* d*d * dd*dd * rr / dp; forcelj = forcelj*tt + philj*dt; } else { tt = 1; } 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]); if (rsq > cut_inner_sq[itype][jtype]) evdwl *= tt; 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 PairLJMDF::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(cut_inner,n+1,n+1,"pair:cut_inner"); memory->create(cut_inner_sq,n+1,n+1,"pair:cut_inner_sq"); 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"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairLJMDF::settings(int narg, char **arg) { if (narg != 2) error->all(FLERR,"Illegal pair_style command"); cut_inner_global = force->numeric(FLERR,arg[0]); cut_global = force->numeric(FLERR,arg[1]); if (cut_inner_global <= 0.0 || cut_inner_global > cut_global) error->all(FLERR,"Illegal pair_style command"); // 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_inner[i][j] = cut_inner_global; cut[i][j] = cut_global; } } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairLJMDF::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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(FLERR,arg[2]); double sigma_one = force->numeric(FLERR,arg[3]); double cut_inner_one = cut_inner_global; double cut_one = cut_global; if (narg == 6) { cut_inner_one = force->numeric(FLERR,arg[4]); cut_one = force->numeric(FLERR,arg[5]); } if (cut_inner_global <= 0.0 || cut_inner_global > cut_global) error->all(FLERR,"Illegal pair_style command"); 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_inner[i][j] = cut_inner_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 PairLJMDF::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_inner[i][j] = mix_distance(cut_inner[i][i],cut_inner[j][j]); cut[i][j] = mix_distance(cut[i][i],cut[j][j]); } cut_inner_sq[i][j] = cut_inner[i][j]*cut_inner[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); cut[j][i] = cut[i][j]; // BUG FIX cut_inner[j][i] = cut_inner[i][j]; cut_inner_sq[j][i] = cut_inner_sq[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]; return cut[i][j]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJMDF::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_inner[i][j],sizeof(double),1,fp); fwrite(&cut[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJMDF::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_inner[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_inner[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJMDF::write_restart_settings(FILE *fp) { fwrite(&mix_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJMDF::read_restart_settings(FILE *fp) { int me = comm->me; if (me == 0) { fread(&mix_flag,sizeof(int),1,fp); } MPI_Bcast(&mix_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- */ double PairLJMDF::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r2inv,r6inv,forcelj,philj; double rr, dp, d, tt, dt, dd; r2inv = 1.0/rsq; r6inv = r2inv*r2inv*r2inv; philj = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]); forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); if (rsq > cut_inner_sq[itype][jtype]) { rr = sqrt(rsq); dp = (cut[itype][jtype] - cut_inner[itype][jtype]); d = (rr - cut_inner[itype][jtype]) / dp; dd = 1-d; tt = (1. + 3.*d + 6.*d*d)* dd*dd*dd; dt = 30.* d*d * dd*dd * rr / dp; forcelj = forcelj*tt + philj*dt; philj *= tt; } fforce = factor_lj*forcelj*r2inv; return factor_lj*philj; } /* ---------------------------------------------------------------------- */ void *PairLJMDF::extract(const char *str, int &dim) { dim = 2; if (strcmp(str,"epsilon") == 0) return (void *) epsilon; if (strcmp(str,"sigma") == 0) return (void *) sigma; return NULL; } diff --git a/src/USER-MISC/pair_lj_sf.cpp b/src/USER-MISC/pair_lj_sf.cpp index 69a7efcfd..32f45ff48 100644 --- a/src/USER-MISC/pair_lj_sf.cpp +++ b/src/USER-MISC/pair_lj_sf.cpp @@ -1,355 +1,355 @@ /* ---------------------------------------------------------------------- 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: Laurent Joly (U Lyon), ljoly.ulyon@gmail.com ------------------------------------------------------------------------- */ #include #include #include #include "pair_lj_sf.h" #include "atom.h" #include "comm.h" #include "force.h" #include "neigh_list.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ PairLJShiftedForce::PairLJShiftedForce(LAMMPS *lmp) : Pair(lmp) { respa_enable = 0; } /* ---------------------------------------------------------------------- */ PairLJShiftedForce::~PairLJShiftedForce() { 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(foffset); memory->destroy(offset); } } /* ---------------------------------------------------------------------- */ void PairLJShiftedForce::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; double r,t; 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); t = r/cut[itype][jtype]; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]) - t*foffset[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]) + (t-1.0)*foffset[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(); } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairLJShiftedForce::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(foffset,n+1,n+1,"pair:foffset"); memory->create(offset,n+1,n+1,"pair:offset"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairLJShiftedForce::settings(int narg, char **arg) { if (narg != 1) error->all(FLERR,"Illegal pair_style command"); cut_global = force->numeric(FLERR,arg[0]); if (cut_global <= 0.0) error->all(FLERR,"Illegal pair_style command"); // 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 PairLJShiftedForce::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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(FLERR,arg[2]); double sigma_one = force->numeric(FLERR,arg[3]); double cut_one = cut_global; if (narg == 5) cut_one = force->numeric(FLERR,arg[4]); if (cut_one <= 0.0) error->all(FLERR,"Incorrect args for pair coefficients"); 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 for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairLJShiftedForce::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); double ratio = sigma[i][j] / cut[i][j]; foffset[i][j] = 4.0 * epsilon[i][j] * (12.0 * pow(ratio,12.0) - 6.0 * pow(ratio,6.0)); offset[i][j] = 4.0 * epsilon[i][j] * (pow(ratio,12.0) - pow(ratio,6.0)); cut[j][i] = cut[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]; foffset[j][i] = foffset[i][j]; offset[j][i] = offset[i][j]; return cut[i][j]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJShiftedForce::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 PairLJShiftedForce::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 PairLJShiftedForce::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 PairLJShiftedForce::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 PairLJShiftedForce::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r2inv,r6inv,forcelj,philj,r,t; r2inv = 1.0/rsq; r6inv = r2inv*r2inv*r2inv; r = sqrt(rsq); t = r/cut[itype][jtype]; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]) - t*foffset[itype][jtype]; fforce = factor_lj*forcelj*r2inv; philj = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]) + (t-1.0)*foffset[itype][jtype] - offset[itype][jtype]; return factor_lj*philj; } diff --git a/src/USER-MISC/pair_lj_sf_dipole_sf.cpp b/src/USER-MISC/pair_lj_sf_dipole_sf.cpp index b88f72bac..33f10f2f1 100644 --- a/src/USER-MISC/pair_lj_sf_dipole_sf.cpp +++ b/src/USER-MISC/pair_lj_sf_dipole_sf.cpp @@ -1,642 +1,642 @@ /* ---------------------------------------------------------------------- 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: Mario Orsi (QMUL), m.orsi@qmul.ac.uk Samuel Genheden (University of Southampton) ------------------------------------------------------------------------- */ #include #include #include "pair_lj_sf_dipole_sf.h" #include "atom.h" #include "neighbor.h" #include "neigh_list.h" #include "comm.h" #include "force.h" #include "memory.h" #include "error.h" #include "update.h" #include using namespace LAMMPS_NS; static int warn_single = 0; /* ---------------------------------------------------------------------- */ PairLJSFDipoleSF::PairLJSFDipoleSF(LAMMPS *lmp) : Pair(lmp) { } /* ---------------------------------------------------------------------- */ PairLJSFDipoleSF::~PairLJSFDipoleSF() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut_lj); memory->destroy(cut_ljsq); memory->destroy(cut_coul); memory->destroy(cut_coulsq); memory->destroy(epsilon); memory->destroy(sigma); memory->destroy(lj1); memory->destroy(lj2); memory->destroy(lj3); memory->destroy(lj4); memory->destroy(scale); } } /* ---------------------------------------------------------------------- */ void PairLJSFDipoleSF::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fx,fy,fz; double rsq,rinv,r2inv,r6inv,r3inv,r5inv; double forcecoulx,forcecouly,forcecoulz,crossx,crossy,crossz; double tixcoul,tiycoul,tizcoul,tjxcoul,tjycoul,tjzcoul; double fq,pdotp,pidotr,pjdotr,pre1,pre2,pre3,pre4; double forcelj,factor_coul,factor_lj; double presf,afac,bfac,pqfac,qpfac,forceljcut,forceljsf; double aforcecoulx,aforcecouly,aforcecoulz; double bforcecoulx,bforcecouly,bforcecoulz; double rcutlj2inv, rcutcoul2inv,rcutlj6inv; 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; double **mu = atom->mu; double **torque = atom->torque; 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; rinv = sqrt(r2inv); // atom can have both a charge and dipole // i,j = charge-charge, dipole-dipole, dipole-charge, or charge-dipole forcecoulx = forcecouly = forcecoulz = 0.0; tixcoul = tiycoul = tizcoul = 0.0; tjxcoul = tjycoul = tjzcoul = 0.0; if (rsq < cut_coulsq[itype][jtype]) { rcutcoul2inv=1.0/cut_coulsq[itype][jtype]; if (qtmp != 0.0 && q[j] != 0.0) { pre1 = qtmp*q[j]*rinv*(r2inv-rcutcoul2inv); forcecoulx += pre1*delx; forcecouly += pre1*dely; forcecoulz += pre1*delz; } if (mu[i][3] > 0.0 && mu[j][3] > 0.0) { r3inv = r2inv*rinv; r5inv = r3inv*r2inv; pdotp = mu[i][0]*mu[j][0] + mu[i][1]*mu[j][1] + mu[i][2]*mu[j][2]; pidotr = mu[i][0]*delx + mu[i][1]*dely + mu[i][2]*delz; pjdotr = mu[j][0]*delx + mu[j][1]*dely + mu[j][2]*delz; afac = 1.0 - rsq*rsq * rcutcoul2inv*rcutcoul2inv; pre1 = afac * ( pdotp - 3.0 * r2inv * pidotr * pjdotr ); aforcecoulx = pre1*delx; aforcecouly = pre1*dely; aforcecoulz = pre1*delz; bfac = 1.0 - 4.0*rsq*sqrt(rsq*rcutcoul2inv)*rcutcoul2inv + 3.0*rsq*rsq*rcutcoul2inv*rcutcoul2inv; presf = 2.0 * r2inv * pidotr * pjdotr; bforcecoulx = bfac * (pjdotr*mu[i][0]+pidotr*mu[j][0]-presf*delx); bforcecouly = bfac * (pjdotr*mu[i][1]+pidotr*mu[j][1]-presf*dely); bforcecoulz = bfac * (pjdotr*mu[i][2]+pidotr*mu[j][2]-presf*delz); forcecoulx += 3.0 * r5inv * ( aforcecoulx + bforcecoulx ); forcecouly += 3.0 * r5inv * ( aforcecouly + bforcecouly ); forcecoulz += 3.0 * r5inv * ( aforcecoulz + bforcecoulz ); pre2 = 3.0 * bfac * r5inv * pjdotr; pre3 = 3.0 * bfac * r5inv * pidotr; pre4 = -bfac * r3inv; crossx = pre4 * (mu[i][1]*mu[j][2] - mu[i][2]*mu[j][1]); crossy = pre4 * (mu[i][2]*mu[j][0] - mu[i][0]*mu[j][2]); crossz = pre4 * (mu[i][0]*mu[j][1] - mu[i][1]*mu[j][0]); tixcoul += crossx + pre2 * (mu[i][1]*delz - mu[i][2]*dely); tiycoul += crossy + pre2 * (mu[i][2]*delx - mu[i][0]*delz); tizcoul += crossz + pre2 * (mu[i][0]*dely - mu[i][1]*delx); tjxcoul += -crossx + pre3 * (mu[j][1]*delz - mu[j][2]*dely); tjycoul += -crossy + pre3 * (mu[j][2]*delx - mu[j][0]*delz); tjzcoul += -crossz + pre3 * (mu[j][0]*dely - mu[j][1]*delx); } if (mu[i][3] > 0.0 && q[j] != 0.0) { r3inv = r2inv*rinv; r5inv = r3inv*r2inv; pidotr = mu[i][0]*delx + mu[i][1]*dely + mu[i][2]*delz; pre1 = 3.0 * q[j] * r5inv * pidotr * (1-rsq*rcutcoul2inv); pqfac = 1.0 - 3.0*rsq*rcutcoul2inv + 2.0*rsq*sqrt(rsq*rcutcoul2inv)*rcutcoul2inv; pre2 = q[j] * r3inv * pqfac; forcecoulx += pre2*mu[i][0] - pre1*delx; forcecouly += pre2*mu[i][1] - pre1*dely; forcecoulz += pre2*mu[i][2] - pre1*delz; tixcoul += pre2 * (mu[i][1]*delz - mu[i][2]*dely); tiycoul += pre2 * (mu[i][2]*delx - mu[i][0]*delz); tizcoul += pre2 * (mu[i][0]*dely - mu[i][1]*delx); } if (mu[j][3] > 0.0 && qtmp != 0.0) { r3inv = r2inv*rinv; r5inv = r3inv*r2inv; pjdotr = mu[j][0]*delx + mu[j][1]*dely + mu[j][2]*delz; pre1 = 3.0 * qtmp * r5inv * pjdotr * (1-rsq*rcutcoul2inv); qpfac = 1.0 - 3.0*rsq*rcutcoul2inv + 2.0*rsq*sqrt(rsq*rcutcoul2inv)*rcutcoul2inv; pre2 = qtmp * r3inv * qpfac; forcecoulx += pre1*delx - pre2*mu[j][0]; forcecouly += pre1*dely - pre2*mu[j][1]; forcecoulz += pre1*delz - pre2*mu[j][2]; tjxcoul += -pre2 * (mu[j][1]*delz - mu[j][2]*dely); tjycoul += -pre2 * (mu[j][2]*delx - mu[j][0]*delz); tjzcoul += -pre2 * (mu[j][0]*dely - mu[j][1]*delx); } } // LJ interaction if (rsq < cut_ljsq[itype][jtype]) { r6inv = r2inv*r2inv*r2inv; forceljcut = r6inv*(lj1[itype][jtype]*r6inv-lj2[itype][jtype])*r2inv; rcutlj2inv = 1.0 / cut_ljsq[itype][jtype]; rcutlj6inv = rcutlj2inv * rcutlj2inv * rcutlj2inv; forceljsf = (lj1[itype][jtype]*rcutlj6inv - lj2[itype][jtype]) * rcutlj6inv * rcutlj2inv; forcelj = factor_lj * (forceljcut - forceljsf); } else forcelj = 0.0; // total force fq = factor_coul*qqrd2e*scale[itype][jtype]; fx = fq*forcecoulx + delx*forcelj; fy = fq*forcecouly + dely*forcelj; fz = fq*forcecoulz + delz*forcelj; // force & torque accumulation f[i][0] += fx; f[i][1] += fy; f[i][2] += fz; torque[i][0] += fq*tixcoul; torque[i][1] += fq*tiycoul; torque[i][2] += fq*tizcoul; if (newton_pair || j < nlocal) { f[j][0] -= fx; f[j][1] -= fy; f[j][2] -= fz; torque[j][0] += fq*tjxcoul; torque[j][1] += fq*tjycoul; torque[j][2] += fq*tjzcoul; } if (eflag) { if (rsq < cut_coulsq[itype][jtype]) { ecoul = (1.0-sqrt(rsq/cut_coulsq[itype][jtype])); ecoul *= ecoul; ecoul *= qtmp * q[j] * rinv; if (mu[i][3] > 0.0 && mu[j][3] > 0.0) ecoul += bfac * (r3inv*pdotp - 3.0*r5inv*pidotr*pjdotr); if (mu[i][3] > 0.0 && q[j] != 0.0) ecoul += -q[j] * r3inv * pqfac * pidotr; if (mu[j][3] > 0.0 && qtmp != 0.0) ecoul += qtmp * r3inv * qpfac * pjdotr; ecoul *= factor_coul*qqrd2e*scale[itype][jtype]; } else ecoul = 0.0; if (rsq < cut_ljsq[itype][jtype]) { evdwl = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype])+ rcutlj6inv*(6*lj3[itype][jtype]*rcutlj6inv-3*lj4[itype][jtype])* rsq*rcutlj2inv+ rcutlj6inv*(-7*lj3[itype][jtype]*rcutlj6inv+4*lj4[itype][jtype]); evdwl *= factor_lj; } else evdwl = 0.0; } if (evflag) ev_tally_xyz(i,j,nlocal,newton_pair, evdwl,ecoul,fx,fy,fz,delx,dely,delz); } } } if (vflag_fdotr) virial_fdotr_compute(); } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairLJSFDipoleSF::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(cut_coul,n+1,n+1,"pair:cut_coul"); memory->create(cut_coulsq,n+1,n+1,"pair:cut_coulsq"); 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(scale,n+1,n+1,"pair:scale"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairLJSFDipoleSF::settings(int narg, char **arg) { if (narg < 1 || narg > 2) error->all(FLERR,"Incorrect args in pair_style command"); if (strcmp(update->unit_style,"electron") == 0) error->all(FLERR,"Cannot (yet) use 'electron' units with dipoles"); cut_lj_global = force->numeric(FLERR,arg[0]); if (narg == 1) cut_coul_global = cut_lj_global; else cut_coul_global = force->numeric(FLERR,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; cut_coul[i][j] = cut_coul_global; } } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairLJSFDipoleSF::coeff(int narg, char **arg) { if (narg < 4 || 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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(FLERR,arg[2]); double sigma_one = force->numeric(FLERR,arg[3]); double cut_lj_one = cut_lj_global; double cut_coul_one = cut_coul_global; double scale_one = 1.0; int iarg = 4; if ((narg > iarg) && (strcmp(arg[iarg],"scale") != 0)) { cut_coul_one = cut_lj_one = force->numeric(FLERR,arg[iarg]); ++iarg; } if ((narg > iarg) && (strcmp(arg[iarg],"scale") != 0)) { cut_coul_one = force->numeric(FLERR,arg[iarg]); ++iarg; } if (narg > iarg) { if (strcmp(arg[iarg],"scale") == 0) { scale_one = force->numeric(FLERR,arg[iarg+1]); iarg += 2; } else error->all(FLERR,"Incorrect args for pair coefficients"); } if (iarg != narg) error->all(FLERR,"Incorrect args for pair coefficients"); 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; cut_coul[i][j] = cut_coul_one; setflag[i][j] = 1; scale[i][j] = scale_one; count++; } } if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairLJSFDipoleSF::init_style() { if (!atom->q_flag || !atom->mu_flag || !atom->torque_flag) error->all(FLERR,"Pair dipole/sf requires atom attributes q, mu, torque"); neighbor->request(this,instance_me); } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairLJSFDipoleSF::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]); cut_coul[i][j] = mix_distance(cut_coul[i][i],cut_coul[j][j]); } double cut = MAX(cut_lj[i][j],cut_coul[i][j]); cut_ljsq[i][j] = cut_lj[i][j] * cut_lj[i][j]; cut_coulsq[i][j] = cut_coul[i][j] * cut_coul[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); cut_ljsq[j][i] = cut_ljsq[i][j]; cut_coulsq[j][i] = cut_coulsq[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]; scale[j][i] = scale[i][j]; return cut; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJSFDipoleSF::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); fwrite(&cut_coul[i][j],sizeof(double),1,fp); fwrite(&scale[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJSFDipoleSF::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); fread(&cut_coul[i][j],sizeof(double),1,fp); fread(&scale[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); MPI_Bcast(&cut_coul[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&scale[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJSFDipoleSF::write_restart_settings(FILE *fp) { fwrite(&cut_lj_global,sizeof(double),1,fp); fwrite(&cut_coul_global,sizeof(double),1,fp); fwrite(&mix_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJSFDipoleSF::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&cut_lj_global,sizeof(double),1,fp); fread(&cut_coul_global,sizeof(double),1,fp); fread(&mix_flag,sizeof(int),1,fp); } MPI_Bcast(&cut_lj_global,1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_coul_global,1,MPI_DOUBLE,0,world); MPI_Bcast(&mix_flag,1,MPI_INT,0,world); } // PairLJSFDipoleSF: calculation of force is missing (to be implemented) double PairLJSFDipoleSF::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r2inv,r6inv; double pdotp,pidotr,pjdotr,pre1,delx,dely,delz; double rinv, r3inv,r5inv, rcutlj2inv, rcutcoul2inv,rcutlj6inv; double qtmp,xtmp,ytmp,ztmp,bfac,pqfac,qpfac, ecoul, evdwl; double **x = atom->x; double *q = atom->q; double **mu = atom->mu; if (!warn_single) { warn_single = 1; if (comm->me == 0) { error->warning(FLERR,"Single method for lj/sf/dipole/sf does not compute forces"); } } qtmp = q[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; r2inv = 1.0/rsq; rinv = sqrt(r2inv); fforce = 0.0; if (rsq < cut_coulsq[itype][jtype]) { delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; // if (qtmp != 0.0 && q[j] != 0.0) { // pre1 = qtmp*q[j]*rinv*(r2inv-1.0/cut_coulsq[itype][jtype]); // forcecoulx += pre1*delx; // forcecouly += pre1*dely; // forcecoulz += pre1*delz; // } if (mu[i][3] > 0.0 && mu[j][3] > 0.0) { r3inv = r2inv*rinv; r5inv = r3inv*r2inv; rcutcoul2inv=1.0/cut_coulsq[itype][jtype]; pdotp = mu[i][0]*mu[j][0] + mu[i][1]*mu[j][1] + mu[i][2]*mu[j][2]; pidotr = mu[i][0]*delx + mu[i][1]*dely + mu[i][2]*delz; pjdotr = mu[j][0]*delx + mu[j][1]*dely + mu[j][2]*delz; bfac = 1.0 - 4.0*rsq*sqrt(rsq)*rcutcoul2inv*sqrt(rcutcoul2inv) + 3.0*rsq*rsq*rcutcoul2inv*rcutcoul2inv; } if (mu[i][3] > 0.0 && q[j] != 0.0) { r3inv = r2inv*rinv; r5inv = r3inv*r2inv; pidotr = mu[i][0]*delx + mu[i][1]*dely + mu[i][2]*delz; rcutcoul2inv=1.0/cut_coulsq[itype][jtype]; pqfac = 1.0 - 3.0*rsq*rcutcoul2inv + 2.0*rsq*sqrt(rsq)*rcutcoul2inv*sqrt(rcutcoul2inv); } if (mu[j][3] > 0.0 && qtmp != 0.0) { r3inv = r2inv*rinv; r5inv = r3inv*r2inv; pjdotr = mu[j][0]*delx + mu[j][1]*dely + mu[j][2]*delz; rcutcoul2inv=1.0/cut_coulsq[itype][jtype]; qpfac = 1.0 - 3.0*rsq*rcutcoul2inv + 2.0*rsq*sqrt(rsq)*rcutcoul2inv*sqrt(rcutcoul2inv); } } if (rsq < cut_ljsq[itype][jtype]) { r6inv = r2inv*r2inv*r2inv; rcutlj2inv = 1.0 / cut_ljsq[itype][jtype]; rcutlj6inv = rcutlj2inv * rcutlj2inv * rcutlj2inv; } double eng = 0.0; if (rsq < cut_coulsq[itype][jtype]) { ecoul = (1.0-sqrt(rsq)/sqrt(cut_coulsq[itype][jtype])); ecoul *= ecoul; ecoul *= qtmp * q[j] * rinv; if (mu[i][3] > 0.0 && mu[j][3] > 0.0) ecoul += bfac * (r3inv*pdotp - 3.0*r5inv*pidotr*pjdotr); if (mu[i][3] > 0.0 && q[j] != 0.0) ecoul += -q[j] * r3inv * pqfac * pidotr; if (mu[j][3] > 0.0 && qtmp != 0.0) ecoul += qtmp * r3inv * qpfac * pjdotr; ecoul *= factor_coul*force->qqrd2e*scale[itype][jtype]; eng += ecoul; } if (rsq < cut_ljsq[itype][jtype]) { evdwl = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype])+ rcutlj6inv*(6*lj3[itype][jtype]*rcutlj6inv-3*lj4[itype][jtype])* rsq*rcutlj2inv+ rcutlj6inv*(-7*lj3[itype][jtype]*rcutlj6inv+4*lj4[itype][jtype]); eng += evdwl*factor_lj; } return eng; } /* ---------------------------------------------------------------------- */ void *PairLJSFDipoleSF::extract(const char *str, int &dim) { dim = 2; if (strcmp(str,"epsilon") == 0) return (void *) epsilon; if (strcmp(str,"sigma") == 0) return (void *) sigma; if (strcmp(str,"scale") == 0) return (void *) scale; return NULL; } diff --git a/src/USER-MISC/pair_morse_smooth_linear.cpp b/src/USER-MISC/pair_morse_smooth_linear.cpp index 844d0113b..ea33510b5 100644 --- a/src/USER-MISC/pair_morse_smooth_linear.cpp +++ b/src/USER-MISC/pair_morse_smooth_linear.cpp @@ -1,370 +1,370 @@ /* ---------------------------------------------------------------------- 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 #include #include #include #include "pair_morse_smooth_linear.h" #include "atom.h" #include "comm.h" #include "force.h" #include "neigh_list.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ PairMorseSmoothLinear::PairMorseSmoothLinear(LAMMPS *lmp) : Pair(lmp) { writedata = 1; } /* ---------------------------------------------------------------------- */ PairMorseSmoothLinear::~PairMorseSmoothLinear() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut); memory->destroy(d0); memory->destroy(alpha); memory->destroy(r0); memory->destroy(morse1); memory->destroy(der_at_cutoff); memory->destroy(offset); } } /* ---------------------------------------------------------------------- */ void PairMorseSmoothLinear::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair, fpartial; double rsq,r,dr,dexp,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); dr = r - r0[itype][jtype]; dexp = exp(-alpha[itype][jtype] * dr); fpartial = morse1[itype][jtype] * (dexp*dexp - dexp) / r; fpair = factor_lj * ( fpartial - der_at_cutoff[itype][jtype] / r); 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 = d0[itype][jtype] * (dexp*dexp - 2.0*dexp) - offset[itype][jtype]; evdwl += ( r - cut[itype][jtype] ) * der_at_cutoff[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 PairMorseSmoothLinear::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(d0,n+1,n+1,"pair:d0"); memory->create(alpha,n+1,n+1,"pair:alpha"); memory->create(r0,n+1,n+1,"pair:r0"); memory->create(morse1,n+1,n+1,"pair:morse1"); memory->create(der_at_cutoff,n+1,n+1,"pair:der_at_cutoff"); memory->create(offset,n+1,n+1,"pair:offset"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairMorseSmoothLinear::settings(int narg, char **arg) { if (narg != 1) error->all(FLERR,"Illegal pair_style command"); cut_global = force->numeric(FLERR,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 PairMorseSmoothLinear::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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double d0_one = force->numeric(FLERR,arg[2]); double alpha_one = force->numeric(FLERR,arg[3]); double r0_one = force->numeric(FLERR,arg[4]); double cut_one = cut_global; if (narg == 6) cut_one = force->numeric(FLERR,arg[5]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { d0[i][j] = d0_one; alpha[i][j] = alpha_one; r0[i][j] = r0_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 PairMorseSmoothLinear::init_one(int i, int j) { if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set"); morse1[i][j] = 2.0*d0[i][j]*alpha[i][j]; double alpha_dr = -alpha[i][j] * (cut[i][j] - r0[i][j]); offset[i][j] = d0[i][j] * (exp(2.0*alpha_dr) - 2.0*exp(alpha_dr)); der_at_cutoff[i][j] = -2.0*alpha[i][j]*d0[i][j] * (exp(2.0*alpha_dr) - exp(alpha_dr)); d0[j][i] = d0[i][j]; alpha[j][i] = alpha[i][j]; r0[j][i] = r0[i][j]; morse1[j][i] = morse1[i][j]; der_at_cutoff[j][i] = der_at_cutoff[i][j]; offset[j][i] = offset[i][j]; return cut[i][j]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairMorseSmoothLinear::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(&d0[i][j],sizeof(double),1,fp); fwrite(&alpha[i][j],sizeof(double),1,fp); fwrite(&r0[i][j],sizeof(double),1,fp); fwrite(&cut[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairMorseSmoothLinear::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(&d0[i][j],sizeof(double),1,fp); fread(&alpha[i][j],sizeof(double),1,fp); fread(&r0[i][j],sizeof(double),1,fp); fread(&cut[i][j],sizeof(double),1,fp); } MPI_Bcast(&d0[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&alpha[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&r0[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairMorseSmoothLinear::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 PairMorseSmoothLinear::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); } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void PairMorseSmoothLinear::write_data(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) fprintf(fp,"%d %g %g %g\n",i,d0[i][i],alpha[i][i],r0[i][i]); } /* ---------------------------------------------------------------------- proc 0 writes all pairs to data file ------------------------------------------------------------------------- */ void PairMorseSmoothLinear::write_data_all(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) fprintf(fp,"%d %d %g %g %g %g\n", i,j,d0[i][j],alpha[i][j],r0[i][j],cut[i][j]); } /* ---------------------------------------------------------------------- */ double PairMorseSmoothLinear::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r,dr,dexp,phi; r = sqrt(rsq); dr = r - r0[itype][jtype]; dexp = exp(-alpha[itype][jtype] * dr); fforce = factor_lj * morse1[itype][jtype] * (dexp*dexp - dexp) / r; phi = d0[itype][jtype] * (dexp*dexp - 2.0*dexp) - offset[itype][jtype]; dr = cut[itype][jtype] - r0[itype][jtype]; phi += dr * der_at_cutoff[itype][jtype]; return factor_lj*phi; } /* ---------------------------------------------------------------------- */ void *PairMorseSmoothLinear::extract(const char *str, int &dim) { dim = 2; if (strcmp(str,"d0") == 0) return (void *) d0; if (strcmp(str,"r0") == 0) return (void *) r0; if (strcmp(str,"alpha") == 0) return (void *) alpha; return NULL; } diff --git a/src/USER-MISC/pair_srp.cpp b/src/USER-MISC/pair_srp.cpp index 5e254b74b..18ea4dc33 100644 --- a/src/USER-MISC/pair_srp.cpp +++ b/src/USER-MISC/pair_srp.cpp @@ -1,744 +1,744 @@ /* ---------------------------------------------------------------------- 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: Timothy Sirk (ARL), Pieter in't Veld (BASF) This pair style srp command calculates a segmental repulsive force between bonds. This is useful for preventing the crossing of bonds if soft non-bonded potentials are used, such as DPD polymer chains. See the doc page for pair_style srp command for usage instructions. There is an example script for this package in examples/USER/srp. Please contact Timothy Sirk for questions (tim.sirk@us.army.mil). ------------------------------------------------------------------------- */ #include #include "pair_srp.h" #include "atom.h" #include "comm.h" #include "force.h" #include "neighbor.h" #include "neigh_list.h" #include "memory.h" #include "error.h" #include "domain.h" #include "modify.h" #include "fix.h" #include "fix_srp.h" #include "thermo.h" #include "output.h" #include #include "citeme.h" using namespace LAMMPS_NS; #define SMALL 1.0e-10 #define BIG 1e10 #define ONETWOBIT 0x40000000 static const char cite_srp[] = "@Article{Sirk2012\n" " author = {T. Sirk and Y. Sliozberg and J. Brennan and M. Lisal and J. Andzelm},\n" " title = {An enhanced entangled polymer model for dissipative particle dynamics},\n" " journal = {J.~Chem.~Phys.},\n" " year = 2012,\n" " volume = 136,\n" " pages = {134903}\n" "}\n\n"; static int srp_instance = 0; /* ---------------------------------------------------------------------- set size of pair comms in constructor ---------------------------------------------------------------------- */ PairSRP::PairSRP(LAMMPS *lmp) : Pair(lmp) { writedata = 1; if (lmp->citeme) lmp->citeme->add(cite_srp); nextra = 1; segment = NULL; // generate unique fix-id for this pair style instance fix_id = strdup("XX_FIX_SRP"); fix_id[0] = '0' + srp_instance / 10; fix_id[1] = '0' + srp_instance % 10; ++srp_instance; // create fix SRP instance here, as it has to // be executed before all other fixes char **fixarg = new char*[3]; fixarg[0] = fix_id; fixarg[1] = (char *) "all"; fixarg[2] = (char *) "SRP"; modify->add_fix(3,fixarg); f_srp = (FixSRP *) modify->fix[modify->nfix-1]; delete [] fixarg; } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairSRP::allocate() { allocated = 1; // particles of bptype inserted by fix srp // bptype is the highest numbered atom type int n = bptype; memory->create(cutsq, n + 1, n + 1, "pair:cutsq"); memory->create(cut, n + 1, n + 1, "pair:cut"); memory->create(a0, n + 1, n + 1, "pair:a0"); // setflag for atom types 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; maxcount = 0; } /* ---------------------------------------------------------------------- free ------------------------------------------------------------------------- */ PairSRP::~PairSRP() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut); memory->destroy(a0); memory->destroy(segment); } // check nfix in case all fixes have already been deleted if (modify->nfix) modify->delete_fix(fix_id); free(fix_id); } /* ---------------------------------------------------------------------- compute bond-bond repulsions ------------------------------------------------------------------------- */ void PairSRP::compute(int eflag, int vflag) { // setup energy and virial if (eflag || vflag) ev_setup(eflag, vflag); else evflag = vflag_fdotr = 0; double **x = atom->x; double **f = atom->f; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; int i0, i1, j0, j1; int i,j,ii,jj,inum,jnum; double dijsq, dij; int *ilist,*jlist,*numneigh,**firstneigh; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; double dx,dy,dz,ti,tj; double wd, lever0, lever1, evdwl, fpair; double fxlever0, fylever0, fzlever0, fxlever1, fylever1, fzlever1; double fx, fy, fz; evdwl = 0.0; // mapping global to local for atoms inside bond particles // exclude 1-2 neighs if requested if (neighbor->ago == 0){ remapBonds(nall); if(exclude) onetwoexclude(ilist, inum, jlist, numneigh, firstneigh); } // this pair style only used with hybrid // due to exclusions // each atom i is type bptype // each neigh j is type bptype // using midpoint distance option if(midpoint){ for (ii = 0; ii < inum; ii++) { i = ilist[ii]; jnum = numneigh[i]; // two atoms inside bond particle i0 = segment[i][0]; j0 = segment[i][1]; for (jj = 0; jj < jnum; jj++) { jlist = firstneigh[i]; j = jlist[jj]; // enforce 1-2 exclusions if( (sbmask(j) & exclude) ) continue; j &= NEIGHMASK; //retrieve atoms from bond particle i1 = segment[j][0]; j1 = segment[j][1]; // midpt dist bond 0 and 1 dx = 0.5*(x[i0][0] - x[i1][0] + x[j0][0] - x[j1][0]); dy = 0.5*(x[i0][1] - x[i1][1] + x[j0][1] - x[j1][1]); dz = 0.5*(x[i0][2] - x[i1][2] + x[j0][2] - x[j1][2]); dijsq = dx*dx + dy*dy + dz*dz; if (dijsq < cutsq[bptype][bptype]){ dij = sqrt(dijsq); if (dij < SMALL) continue; // dij can be 0.0 with soft potentials wd = 1.0 - dij / cut[bptype][bptype]; fpair = 0.5 * a0[bptype][bptype] * wd / dij; // 0.5 factor for lever rule // force for bond 0, beads 0,1 //force between bonds fx = fpair * dx; fy = fpair * dy; fz = fpair * dz; f[i0][0] += fx; //keep force sign for bond 0 f[i0][1] += fy; f[i0][2] += fz; f[j0][0] += fx; f[j0][1] += fy; f[j0][2] += fz; f[i1][0] -= fx; //flip force sign for bond 1 f[i1][1] -= fy; f[i1][2] -= fz; f[j1][0] -= fx; f[j1][1] -= fy; f[j1][2] -= fz; // ************************************************* // if (eflag){ evdwl = 0.5 * a0[bptype][bptype] * cut[bptype][bptype] * wd * wd; } if (evflag){ ev_tally(i0,i1,nlocal,1,0.5*evdwl,0.0,fpair,dx,dy,dz); ev_tally(j0,j1,nlocal,1,0.5*evdwl,0.0,fpair,dx,dy,dz); } if (vflag_fdotr) virial_fdotr_compute(); } } } } else{ // using min distance option for (ii = 0; ii < inum; ii++) { i = ilist[ii]; jnum = numneigh[i]; i0 = segment[i][0]; j0 = segment[i][1]; for (jj = 0; jj < jnum; jj++) { jlist = firstneigh[i]; j = jlist[jj]; // enforce 1-2 exclusions if( (sbmask(j) & exclude) ) continue; j &= NEIGHMASK; i1 = segment[j][0]; j1 = segment[j][1]; getMinDist(x, dx, dy, dz, ti, tj, i0, j0, i1, j1); dijsq = dx*dx + dy*dy + dz*dz; if (dijsq < cutsq[bptype][bptype]){ dij = sqrt(dijsq); if (dij < SMALL) continue; // dij can be 0.0 with soft potentials wd = 1.0 - dij / cut[bptype][bptype]; fpair = a0[bptype][bptype] * wd / dij; // force for bond 0, beads 0,1 lever0 = 0.5 + ti; // assign force according to lever rule lever1 = 0.5 + tj; // assign force according to lever rule //force between bonds fx = fpair * dx; fy = fpair * dy; fz = fpair * dz; //decompose onto atoms fxlever0 = fx * lever0; fylever0 = fy * lever0; fzlever0 = fz * lever0; fxlever1 = fx * lever1; fylever1 = fy * lever1; fzlever1 = fz * lever1; f[i0][0] += fxlever0; //keep force sign for bond 0 f[i0][1] += fylever0; f[i0][2] += fzlever0; f[j0][0] += (fx - fxlever0); f[j0][1] += (fy - fylever0); f[j0][2] += (fz - fzlever0); f[i1][0] -= fxlever1; //flip force sign for bond 1 f[i1][1] -= fylever1; f[i1][2] -= fzlever1; f[j1][0] -= (fx - fxlever1); f[j1][1] -= (fy - fylever1); f[j1][2] -= (fz - fzlever1); // ************************************************* // if (eflag){ evdwl = 0.5 * a0[bptype][bptype] * cut[bptype][bptype] * wd * wd; } if (evflag){ ev_tally(i0,i1,nlocal,1,0.5*evdwl,0.0,0.5*fpair,dx,dy,dz); ev_tally(j0,j1,nlocal,1,0.5*evdwl,0.0,0.5*fpair,dx,dy,dz); } if (vflag_fdotr) virial_fdotr_compute(); } } } } } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairSRP::settings(int narg, char **arg) { if (narg < 3 || narg > 7) error->all(FLERR,"Illegal pair_style command"); if (atom->tag_enable == 0) error->all(FLERR,"Pair_style srp requires atom IDs"); cut_global = force->numeric(FLERR,arg[0]); // wildcard if (strcmp(arg[1],"*") == 0) btype = 0; else { btype = force->inumeric(FLERR,arg[1]); if ((btype > atom->nbondtypes) || (btype <= 0)) error->all(FLERR,"Illegal pair_style command"); } // settings midpoint = 0; min = 0; if (strcmp(arg[2],"min") == 0) min = 1; else if (strcmp(arg[2],"mid") == 0) midpoint = 1; else error->all(FLERR,"Illegal pair_style command"); int iarg = 3; // default exclude 1-2 // scaling for 1-2, etc not supported exclude = 1; // use last atom type by default for bond particles bptype = atom->ntypes; while (iarg < narg) { if (strcmp(arg[iarg],"exclude") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal pair srp command"); if (strcmp(arg[iarg+1],"yes") == 0) exclude = 1; if (strcmp(arg[iarg+1],"no") == 0){ if (min) error->all(FLERR,"Illegal exclude option in pair srp command"); exclude = 0; } iarg += 2; } else if (strcmp(arg[iarg],"bptype") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal pair srp command"); bptype = force->inumeric(FLERR,arg[iarg+1]); if ((bptype < 1) || (bptype > atom->ntypes)) error->all(FLERR,"Illegal bond particle type for srp"); iarg += 2; } else error->all(FLERR,"Illegal pair srp command"); } // reset cutoffs if explicitly set if (allocated) { int i,j; for (i = 1; i <= bptype; i++) for (j = i+1; j <= bptype; j++) if (setflag[i][j]) cut[i][j] = cut_global; } } /* ---------------------------------------------------------------------- set coeffs ------------------------------------------------------------------------- */ void PairSRP::coeff(int narg, char **arg) { if (narg < 3 || narg > 4) error->all(FLERR,"PairSRP: Incorrect args for pair coeff"); if (!allocated) allocate(); // set ij bond-bond cutoffs int ilo, ihi, jlo, jhi; - force->bounds(arg[0], bptype, ilo, ihi); - force->bounds(arg[1], bptype, jlo, jhi); + force->bounds(FLERR,arg[0], bptype, ilo, ihi); + force->bounds(FLERR,arg[1], bptype, jlo, jhi); double a0_one = force->numeric(FLERR,arg[2]); double cut_one = cut_global; if (narg == 4) cut_one = force->numeric(FLERR,arg[3]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { a0[i][j] = a0_one; cut[i][j] = cut_one; cutsq[i][j] = cut_one * cut_one; setflag[i][j] = 1; count++; } } if (count == 0) error->warning(FLERR,"PairSRP: No pair coefficients were set"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairSRP::init_style() { if (!force->newton_pair) error->all(FLERR,"PairSRP: Pair srp requires newton pair on"); // verify that fix SRP is still defined and has not been changed. int ifix = modify->find_fix(fix_id); if (f_srp != (FixSRP *)modify->fix[ifix]) error->all(FLERR,"Fix SRP has been changed unexpectedly"); if (comm->me == 0) { if (screen) fprintf(screen,"Using type %d for bond particles\n",bptype); if (logfile) fprintf(logfile,"Using type %d for bond particles\n",bptype); } // set bond and bond particle types in fix srp // bonds of this type will be represented by bond particles // if bond type is 0, then all bonds have bond particles // btype = bond type char c0[20]; char* arg0[2]; sprintf(c0, "%d", btype); arg0[0] = (char *) "btype"; arg0[1] = c0; f_srp->modify_params(2, arg0); // bptype = bond particle type sprintf(c0, "%d", bptype); arg0[0] = (char *) "bptype"; arg0[1] = c0; f_srp->modify_params(2, arg0); // bond particles do not contribute to energy or virial // bond particles do not belong to group all // but thermo normalization is by nall // therefore should turn off normalization int me; MPI_Comm_rank(world,&me); char *arg1[2]; arg1[0] = (char *) "norm"; arg1[1] = (char *) "no"; output->thermo->modify_params(2, arg1); if (me == 0) error->message(FLERR,"Thermo normalization turned off by pair srp"); neighbor->request(this,instance_me); } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairSRP::init_one(int i, int j) { if (setflag[i][j] == 0) error->all(FLERR,"PairSRP: All pair coeffs are not set"); cut[j][i] = cut[i][j]; a0[j][i] = a0[i][j]; return cut[i][j]; } /* ---------------------------------------------------------------------- find min distance for bonds i0/j0 and i1/j1 ------------------------------------------------------------------------- */ inline void PairSRP::getMinDist(double** &x, double &dx, double &dy, double &dz, double &ti, double &tj, int &i0, int &j0, int &i1, int &j1) { // move these outside the loop double diffx0, diffy0, diffz0, diffx1, diffy1, diffz1, dPx, dPy, dPz, RiRi, RiRj, RjRj; double denom, termx0, termy0, termz0, num0, termx1, termy1, termz1, num1; // compute midpt dist from 1st atom, 1st bond diffx0 = x[j0][0] - x[i0][0]; // x,y,z from bond 0 diffy0 = x[j0][1] - x[i0][1]; diffz0 = x[j0][2] - x[i0][2]; // compute midpt dist from 1st atom, 2nd bond diffx1 = x[j1][0] - x[i1][0]; diffy1 = x[j1][1] - x[i1][1]; diffz1 = x[j1][2] - x[i1][2]; // midpoint distance dPx = 0.5*(diffx0-diffx1) + x[i0][0]-x[i1][0]; dPy = 0.5*(diffy0-diffy1) + x[i0][1]-x[i1][1]; dPz = 0.5*(diffz0-diffz1) + x[i0][2]-x[i1][2]; // Ri^2 Rj^2 RiRi = diffx0*diffx0 + diffy0*diffy0 + diffz0*diffz0; RiRj = diffx0*diffx1 + diffy0*diffy1 + diffz0*diffz1; RjRj = diffx1*diffx1 + diffy1*diffy1 + diffz1*diffz1; denom = RiRj*RiRj - RiRi*RjRj; // handle case of parallel lines // reduce to midpt distance if (fabs(denom) < SMALL){ if(denom < 0) denom = -BIG; else denom = BIG; } // calc ti termx0 = RiRj*diffx1 - RjRj*diffx0; termy0 = RiRj*diffy1 - RjRj*diffy0; termz0 = RiRj*diffz1 - RjRj*diffz0; num0 = dPx*termx0 + dPy*termy0 + dPz*termz0; ti = num0 / denom; if (ti > 0.5) ti = 0.5; if (ti < -0.5) ti = -0.5; // calc tj termx1 = RiRj*diffx0 - RiRi*diffx1; termy1 = RiRj*diffy0 - RiRi*diffy1; termz1 = RiRj*diffz0 - RiRi*diffz1; num1 = dPx*termx1 + dPy*termy1 + dPz*termz1; tj = -num1/ denom; if (tj > 0.5) tj = 0.5; if (tj < -0.5) tj = -0.5; // min dist dx = dPx - ti*diffx0 + tj*diffx1; dy = dPy - ti*diffy0 + tj*diffy1; dz = dPz - ti*diffz0 + tj*diffz1; } /* -------------------------------------------------------- map global id of atoms in stored by each bond particle ------------------------------------------------------- */ inline void PairSRP::remapBonds(int &nall) { if(nall > maxcount){ memory->grow(segment, nall, 2, "pair:segment"); maxcount = nall; } // loop over all bond particles // each bond paricle holds two bond atoms // map global ids of bond atoms to local ids // might not be able to map both bond atoms of j, if j is outside neighcut // these are not on neighlist, so are not used int tmp; srp = f_srp->array_atom; for (int i = 0; i < nall; i++) { if(atom->type[i] == bptype){ // tmp is local id // tmp == -1 is ok tmp = atom->map((int)srp[i][0]); segment[i][0] = domain->closest_image(i,tmp); // repeat with other id tmp = atom->map((int)srp[i][1]); segment[i][1] = domain->closest_image(i,tmp); } } } /* -------------------------------------------------------- add exclusions for 1-2 neighs, if requested more complex exclusions or scaling probably not needed ------------------------------------------------------- */ inline void PairSRP::onetwoexclude(int* &ilist, int &inum, int* &jlist, int* &numneigh, int** &firstneigh) { int i0, i1, j0, j1; int i,j,ii,jj,jnum; // encode neighs with exclusions // only need 1-2 info for normal uses of srp // add 1-3, etc later if ever needed for (ii = 0; ii < inum; ii++) { i = ilist[ii]; jnum = numneigh[i]; // two atoms inside bond particle i0 = segment[i][0]; j0 = segment[i][1]; for (jj = 0; jj < jnum; jj++) { jlist = firstneigh[i]; j = jlist[jj]; j &= NEIGHMASK; //two atoms inside bond particle i1 = segment[j][0]; j1 = segment[j][1]; // check for a 1-2 neigh if(i0 == i1 || i0 == j1 || i1 == j0 || j0 == j1){ j |= ONETWOBIT; jlist[jj] = j; } } } } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void PairSRP::write_data(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) fprintf(fp,"%d %g\n",i,a0[i][i]); } /* ---------------------------------------------------------------------- proc 0 writes all pairs to data file ------------------------------------------------------------------------- */ void PairSRP::write_data_all(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) fprintf(fp,"%d %d %g %g\n",i,j,a0[i][j],cut[i][j]); } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairSRP::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(&a0[i][j],sizeof(double),1,fp); fwrite(&cut[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairSRP::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) { printf(" i %d j %d \n",i,j); fread(&a0[i][j],sizeof(double),1,fp); fread(&cut[i][j],sizeof(double),1,fp); } MPI_Bcast(&a0[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairSRP::write_restart_settings(FILE *fp) { fwrite(&cut_global,sizeof(double),1,fp); fwrite(&bptype,sizeof(int),1,fp); fwrite(&btype,sizeof(int),1,fp); fwrite(&min,sizeof(int),1,fp); fwrite(&midpoint,sizeof(int),1,fp); fwrite(&exclude,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairSRP::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&cut_global,sizeof(double),1,fp); fread(&bptype,sizeof(int),1,fp); fread(&btype,sizeof(int),1,fp); fread(&min,sizeof(int),1,fp); fread(&midpoint,sizeof(int),1,fp); fread(&exclude,sizeof(int),1,fp); } MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world); } diff --git a/src/USER-SMD/pair_smd_hertz.cpp b/src/USER-SMD/pair_smd_hertz.cpp index 0bcf2c8a3..3c7d7cffb 100644 --- a/src/USER-SMD/pair_smd_hertz.cpp +++ b/src/USER-SMD/pair_smd_hertz.cpp @@ -1,385 +1,385 @@ /* ---------------------------------------------------------------------- * * *** Smooth Mach Dynamics *** * * This file is part of the USER-SMD package for LAMMPS. * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. * * ----------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- 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 Parks (SNL) ------------------------------------------------------------------------- */ #include #include #include #include #include "pair_smd_hertz.h" #include "atom.h" #include "domain.h" #include "force.h" #include "update.h" #include "modify.h" #include "fix.h" #include "comm.h" #include "neighbor.h" #include "neigh_list.h" #include "neigh_request.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define SQRT2 1.414213562e0 /* ---------------------------------------------------------------------- */ PairHertz::PairHertz(LAMMPS *lmp) : Pair(lmp) { onerad_dynamic = onerad_frozen = maxrad_dynamic = maxrad_frozen = NULL; bulkmodulus = NULL; kn = NULL; scale = 1.0; } /* ---------------------------------------------------------------------- */ PairHertz::~PairHertz() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(bulkmodulus); memory->destroy(kn); delete[] onerad_dynamic; delete[] onerad_frozen; delete[] maxrad_dynamic; delete[] maxrad_frozen; } } /* ---------------------------------------------------------------------- */ void PairHertz::compute(int eflag, int vflag) { int i, j, ii, jj, inum, jnum, itype, jtype; double xtmp, ytmp, ztmp, delx, dely, delz; double rsq, r, evdwl, fpair; int *ilist, *jlist, *numneigh, **firstneigh; double rcut, r_geom, delta, ri, rj, dt_crit; double *rmass = atom->rmass; evdwl = 0.0; if (eflag || vflag) ev_setup(eflag, vflag); else evflag = vflag_fdotr = 0; double **f = atom->f; double **x = atom->x; double **x0 = atom->x0; int *type = atom->type; int nlocal = atom->nlocal; double *radius = atom->contact_radius; double *sph_radius = atom->radius; double rcutSq; double delx0, dely0, delz0, rSq0, sphCut; int newton_pair = force->newton_pair; int periodic = (domain->xperiodic || domain->yperiodic || domain->zperiodic); inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; stable_time_increment = 1.0e22; // 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]; ri = scale * radius[i]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; j &= NEIGHMASK; jtype = type[j]; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx * delx + dely * dely + delz * delz; rj = scale * radius[j]; rcut = ri + rj; rcutSq = rcut * rcut; if (rsq < rcutSq) { /* * self contact option: * if pair of particles was initially close enough to interact via a bulk continuum mechanism (e.g. SPH), exclude pair from contact forces. * this approach should work well if no updates of the reference configuration are performed. */ if (itype == jtype) { delx0 = x0[j][0] - x0[i][0]; dely0 = x0[j][1] - x0[i][1]; delz0 = x0[j][2] - x0[i][2]; if (periodic) { domain->minimum_image(delx0, dely0, delz0); } rSq0 = delx0 * delx0 + dely0 * dely0 + delz0 * delz0; // initial distance sphCut = sph_radius[i] + sph_radius[j]; if (rSq0 < sphCut * sphCut) { rcut = 0.5 * rcut; rcutSq = rcut * rcut; if (rsq > rcutSq) { continue; } } } r = sqrt(rsq); //printf("hertz interaction, r=%f, cut=%f, h=%f\n", r, rcut, sqrt(rSq0)); // Hertzian short-range forces delta = rcut - r; // overlap distance r_geom = ri * rj / rcut; //assuming poisson ratio = 1/4 for 3d fpair = 1.066666667e0 * bulkmodulus[itype][jtype] * delta * sqrt(delta * r_geom); // units: N evdwl = fpair * 0.4e0 * delta; // GCG 25 April: this expression conserves total energy dt_crit = 3.14 * sqrt(0.5 * (rmass[i] + rmass[j]) / (fpair / delta)); stable_time_increment = MIN(stable_time_increment, dt_crit); if (r > 2.0e-16) { fpair /= r; // divide by r and multiply with non-normalized distance vector } else { fpair = 0.0; } /* * contact viscosity -- needs to be done, see GRANULAR package for normal & shear damping * for now: no damping and thus no viscous energy deltaE */ if (evflag) { ev_tally(i, j, nlocal, newton_pair, evdwl, 0.0, fpair, delx, dely, delz); } 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; } } } } // double stable_time_increment_all = 0.0; // MPI_Allreduce(&stable_time_increment, &stable_time_increment_all, 1, MPI_DOUBLE, MPI_MIN, world); // if (comm->me == 0) { // printf("stable time step for pair smd/hertz is %f\n", stable_time_increment_all); // } } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairHertz::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(bulkmodulus, n + 1, n + 1, "pair:kspring"); memory->create(kn, n + 1, n + 1, "pair:kn"); memory->create(cutsq, n + 1, n + 1, "pair:cutsq"); // always needs to be allocated, even with granular neighborlist onerad_dynamic = new double[n + 1]; onerad_frozen = new double[n + 1]; maxrad_dynamic = new double[n + 1]; maxrad_frozen = new double[n + 1]; } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairHertz::settings(int narg, char **arg) { if (narg != 1) error->all(FLERR, "Illegal number of args for pair_style hertz"); scale = force->numeric(FLERR, arg[0]); if (comm->me == 0) { printf("\n>>========>>========>>========>>========>>========>>========>>========>>========\n"); printf("SMD/HERTZ CONTACT SETTINGS:\n"); printf("... effective contact radius is scaled by %f\n", scale); printf(">>========>>========>>========>>========>>========>>========>>========>>========\n"); } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairHertz::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); + force->bounds(FLERR,arg[0], atom->ntypes, ilo, ihi); + force->bounds(FLERR,arg[1], atom->ntypes, jlo, jhi); double bulkmodulus_one = atof(arg[2]); // set short-range force constant double kn_one = 0.0; if (domain->dimension == 3) { kn_one = (16. / 15.) * bulkmodulus_one; //assuming poisson ratio = 1/4 for 3d } else { kn_one = 0.251856195 * (2. / 3.) * bulkmodulus_one; //assuming poisson ratio = 1/3 for 2d } int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo, i); j <= jhi; j++) { bulkmodulus[i][j] = bulkmodulus_one; kn[i][j] = kn_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 PairHertz::init_one(int i, int j) { if (!allocated) allocate(); if (setflag[i][j] == 0) error->all(FLERR, "All pair coeffs are not set"); bulkmodulus[j][i] = bulkmodulus[i][j]; kn[j][i] = kn[i][j]; // cutoff = sum of max I,J radii for // dynamic/dynamic & dynamic/frozen interactions, but not frozen/frozen double cutoff = maxrad_dynamic[i] + maxrad_dynamic[j]; cutoff = MAX(cutoff, maxrad_frozen[i] + maxrad_dynamic[j]); cutoff = MAX(cutoff, maxrad_dynamic[i] + maxrad_frozen[j]); if (comm->me == 0) { printf("cutoff for pair smd/hertz = %f\n", cutoff); } return cutoff; } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairHertz::init_style() { int i; // error checks if (!atom->contact_radius_flag) error->all(FLERR, "Pair style smd/hertz requires atom style with contact_radius"); int irequest = neighbor->request(this); neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->gran = 1; // set maxrad_dynamic and maxrad_frozen for each type // include future Fix pour particles as dynamic for (i = 1; i <= atom->ntypes; i++) onerad_dynamic[i] = onerad_frozen[i] = 0.0; double *radius = atom->radius; int *type = atom->type; int nlocal = atom->nlocal; for (i = 0; i < nlocal; i++) { onerad_dynamic[type[i]] = MAX(onerad_dynamic[type[i]], radius[i]); } MPI_Allreduce(&onerad_dynamic[1], &maxrad_dynamic[1], atom->ntypes, MPI_DOUBLE, MPI_MAX, world); MPI_Allreduce(&onerad_frozen[1], &maxrad_frozen[1], atom->ntypes, MPI_DOUBLE, MPI_MAX, world); } /* ---------------------------------------------------------------------- neighbor callback to inform pair style of neighbor list to use optional granular history list ------------------------------------------------------------------------- */ void PairHertz::init_list(int id, NeighList *ptr) { if (id == 0) list = ptr; } /* ---------------------------------------------------------------------- memory usage of local atom-based arrays ------------------------------------------------------------------------- */ double PairHertz::memory_usage() { return 0.0; } void *PairHertz::extract(const char *str, int &i) { //printf("in PairTriSurf::extract\n"); if (strcmp(str, "smd/hertz/stable_time_increment_ptr") == 0) { return (void *) &stable_time_increment; } return NULL; } diff --git a/src/USER-SMD/pair_smd_triangulated_surface.cpp b/src/USER-SMD/pair_smd_triangulated_surface.cpp index f5db6acd8..8410f2ec0 100644 --- a/src/USER-SMD/pair_smd_triangulated_surface.cpp +++ b/src/USER-SMD/pair_smd_triangulated_surface.cpp @@ -1,846 +1,846 @@ /* ---------------------------------------------------------------------- * * *** Smooth Mach Dynamics *** * * This file is part of the USER-SMD package for LAMMPS. * Copyright (2014) Georg C. Ganzenmueller, georg.ganzenmueller@emi.fhg.de * Fraunhofer Ernst-Mach Institute for High-Speed Dynamics, EMI, * Eckerstrasse 4, D-79104 Freiburg i.Br, Germany. * * ----------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- 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 Parks (SNL) ------------------------------------------------------------------------- */ #include #include #include #include #include "pair_smd_triangulated_surface.h" #include "atom.h" #include "domain.h" #include "force.h" #include "update.h" #include "modify.h" #include "fix.h" #include "comm.h" #include "neighbor.h" #include "neigh_list.h" #include "neigh_request.h" #include "memory.h" #include "error.h" #include #include #include using namespace std; using namespace LAMMPS_NS; using namespace Eigen; #define SQRT2 1.414213562e0 /* ---------------------------------------------------------------------- */ PairTriSurf::PairTriSurf(LAMMPS *lmp) : Pair(lmp) { onerad_dynamic = onerad_frozen = maxrad_dynamic = maxrad_frozen = NULL; bulkmodulus = NULL; kn = NULL; scale = 1.0; } /* ---------------------------------------------------------------------- */ PairTriSurf::~PairTriSurf() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(bulkmodulus); memory->destroy(kn); delete[] onerad_dynamic; delete[] onerad_frozen; delete[] maxrad_dynamic; delete[] maxrad_frozen; } } /* ---------------------------------------------------------------------- */ void PairTriSurf::compute(int eflag, int vflag) { int i, j, ii, jj, inum, jnum, itype, jtype; double rsq, r, evdwl, fpair; int *ilist, *jlist, *numneigh, **firstneigh; double rcut, r_geom, delta, r_tri, r_particle, touch_distance, dt_crit; int tri, particle; Vector3d normal, x1, x2, x3, x4, x13, x23, x43, w, cp, x4cp, vnew, v_old; ; Vector3d xi, x_center, dx; Matrix2d C; Vector2d w2d, rhs; evdwl = 0.0; if (eflag || vflag) ev_setup(eflag, vflag); else evflag = vflag_fdotr = 0; tagint *mol = atom->molecule; double **f = atom->f; double **smd_data_9 = atom->smd_data_9; double **x = atom->x; double **x0 = atom->x0; double **v = atom->v; double *rmass = atom->rmass; int *type = atom->type; int nlocal = atom->nlocal; double *radius = atom->contact_radius; double rcutSq; Vector3d offset; int newton_pair = force->newton_pair; int periodic = (domain->xperiodic || domain->yperiodic || domain->zperiodic); inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; int max_neighs = 0; stable_time_increment = 1.0e22; // loop over neighbors of my atoms using a half neighbor list for (ii = 0; ii < inum; ii++) { i = ilist[ii]; itype = type[i]; jlist = firstneigh[i]; jnum = numneigh[i]; max_neighs = MAX(max_neighs, jnum); for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; j &= NEIGHMASK; jtype = type[j]; /* * decide which one of i, j is triangle and which is particle */ if ((mol[i] < 65535) && (mol[j] >= 65535)) { particle = i; tri = j; } else if ((mol[j] < 65535) && (mol[i] >= 65535)) { particle = j; tri = i; } else { error->one(FLERR, "unknown case"); } //x_center << x[tri][0], x[tri][1], x[tri][2]; // center of triangle x_center(0) = x[tri][0]; x_center(1) = x[tri][1]; x_center(2) = x[tri][2]; //x4 << x[particle][0], x[particle][1], x[particle][2]; x4(0) = x[particle][0]; x4(1) = x[particle][1]; x4(2) = x[particle][2]; dx = x_center - x4; // if (periodic) { domain->minimum_image(dx(0), dx(1), dx(2)); } rsq = dx.squaredNorm(); r_tri = scale * radius[tri]; r_particle = scale * radius[particle]; rcut = r_tri + r_particle; rcutSq = rcut * rcut; //printf("type i=%d, type j=%d, r=%f, ri=%f, rj=%f\n", itype, jtype, sqrt(rsq), ri, rj); if (rsq < rcutSq) { /* * gather triangle information */ normal(0) = x0[tri][0]; normal(1) = x0[tri][1]; normal(2) = x0[tri][2]; /* * distance check: is particle closer than its radius to the triangle plane? */ if (fabs(dx.dot(normal)) < radius[particle]) { /* * get other two triangle vertices */ x1(0) = smd_data_9[tri][0]; x1(1) = smd_data_9[tri][1]; x1(2) = smd_data_9[tri][2]; x2(0) = smd_data_9[tri][3]; x2(1) = smd_data_9[tri][4]; x2(2) = smd_data_9[tri][5]; x3(0) = smd_data_9[tri][6]; x3(1) = smd_data_9[tri][7]; x3(2) = smd_data_9[tri][8]; PointTriangleDistance(x4, x1, x2, x3, cp, r); /* * distance to closest point */ x4cp = x4 - cp; /* * flip normal to point in direction of x4cp */ if (x4cp.dot(normal) < 0.0) { normal *= -1.0; } /* * penalty force pushes particle away from triangle */ if (r < 1.0 * radius[particle]) { delta = radius[particle] - r; // overlap distance r_geom = radius[particle]; fpair = 1.066666667e0 * bulkmodulus[itype][jtype] * delta * sqrt(delta * r_geom); dt_crit = 3.14 * sqrt(rmass[particle] / (fpair / delta)); stable_time_increment = MIN(stable_time_increment, dt_crit); evdwl = r * fpair * 0.4e0 * delta; // GCG 25 April: this expression conserves total energy fpair /= (r + 1.0e-2 * radius[particle]); // divide by r + softening and multiply with non-normalized distance vector if (particle < nlocal) { f[particle][0] += x4cp(0) * fpair; f[particle][1] += x4cp(1) * fpair; f[particle][2] += x4cp(2) * fpair; } if (tri < nlocal) { f[tri][0] -= x4cp(0) * fpair; f[tri][1] -= x4cp(1) * fpair; f[tri][2] -= x4cp(2) * fpair; } if (evflag) { ev_tally(i, j, nlocal, newton_pair, evdwl, 0.0, fpair, x4cp(0), x4cp(1), x4cp(2)); } } /* * if particle comes too close to triangle, reflect its velocity and explicitely move it away */ touch_distance = 1.0 * radius[particle]; if (r < touch_distance) { /* * reflect velocity if it points toward triangle */ normal = x4cp / r; //v_old << v[particle][0], v[particle][1], v[particle][2]; v_old(0) = v[particle][0]; v_old(1) = v[particle][1]; v_old(2) = v[particle][2]; if (v_old.dot(normal) < 0.0) { //printf("flipping velocity\n"); vnew = 1.0 * (-2.0 * v_old.dot(normal) * normal + v_old); v[particle][0] = vnew(0); v[particle][1] = vnew(1); v[particle][2] = vnew(2); } //printf("moving particle on top of triangle\n"); x[particle][0] = cp(0) + touch_distance * normal(0); x[particle][1] = cp(1) + touch_distance * normal(1); x[particle][2] = cp(2) + touch_distance * normal(2); } } } } } // int max_neighs_all = 0; // MPI_Allreduce(&max_neighs, &max_neighs_all, 1, MPI_INT, MPI_MAX, world); // if (comm->me == 0) { // printf("max. neighs in tri pair is %d\n", max_neighs_all); // } // // double stable_time_increment_all = 0.0; // MPI_Allreduce(&stable_time_increment, &stable_time_increment_all, 1, MPI_DOUBLE, MPI_MIN, world); // if (comm->me == 0) { // printf("stable time step tri pair is %f\n", stable_time_increment_all); // } } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairTriSurf::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(bulkmodulus, n + 1, n + 1, "pair:kspring"); memory->create(kn, n + 1, n + 1, "pair:kn"); memory->create(cutsq, n + 1, n + 1, "pair:cutsq"); // always needs to be allocated, even with granular neighborlist onerad_dynamic = new double[n + 1]; onerad_frozen = new double[n + 1]; maxrad_dynamic = new double[n + 1]; maxrad_frozen = new double[n + 1]; } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairTriSurf::settings(int narg, char **arg) { if (narg != 1) error->all(FLERR, "Illegal number of args for pair_style smd/tri_surface"); scale = force->numeric(FLERR, arg[0]); if (comm->me == 0) { printf("\n>>========>>========>>========>>========>>========>>========>>========>>========\n"); printf("SMD/TRI_SURFACE CONTACT SETTINGS:\n"); printf("... effective contact radius is scaled by %f\n", scale); printf(">>========>>========>>========>>========>>========>>========>>========>>========\n"); } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairTriSurf::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); + force->bounds(FLERR,arg[0], atom->ntypes, ilo, ihi); + force->bounds(FLERR,arg[1], atom->ntypes, jlo, jhi); double bulkmodulus_one = atof(arg[2]); // set short-range force constant double kn_one = 0.0; if (domain->dimension == 3) { kn_one = (16. / 15.) * bulkmodulus_one; //assuming poisson ratio = 1/4 for 3d } else { kn_one = 0.251856195 * (2. / 3.) * bulkmodulus_one; //assuming poisson ratio = 1/3 for 2d } int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo, i); j <= jhi; j++) { bulkmodulus[i][j] = bulkmodulus_one; kn[i][j] = kn_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 PairTriSurf::init_one(int i, int j) { if (!allocated) allocate(); if (setflag[i][j] == 0) error->all(FLERR, "All pair coeffs are not set"); bulkmodulus[j][i] = bulkmodulus[i][j]; kn[j][i] = kn[i][j]; // cutoff = sum of max I,J radii for // dynamic/dynamic & dynamic/frozen interactions, but not frozen/frozen double cutoff = maxrad_dynamic[i] + maxrad_dynamic[j]; cutoff = MAX(cutoff, maxrad_frozen[i] + maxrad_dynamic[j]); cutoff = MAX(cutoff, maxrad_dynamic[i] + maxrad_frozen[j]); if (comm->me == 0) { printf("cutoff for pair smd/smd/tri_surface = %f\n", cutoff); } return cutoff; } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairTriSurf::init_style() { int i; // error checks if (!atom->contact_radius_flag) error->all(FLERR, "Pair style smd/smd/tri_surface requires atom style with contact_radius"); // old: half list int irequest = neighbor->request(this); neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->gran = 1; // need a full neighbor list // int irequest = neighbor->request(this); // neighbor->requests[irequest]->half = 0; // neighbor->requests[irequest]->full = 1; // set maxrad_dynamic and maxrad_frozen for each type // include future Fix pour particles as dynamic for (i = 1; i <= atom->ntypes; i++) onerad_dynamic[i] = onerad_frozen[i] = 0.0; double *radius = atom->radius; int *type = atom->type; int nlocal = atom->nlocal; for (i = 0; i < nlocal; i++) { onerad_dynamic[type[i]] = MAX(onerad_dynamic[type[i]], radius[i]); } MPI_Allreduce(&onerad_dynamic[1], &maxrad_dynamic[1], atom->ntypes, MPI_DOUBLE, MPI_MAX, world); MPI_Allreduce(&onerad_frozen[1], &maxrad_frozen[1], atom->ntypes, MPI_DOUBLE, MPI_MAX, world); } /* ---------------------------------------------------------------------- neighbor callback to inform pair style of neighbor list to use optional granular history list ------------------------------------------------------------------------- */ void PairTriSurf::init_list(int id, NeighList *ptr) { if (id == 0) list = ptr; } /* ---------------------------------------------------------------------- memory usage of local atom-based arrays ------------------------------------------------------------------------- */ double PairTriSurf::memory_usage() { return 0.0; } /* * distance between triangle and point */ /* function [dist,PP0] = pointTriangleDistance(TRI,P) % calculate distance between a point and a triangle in 3D % SYNTAX % dist = pointTriangleDistance(TRI,P) % [dist,PP0] = pointTriangleDistance(TRI,P) % % DESCRIPTION % Calculate the distance of a given point P from a triangle TRI. % Point P is a row vector of the form 1x3. The triangle is a matrix % formed by three rows of points TRI = [P1;P2;P3] each of size 1x3. % dist = pointTriangleDistance(TRI,P) returns the distance of the point P % to the triangle TRI. % [dist,PP0] = pointTriangleDistance(TRI,P) additionally returns the % closest point PP0 to P on the triangle TRI. % % Author: Gwendolyn Fischer % Release: 1.0 % Release date: 09/02/02 % Release: 1.1 Fixed Bug because of normalization % Release: 1.2 Fixed Bug because of typo in region 5 20101013 % Release: 1.3 Fixed Bug because of typo in region 2 20101014 % Possible extention could be a version tailored not to return the distance % and additionally the closest point, but instead return only the closest % point. Could lead to a small speed gain. % Example: % %% The Problem % P0 = [0.5 -0.3 0.5]; % % P1 = [0 -1 0]; % P2 = [1 0 0]; % P3 = [0 0 0]; % % vertices = [P1; P2; P3]; % faces = [1 2 3]; % % %% The Engine % [dist,PP0] = pointTriangleDistance([P1;P2;P3],P0); % % %% Visualization % [x,y,z] = sphere(20); % x = dist*x+P0(1); % y = dist*y+P0(2); % z = dist*z+P0(3); % % figure % hold all % patch('Vertices',vertices,'Faces',faces,'FaceColor','r','FaceAlpha',0.8); % plot3(P0(1),P0(2),P0(3),'b*'); % plot3(PP0(1),PP0(2),PP0(3),'*g') % surf(x,y,z,'FaceColor','b','FaceAlpha',0.3) % view(3) % The algorithm is based on % "David Eberly, 'Distance Between Point and Triangle in 3D', % Geometric Tools, LLC, (1999)" % http:\\www.geometrictools.com/Documentation/DistancePoint3Triangle3.pdf % % ^t % \ | % \reg2| % \ | % \ | % \ | % \| % *P2 % |\ % | \ % reg3 | \ reg1 % | \ % |reg0\ % | \ % | \ P1 % -------*-------*------->s % |P0 \ % reg4 | reg5 \ reg6 */ //void PairTriSurf::PointTriangleDistance(const Vector3d P, const Vector3d TRI1, const Vector3d TRI2, const Vector3d TRI3, // Vector3d &CP, double &dist) { // // Vector3d B, E0, E1, D; // double a, b, c, d, e, f; // double det, s, t, sqrDistance, tmp0, tmp1, numer, denom, invDet; // // // rewrite triangle in normal form // B = TRI1; // E0 = TRI2 - B; // E1 = TRI3 - B; // // D = B - P; // a = E0.dot(E0); // b = E0.dot(E1); // c = E1.dot(E1); // d = E0.dot(D); // e = E1.dot(D); // f = D.dot(D); // // det = a * c - b * b; // //% do we have to use abs here? // s = b * e - c * d; // t = b * d - a * e; // // //% Terible tree of conditionals to determine in which region of the diagram // //% shown above the projection of the point into the triangle-plane lies. // if ((s + t) <= det) { // if (s < 0) { // if (t < 0) { // // %region4 // if (d < 0) { // t = 0; // if (-d >= a) { // s = 1; // sqrDistance = a + 2 * d + f; // } else { // s = -d / a; // sqrDistance = d * s + f; // } // } else { // s = 0; // if (e >= 0) { // t = 0; // sqrDistance = f; // } else { // if (-e >= c) { // t = 1; // sqrDistance = c + 2 * e + f; // } else { // t = -e / c; // sqrDistance = e * t + f; // } // } // } // // end % of region 4 // } else { // // % region 3 // s = 0; // if (e >= 0) { // t = 0; // sqrDistance = f; // } else { // if (-e >= c) { // t = 1; // sqrDistance = c + 2 * e + f; // } else { // t = -e / c; // sqrDistance = e * t + f; // } // } // } // // end of region 3 // } else { // if (t < 0) { // //% region 5 // t = 0; // if (d >= 0) { // s = 0; // sqrDistance = f; // } else { // if (-d >= a) { // s = 1; // sqrDistance = a + 2 * d + f; // } else { // s = -d / a; // sqrDistance = d * s + f; // } // } // } else { // // region 0 // invDet = 1 / det; // s = s * invDet; // t = t * invDet; // sqrDistance = s * (a * s + b * t + 2 * d) + t * (b * s + c * t + 2 * e) + f; // } // } // } else { // if (s < 0) { // // % region 2 // tmp0 = b + d; // tmp1 = c + e; // if (tmp1 > tmp0) { //% minimum on edge s+t=1 // numer = tmp1 - tmp0; // denom = a - 2 * b + c; // if (numer >= denom) { // s = 1; // t = 0; // sqrDistance = a + 2 * d + f; // } else { // s = numer / denom; // t = 1 - s; // sqrDistance = s * (a * s + b * t + 2 * d) + t * (b * s + c * t + 2 * e) + f; // } // } else // // % minimum on edge s=0 // s = 0; // if (tmp1 <= 0) { // t = 1; // sqrDistance = c + 2 * e + f; // } else { // if (e >= 0) { // t = 0; // sqrDistance = f; // } else { // t = -e / c; // sqrDistance = e * t + f; // } // } // } //end % of region 2 // else { // if (t < 0) { // // %region6 // tmp0 = b + e; // tmp1 = a + d; // if (tmp1 > tmp0) { // numer = tmp1 - tmp0; // denom = a - 2 * b + c; // if (numer >= denom) { // t = 1; // s = 0; // sqrDistance = c + 2 * e + f; // } else { // t = numer / denom; // s = 1 - t; // sqrDistance = s * (a * s + b * t + 2 * d) + t * (b * s + c * t + 2 * e) + f; // } // } else { // t = 0; // if (tmp1 <= 0) { // s = 1; // sqrDistance = a + 2 * d + f; // } else { // if (d >= 0) { // s = 0; // sqrDistance = f; // } else { // s = -d / a; // sqrDistance = d * s + f; // } // } // } // % end region 6 // } else { // //% region 1 // numer = c + e - b - d; // if (numer <= 0) { // s = 0; // t = 1; // sqrDistance = c + 2 * e + f; // } else { // denom = a - 2 * b + c; // if (numer >= denom) { // s = 1; // t = 0; // sqrDistance = a + 2 * d + f; // } else { // s = numer / denom; // t = 1 - s; // sqrDistance = s * (a * s + b * t + 2 * d) + t * (b * s + c * t + 2 * e) + f; // } // } //% end of region 1 // } // } // } // // // % account for numerical round-off error // if (sqrDistance < 0) { // sqrDistance = 0; // } // // dist = sqrt(sqrDistance); // // // closest point // CP = B + s * E0 + t * E1; // //} /* * % The algorithm is based on % "David Eberly, 'Distance Between Point and Triangle in 3D', % Geometric Tools, LLC, (1999)" % http:\\www.geometrictools.com/Documentation/DistancePoint3Triangle3.pdf */ void PairTriSurf::PointTriangleDistance(const Vector3d sourcePosition, const Vector3d TRI0, const Vector3d TRI1, const Vector3d TRI2, Vector3d &CP, double &dist) { Vector3d edge0 = TRI1 - TRI0; Vector3d edge1 = TRI2 - TRI0; Vector3d v0 = TRI0 - sourcePosition; double a = edge0.dot(edge0); double b = edge0.dot(edge1); double c = edge1.dot(edge1); double d = edge0.dot(v0); double e = edge1.dot(v0); double det = a * c - b * b; double s = b * e - c * d; double t = b * d - a * e; if (s + t < det) { if (s < 0.f) { if (t < 0.f) { if (d < 0.f) { s = clamp(-d / a, 0.f, 1.f); t = 0.f; } else { s = 0.f; t = clamp(-e / c, 0.f, 1.f); } } else { s = 0.f; t = clamp(-e / c, 0.f, 1.f); } } else if (t < 0.f) { s = clamp(-d / a, 0.f, 1.f); t = 0.f; } else { float invDet = 1.f / det; s *= invDet; t *= invDet; } } else { if (s < 0.f) { float tmp0 = b + d; float tmp1 = c + e; if (tmp1 > tmp0) { float numer = tmp1 - tmp0; float denom = a - 2 * b + c; s = clamp(numer / denom, 0.f, 1.f); t = 1 - s; } else { t = clamp(-e / c, 0.f, 1.f); s = 0.f; } } else if (t < 0.f) { if (a + d > b + e) { float numer = c + e - b - d; float denom = a - 2 * b + c; s = clamp(numer / denom, 0.f, 1.f); t = 1 - s; } else { s = clamp(-e / c, 0.f, 1.f); t = 0.f; } } else { float numer = c + e - b - d; float denom = a - 2 * b + c; s = clamp(numer / denom, 0.f, 1.f); t = 1.f - s; } } CP = TRI0 + s * edge0 + t * edge1; dist = (CP - sourcePosition).norm(); } double PairTriSurf::clamp(const double a, const double min, const double max) { if (a < min) { return min; } else if (a > max) { return max; } else { return a; } } void *PairTriSurf::extract(const char *str, int &i) { //printf("in PairTriSurf::extract\n"); if (strcmp(str, "smd/tri_surface/stable_time_increment_ptr") == 0) { return (void *) &stable_time_increment; } return NULL; } diff --git a/src/USER-SPH/pair_sph_heatconduction.cpp b/src/USER-SPH/pair_sph_heatconduction.cpp index 0b3716658..02e667e43 100644 --- a/src/USER-SPH/pair_sph_heatconduction.cpp +++ b/src/USER-SPH/pair_sph_heatconduction.cpp @@ -1,219 +1,219 @@ /* ---------------------------------------------------------------------- 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 #include #include "pair_sph_heatconduction.h" #include "atom.h" #include "force.h" #include "comm.h" #include "memory.h" #include "error.h" #include "neigh_list.h" #include "domain.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ PairSPHHeatConduction::PairSPHHeatConduction(LAMMPS *lmp) : Pair(lmp) { restartinfo = 0; } /* ---------------------------------------------------------------------- */ PairSPHHeatConduction::~PairSPHHeatConduction() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut); memory->destroy(alpha); } } /* ---------------------------------------------------------------------- */ void PairSPHHeatConduction::compute(int eflag, int vflag) { int i, j, ii, jj, inum, jnum, itype, jtype; double xtmp, ytmp, ztmp, delx, dely, delz; int *ilist, *jlist, *numneigh, **firstneigh; double imass, jmass, h, ih, ihsq; double rsq, wfd, D, deltaE; if (eflag || vflag) ev_setup(eflag, vflag); else evflag = vflag_fdotr = 0; double **x = atom->x; double *e = atom->e; double *de = atom->de; double *mass = atom->mass; double *rho = atom->rho; 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 and do heat diffusion for (ii = 0; ii < inum; ii++) { i = ilist[ii]; itype = type[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; jlist = firstneigh[i]; jnum = numneigh[i]; imass = mass[itype]; 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]; jmass = mass[jtype]; if (rsq < cutsq[itype][jtype]) { h = cut[itype][jtype]; ih = 1.0 / h; ihsq = ih * ih; // kernel function wfd = h - sqrt(rsq); if (domain->dimension == 3) { // Lucy Kernel, 3d // Note that wfd, the derivative of the weight function with respect to r, // is lacking a factor of r. // The missing factor of r is recovered by // deltaE, which is missing a factor of 1/r wfd = -25.066903536973515383e0 * wfd * wfd * ihsq * ihsq * ihsq * ih; } else { // Lucy Kernel, 2d wfd = -19.098593171027440292e0 * wfd * wfd * ihsq * ihsq * ihsq; } jmass = mass[jtype]; D = alpha[itype][jtype]; // diffusion coefficient deltaE = 2.0 * imass * jmass / (imass+jmass); deltaE *= (rho[i] + rho[j]) / (rho[i] * rho[j]); deltaE *= D * (e[i] - e[j]) * wfd; de[i] += deltaE; if (newton_pair || j < nlocal) { de[j] -= deltaE; } } } } } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairSPHHeatConduction::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(alpha, n + 1, n + 1, "pair:alpha"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairSPHHeatConduction::settings(int narg, char **arg) { if (narg != 0) error->all(FLERR, "Illegal number of setting arguments for pair_style sph/heatconduction"); } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairSPHHeatConduction::coeff(int narg, char **arg) { if (narg != 4) error->all(FLERR,"Incorrect number of args for pair_style sph/heatconduction 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); + force->bounds(FLERR,arg[0], atom->ntypes, ilo, ihi); + force->bounds(FLERR,arg[1], atom->ntypes, jlo, jhi); double alpha_one = force->numeric(FLERR,arg[2]); double cut_one = force->numeric(FLERR,arg[3]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { //printf("setting cut[%d][%d] = %f\n", i, j, cut_one); cut[i][j] = cut_one; alpha[i][j] = alpha_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 PairSPHHeatConduction::init_one(int i, int j) { if (setflag[i][j] == 0) { error->all(FLERR,"All pair sph/heatconduction coeffs are not set"); } cut[j][i] = cut[i][j]; alpha[j][i] = alpha[i][j]; return cut[i][j]; } /* ---------------------------------------------------------------------- */ double PairSPHHeatConduction::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { fforce = 0.0; return 0.0; } diff --git a/src/USER-SPH/pair_sph_idealgas.cpp b/src/USER-SPH/pair_sph_idealgas.cpp index caea8eb3e..2ba0d9bfb 100644 --- a/src/USER-SPH/pair_sph_idealgas.cpp +++ b/src/USER-SPH/pair_sph_idealgas.cpp @@ -1,260 +1,260 @@ /* ---------------------------------------------------------------------- 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 #include #include "pair_sph_idealgas.h" #include "atom.h" #include "force.h" #include "comm.h" #include "neigh_list.h" #include "memory.h" #include "error.h" #include "domain.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ PairSPHIdealGas::PairSPHIdealGas(LAMMPS *lmp) : Pair(lmp) { restartinfo = 0; } /* ---------------------------------------------------------------------- */ PairSPHIdealGas::~PairSPHIdealGas() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut); memory->destroy(viscosity); } } /* ---------------------------------------------------------------------- */ void PairSPHIdealGas::compute(int eflag, int vflag) { int i, j, ii, jj, inum, jnum, itype, jtype; double xtmp, ytmp, ztmp, delx, dely, delz, fpair; int *ilist, *jlist, *numneigh, **firstneigh; double vxtmp, vytmp, vztmp, imass, jmass, fi, fj, fvisc, h, ih, ihsq; double rsq, wfd, delVdotDelR, mu, deltaE, ci, cj; if (eflag || vflag) ev_setup(eflag, vflag); else evflag = vflag_fdotr = 0; double **v = atom->vest; double **x = atom->x; double **f = atom->f; double *rho = atom->rho; double *mass = atom->mass; double *de = atom->de; double *e = atom->e; double *drho = atom->drho; 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]; vxtmp = v[i][0]; vytmp = v[i][1]; vztmp = v[i][2]; itype = type[i]; jlist = firstneigh[i]; jnum = numneigh[i]; imass = mass[itype]; fi = 0.4 * e[i] / imass / rho[i]; // ideal gas EOS; this expression is fi = pressure / rho^2 ci = sqrt(0.4*e[i]/imass); // speed of sound with heat capacity ratio gamma=1.4 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]; jmass = mass[jtype]; if (rsq < cutsq[itype][jtype]) { h = cut[itype][jtype]; ih = 1. / h; ihsq = ih * ih; wfd = h - sqrt(rsq); if (domain->dimension == 3) { // Lucy Kernel, 3d // Note that wfd, the derivative of the weight function with respect to r, // is lacking a factor of r. // The missing factor of r is recovered by // (1) using delV . delX instead of delV . (delX/r) and // (2) using f[i][0] += delx * fpair instead of f[i][0] += (delx/r) * fpair wfd = -25.066903536973515383e0 * wfd * wfd * ihsq * ihsq * ihsq * ih; } else { // Lucy Kernel, 2d wfd = -19.098593171027440292e0 * wfd * wfd * ihsq * ihsq * ihsq; } fj = 0.4 * e[j] / jmass / rho[j]; // dot product of velocity delta and distance vector delVdotDelR = delx * (vxtmp - v[j][0]) + dely * (vytmp - v[j][1]) + delz * (vztmp - v[j][2]); // artificial viscosity (Monaghan 1992) if (delVdotDelR < 0.) { cj = sqrt(0.4*e[j]/jmass); mu = h * delVdotDelR / (rsq + 0.01 * h * h); fvisc = -viscosity[itype][jtype] * (ci + cj) * mu / (rho[i] + rho[j]); } else { fvisc = 0.; } // total pair force & thermal energy increment fpair = -imass * jmass * (fi + fj + fvisc) * wfd; deltaE = -0.5 * fpair * delVdotDelR; f[i][0] += delx * fpair; f[i][1] += dely * fpair; f[i][2] += delz * fpair; // and change in density drho[i] += jmass * delVdotDelR * wfd; // change in thermal energy de[i] += deltaE; if (newton_pair || j < nlocal) { f[j][0] -= delx * fpair; f[j][1] -= dely * fpair; f[j][2] -= delz * fpair; de[j] += deltaE; drho[j] += imass * delVdotDelR * wfd; } if (evflag) ev_tally(i, j, nlocal, newton_pair, 0.0, 0.0, fpair, delx, dely, delz); if (evflag) ev_tally(i, j, nlocal, newton_pair, 0.0, 0.0, fpair, delx, dely, delz); } } } if (vflag_fdotr) virial_fdotr_compute(); } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairSPHIdealGas::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(viscosity, n + 1, n + 1, "pair:viscosity"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairSPHIdealGas::settings(int narg, char **arg) { if (narg != 0) error->all(FLERR, "Illegal number of setting arguments for pair_style sph/idealgas"); } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairSPHIdealGas::coeff(int narg, char **arg) { if (narg != 4) error->all(FLERR,"Incorrect number of args for pair_style sph/idealgas 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); + force->bounds(FLERR,arg[0], atom->ntypes, ilo, ihi); + force->bounds(FLERR,arg[1], atom->ntypes, jlo, jhi); double viscosity_one = force->numeric(FLERR,arg[2]); double cut_one = force->numeric(FLERR,arg[3]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { viscosity[i][j] = viscosity_one; //printf("setting cut[%d][%d] = %f\n", i, j, cut_one); cut[i][j] = cut_one; setflag[i][j] = 1; count++; } } if (count == 0) error->all(FLERR,"Incorrect args for pair sph/idealgas coefficients"); } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairSPHIdealGas::init_one(int i, int j) { if (setflag[i][j] == 0) { error->all(FLERR,"All pair sph/idealgas coeffs are not set"); } cut[j][i] = cut[i][j]; return cut[i][j]; } /* ---------------------------------------------------------------------- */ double PairSPHIdealGas::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { fforce = 0.0; return 0.0; } diff --git a/src/USER-SPH/pair_sph_lj.cpp b/src/USER-SPH/pair_sph_lj.cpp index f0f3e3df3..98752ac12 100644 --- a/src/USER-SPH/pair_sph_lj.cpp +++ b/src/USER-SPH/pair_sph_lj.cpp @@ -1,366 +1,366 @@ /* ---------------------------------------------------------------------- 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 #include #include "pair_sph_lj.h" #include "atom.h" #include "force.h" #include "comm.h" #include "neigh_list.h" #include "memory.h" #include "error.h" #include "domain.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ PairSPHLJ::PairSPHLJ(LAMMPS *lmp) : Pair(lmp) { restartinfo = 0; } /* ---------------------------------------------------------------------- */ PairSPHLJ::~PairSPHLJ() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut); memory->destroy(viscosity); } } /* ---------------------------------------------------------------------- */ void PairSPHLJ::compute(int eflag, int vflag) { int i, j, ii, jj, inum, jnum, itype, jtype; double xtmp, ytmp, ztmp, delx, dely, delz, fpair; int *ilist, *jlist, *numneigh, **firstneigh; double vxtmp, vytmp, vztmp, imass, jmass, fi, fj, fvisc, h, ih, ihsq, ihcub; double rsq, wfd, delVdotDelR, mu, deltaE, ci, cj, lrc; if (eflag || vflag) ev_setup(eflag, vflag); else evflag = vflag_fdotr = 0; double **v = atom->vest; double **x = atom->x; double **f = atom->f; double *rho = atom->rho; double *mass = atom->mass; double *de = atom->de; double *e = atom->e; double *cv = atom->cv; double *drho = atom->drho; 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]; vxtmp = v[i][0]; vytmp = v[i][1]; vztmp = v[i][2]; itype = type[i]; jlist = firstneigh[i]; jnum = numneigh[i]; imass = mass[itype]; // compute pressure of particle i with LJ EOS LJEOS2(rho[i], e[i], cv[i], &fi, &ci); fi /= (rho[i] * rho[i]); //printf("fi = %f\n", fi); 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]; jmass = mass[jtype]; if (rsq < cutsq[itype][jtype]) { h = cut[itype][jtype]; ih = 1.0 / h; ihsq = ih * ih; ihcub = ihsq * ih; wfd = h - sqrt(rsq); if (domain->dimension == 3) { // Lucy Kernel, 3d // Note that wfd, the derivative of the weight function with respect to r, // is lacking a factor of r. // The missing factor of r is recovered by // (1) using delV . delX instead of delV . (delX/r) and // (2) using f[i][0] += delx * fpair instead of f[i][0] += (delx/r) * fpair wfd = -25.066903536973515383e0 * wfd * wfd * ihsq * ihsq * ihsq * ih; } else { // Lucy Kernel, 2d wfd = -19.098593171027440292e0 * wfd * wfd * ihsq * ihsq * ihsq; } // function call to LJ EOS LJEOS2(rho[j], e[j], cv[j], &fj, &cj); fj /= (rho[j] * rho[j]); // apply long-range correction to model a LJ fluid with cutoff // this implies that the modelled LJ fluid has cutoff == SPH cutoff lrc = - 11.1701 * (ihcub * ihcub * ihcub - 1.5 * ihcub); fi += lrc; fj += lrc; // dot product of velocity delta and distance vector delVdotDelR = delx * (vxtmp - v[j][0]) + dely * (vytmp - v[j][1]) + delz * (vztmp - v[j][2]); // artificial viscosity (Monaghan 1992) if (delVdotDelR < 0.) { mu = h * delVdotDelR / (rsq + 0.01 * h * h); fvisc = -viscosity[itype][jtype] * (ci + cj) * mu / (rho[i] + rho[j]); } else { fvisc = 0.; } // total pair force & thermal energy increment fpair = -imass * jmass * (fi + fj + fvisc) * wfd; deltaE = -0.5 * fpair * delVdotDelR; f[i][0] += delx * fpair; f[i][1] += dely * fpair; f[i][2] += delz * fpair; // and change in density drho[i] += jmass * delVdotDelR * wfd; // change in thermal energy de[i] += deltaE; if (newton_pair || j < nlocal) { f[j][0] -= delx * fpair; f[j][1] -= dely * fpair; f[j][2] -= delz * fpair; de[j] += deltaE; drho[j] += imass * delVdotDelR * wfd; } if (evflag) ev_tally(i, j, nlocal, newton_pair, 0.0, 0.0, fpair, delx, dely, delz); } } } if (vflag_fdotr) virial_fdotr_compute(); } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairSPHLJ::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(viscosity, n + 1, n + 1, "pair:viscosity"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairSPHLJ::settings(int narg, char **arg) { if (narg != 0) error->all(FLERR, "Illegal number of setting arguments for pair_style sph/lj"); } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairSPHLJ::coeff(int narg, char **arg) { if (narg != 4) error->all(FLERR, "Incorrect args for pair_style sph/lj 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); + force->bounds(FLERR,arg[0], atom->ntypes, ilo, ihi); + force->bounds(FLERR,arg[1], atom->ntypes, jlo, jhi); double viscosity_one = force->numeric(FLERR,arg[2]); double cut_one = force->numeric(FLERR,arg[3]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { viscosity[i][j] = viscosity_one; printf("setting cut[%d][%d] = %f\n", i, j, cut_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 PairSPHLJ::init_one(int i, int j) { if (setflag[i][j] == 0) { error->all(FLERR,"All pair sph/lj coeffs are not set"); } cut[j][i] = cut[i][j]; viscosity[j][i] = viscosity[i][j]; return cut[i][j]; } /* ---------------------------------------------------------------------- */ double PairSPHLJ::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { fforce = 0.0; return 0.0; } /*double PairSPHLJ::LJEOS2(double rho, double e, double cv) { double T = e / cv; if (T < 1.e-2) T = 1.e-2; //printf("%f %f\n", T, rho); double iT = 0.1e1 / T; //double itpow1_4 = exp(0.25 * log(iT)); //pow(iT, 0.1e1 / 0.4e1); double itpow1_4 = pow(iT, 0.1e1 / 0.4e1); double x = rho * itpow1_4; double xsq = x * x; double xpow3 = xsq * x; double xpow4 = xsq * xsq; double xpow9 = xpow3 * xpow3 * xpow3; return (0.1e1 + rho * (0.3629e1 + 0.7264e1 * x + 0.104925e2 * xsq + 0.11460e2 * xpow3 + 0.21760e1 * xpow9 - itpow1_4 * itpow1_4 * (0.5369e1 + 0.13160e2 * x + 0.18525e2 * xsq - 0.17076e2 * xpow3 + 0.9320e1 * xpow4) + iT * (-0.3492e1 + 0.18698e2 * x - 0.35505e2 * xsq + 0.31816e2 * xpow3 - 0.11195e2 * xpow4)) * itpow1_4) * rho * T; }*/ /* --------------------------------------------------------------------------------------------- */ /* Lennard-Jones EOS, Francis H. Ree "Analytic representation of thermodynamic data for the Lennard‐Jones fluid", Journal of Chemical Physics 73 pp. 5401-5403 (1980) */ void PairSPHLJ::LJEOS2(double rho, double e, double cv, double *p, double *c) { double T = e/cv; double beta = 1.0 / T; double beta_sqrt = sqrt(beta); double x = rho * sqrt(beta_sqrt); double xsq = x * x; double xpow3 = xsq * x; double xpow4 = xsq * xsq; /* differential of Helmholtz free energy w.r.t. x */ double diff_A_NkT = 3.629 + 7.264*x - beta*(3.492 - 18.698*x + 35.505*xsq - 31.816*xpow3 + 11.195*xpow4) - beta_sqrt*(5.369 + 13.16*x + 18.525*xsq - 17.076*xpow3 + 9.32*xpow4) + 10.4925*xsq + 11.46*xpow3 + 2.176*xpow4*xpow4*x; /* differential of Helmholtz free energy w.r.t. x^2 */ double d2A_dx2 = 7.264 + 20.985*x \ + beta*(18.698 - 71.01*x + 95.448*xsq - 44.78*xpow3)\ - beta_sqrt*(13.16 + 37.05*x - 51.228*xsq + 37.28*xpow3)\ + 34.38*xsq + 19.584*xpow4*xpow4; // p = rho k T * (1 + rho * d(A/(NkT))/drho) // dx/drho = rho/x *p = rho * T * (1.0 + diff_A_NkT * x); // pressure double csq = T * (1.0 + 2.0 * diff_A_NkT * x + d2A_dx2 * x * x); // soundspeed squared if (csq > 0.0) { *c = sqrt(csq); // soundspeed } else { *c = 0.0; } } /* ------------------------------------------------------------------------------ */ /* Jirí Kolafa, Ivo Nezbeda * "The Lennard-Jones fluid: an accurate analytic and theoretically-based equation of state", * Fluid Phase Equilibria 100 pp. 1-34 (1994) */ /*double PairSPHLJ::LJEOS2(double rho, double e, double cv) { double T = e / cv; double sT = sqrt(T); double isT = 1.0 / sT; double dC = -0.063920968 * log(T) + 0.011117524 / T - 0.076383859 / sT + 1.080142248 + 0.000693129 * sT; double eta = 3.141592654 / 6. * rho * (dC * dC * dC); double zHS = (1 + eta * (1 + eta * (1 - eta / 1.5 * (1 + eta)))) / ((1. - eta) * (1. - eta) * (1. - eta)); double BC = (((((-0.58544978 * isT + 0.43102052) * isT + .87361369) * isT - 4.13749995) * isT + 2.90616279) * isT - 7.02181962) / T + 0.02459877; double gammaBH = 1.92907278; double sum = ((2.01546797 * 2 + rho * ((-28.17881636) * 3 + rho * (28.28313847 * 4 + rho * (-10.42402873) * 5))) + (-19.58371655 * 2 + rho * (+75.62340289 * 3 + rho * ((-120.70586598) * 4 + rho * (+93.92740328 * 5 + rho * (-27.37737354) * 6)))) / sqrt(T) + ((29.34470520 * 2 + rho * ((-112.35356937) * 3 + rho * (+170.64908980 * 4 + rho * ((-123.06669187) * 5 + rho * 34.42288969 * 6)))) + ((-13.37031968) * 2 + rho * (65.38059570 * 3 + rho * ((-115.09233113) * 4 + rho * (88.91973082 * 5 + rho * (-25.62099890) * 6)))) / T) / T) * rho * rho; return ((zHS + BC / exp(gammaBH * rho * rho) * rho * (1 - 2 * gammaBH * rho * rho)) * T + sum) * rho; } */ diff --git a/src/USER-SPH/pair_sph_rhosum.cpp b/src/USER-SPH/pair_sph_rhosum.cpp index 4b7b028ad..4bff0ec27 100644 --- a/src/USER-SPH/pair_sph_rhosum.cpp +++ b/src/USER-SPH/pair_sph_rhosum.cpp @@ -1,313 +1,313 @@ /* ---------------------------------------------------------------------- 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 #include #include "pair_sph_rhosum.h" #include "atom.h" #include "force.h" #include "comm.h" #include "neigh_list.h" #include "neigh_request.h" #include "memory.h" #include "error.h" #include "neighbor.h" #include "update.h" #include "domain.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ PairSPHRhoSum::PairSPHRhoSum(LAMMPS *lmp) : Pair(lmp) { restartinfo = 0; // set comm size needed by this Pair comm_forward = 1; first = 1; } /* ---------------------------------------------------------------------- */ PairSPHRhoSum::~PairSPHRhoSum() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut); } } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairSPHRhoSum::init_style() { // need a full neighbor list int irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->full = 1; } /* ---------------------------------------------------------------------- */ void PairSPHRhoSum::compute(int eflag, int vflag) { int i, j, ii, jj, jnum, itype, jtype; double xtmp, ytmp, ztmp, delx, dely, delz; double rsq, imass, h, ih, ihsq; int *jlist; double wf; // neighbor list variables int inum, *ilist, *numneigh, **firstneigh; if (eflag || vflag) ev_setup(eflag, vflag); else evflag = vflag_fdotr = 0; double **x = atom->x; double *rho = atom->rho; int *type = atom->type; double *mass = atom->mass; // check consistency of pair coefficients if (first) { for (i = 1; i <= atom->ntypes; i++) { for (j = 1; i <= atom->ntypes; i++) { if (cutsq[i][j] > 0.0) { if (!setflag[i][i] || !setflag[j][j]) { if (comm->me == 0) { printf( "SPH particle types %d and %d interact, but not all of their single particle properties are set.\n", i, j); } } } } } first = 0; } inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // recompute density // we use a full neighborlist here if (nstep != 0) { if ((update->ntimestep % nstep) == 0) { // initialize density with self-contribution, for (ii = 0; ii < inum; ii++) { i = ilist[ii]; itype = type[i]; imass = mass[itype]; h = cut[itype][itype]; if (domain->dimension == 3) { /* // Lucy kernel, 3d wf = 2.0889086280811262819e0 / (h * h * h); */ // quadric kernel, 3d wf = 2.1541870227086614782 / (h * h * h); } else { /* // Lucy kernel, 2d wf = 1.5915494309189533576e0 / (h * h); */ // quadric kernel, 2d wf = 1.5915494309189533576e0 / (h * h); } rho[i] = imass * wf; } // add density at each atom via kernel function overlap 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; jtype = type[j]; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx * delx + dely * dely + delz * delz; if (rsq < cutsq[itype][jtype]) { h = cut[itype][jtype]; ih = 1.0 / h; ihsq = ih * ih; if (domain->dimension == 3) { /* // Lucy kernel, 3d r = sqrt(rsq); wf = (h - r) * ihsq; wf = 2.0889086280811262819e0 * (h + 3. * r) * wf * wf * wf * ih; */ // quadric kernel, 3d wf = 1.0 - rsq * ihsq; wf = wf * wf; wf = wf * wf; wf = 2.1541870227086614782e0 * wf * ihsq * ih; } else { // Lucy kernel, 2d //r = sqrt(rsq); //wf = (h - r) * ihsq; //wf = 1.5915494309189533576e0 * (h + 3. * r) * wf * wf * wf; // quadric kernel, 2d wf = 1.0 - rsq * ihsq; wf = wf * wf; wf = wf * wf; wf = 1.5915494309189533576e0 * wf * ihsq; } rho[i] += mass[jtype] * wf; } } } } } // communicate densities comm->forward_comm_pair(this); } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairSPHRhoSum::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"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairSPHRhoSum::settings(int narg, char **arg) { if (narg != 1) error->all(FLERR, "Illegal number of setting arguments for pair_style sph/rhosum"); nstep = force->inumeric(FLERR,arg[0]); } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairSPHRhoSum::coeff(int narg, char **arg) { if (narg != 3) error->all(FLERR,"Incorrect number of args for sph/rhosum 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); + force->bounds(FLERR,arg[0], atom->ntypes, ilo, ihi); + force->bounds(FLERR,arg[1], atom->ntypes, jlo, jhi); double cut_one = force->numeric(FLERR,arg[2]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { //printf("setting cut[%d][%d] = %f\n", i, j, cut_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 PairSPHRhoSum::init_one(int i, int j) { if (setflag[i][j] == 0) { error->all(FLERR,"All pair sph/rhosum coeffs are not set"); } cut[j][i] = cut[i][j]; return cut[i][j]; } /* ---------------------------------------------------------------------- */ double PairSPHRhoSum::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { fforce = 0.0; return 0.0; } /* ---------------------------------------------------------------------- */ int PairSPHRhoSum::pack_forward_comm(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i, j, m; double *rho = atom->rho; m = 0; for (i = 0; i < n; i++) { j = list[i]; buf[m++] = rho[j]; } return m; } /* ---------------------------------------------------------------------- */ void PairSPHRhoSum::unpack_forward_comm(int n, int first, double *buf) { int i, m, last; double *rho = atom->rho; m = 0; last = first + n; for (i = first; i < last; i++) rho[i] = buf[m++]; } diff --git a/src/USER-SPH/pair_sph_taitwater.cpp b/src/USER-SPH/pair_sph_taitwater.cpp index 846ec1189..b1887c616 100644 --- a/src/USER-SPH/pair_sph_taitwater.cpp +++ b/src/USER-SPH/pair_sph_taitwater.cpp @@ -1,301 +1,301 @@ /* ---------------------------------------------------------------------- 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 #include #include "pair_sph_taitwater.h" #include "atom.h" #include "force.h" #include "comm.h" #include "neigh_list.h" #include "memory.h" #include "error.h" #include "domain.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ PairSPHTaitwater::PairSPHTaitwater(LAMMPS *lmp) : Pair(lmp) { restartinfo = 0; first = 1; } /* ---------------------------------------------------------------------- */ PairSPHTaitwater::~PairSPHTaitwater() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut); memory->destroy(rho0); memory->destroy(soundspeed); memory->destroy(B); memory->destroy(viscosity); } } /* ---------------------------------------------------------------------- */ void PairSPHTaitwater::compute(int eflag, int vflag) { int i, j, ii, jj, inum, jnum, itype, jtype; double xtmp, ytmp, ztmp, delx, dely, delz, fpair; int *ilist, *jlist, *numneigh, **firstneigh; double vxtmp, vytmp, vztmp, imass, jmass, fi, fj, fvisc, h, ih, ihsq; double rsq, tmp, wfd, delVdotDelR, mu, deltaE; if (eflag || vflag) ev_setup(eflag, vflag); else evflag = vflag_fdotr = 0; double **v = atom->vest; double **x = atom->x; double **f = atom->f; double *rho = atom->rho; double *mass = atom->mass; double *de = atom->de; double *drho = atom->drho; int *type = atom->type; int nlocal = atom->nlocal; int newton_pair = force->newton_pair; // check consistency of pair coefficients if (first) { for (i = 1; i <= atom->ntypes; i++) { for (j = 1; i <= atom->ntypes; i++) { if (cutsq[i][j] > 1.e-32) { if (!setflag[i][i] || !setflag[j][j]) { if (comm->me == 0) { printf( "SPH particle types %d and %d interact with cutoff=%g, but not all of their single particle properties are set.\n", i, j, sqrt(cutsq[i][j])); } } } } } first = 0; } 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]; vxtmp = v[i][0]; vytmp = v[i][1]; vztmp = v[i][2]; itype = type[i]; jlist = firstneigh[i]; jnum = numneigh[i]; imass = mass[itype]; // compute pressure of atom i with Tait EOS tmp = rho[i] / rho0[itype]; fi = tmp * tmp * tmp; fi = B[itype] * (fi * fi * tmp - 1.0) / (rho[i] * rho[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]; jmass = mass[jtype]; if (rsq < cutsq[itype][jtype]) { h = cut[itype][jtype]; ih = 1.0 / h; ihsq = ih * ih; wfd = h - sqrt(rsq); if (domain->dimension == 3) { // Lucy Kernel, 3d // Note that wfd, the derivative of the weight function with respect to r, // is lacking a factor of r. // The missing factor of r is recovered by // (1) using delV . delX instead of delV . (delX/r) and // (2) using f[i][0] += delx * fpair instead of f[i][0] += (delx/r) * fpair wfd = -25.066903536973515383e0 * wfd * wfd * ihsq * ihsq * ihsq * ih; } else { // Lucy Kernel, 2d wfd = -19.098593171027440292e0 * wfd * wfd * ihsq * ihsq * ihsq; } // compute pressure of atom j with Tait EOS tmp = rho[j] / rho0[jtype]; fj = tmp * tmp * tmp; fj = B[jtype] * (fj * fj * tmp - 1.0) / (rho[j] * rho[j]); // dot product of velocity delta and distance vector delVdotDelR = delx * (vxtmp - v[j][0]) + dely * (vytmp - v[j][1]) + delz * (vztmp - v[j][2]); // artificial viscosity (Monaghan 1992) if (delVdotDelR < 0.) { mu = h * delVdotDelR / (rsq + 0.01 * h * h); fvisc = -viscosity[itype][jtype] * (soundspeed[itype] + soundspeed[jtype]) * mu / (rho[i] + rho[j]); } else { fvisc = 0.; } // total pair force & thermal energy increment fpair = -imass * jmass * (fi + fj + fvisc) * wfd; deltaE = -0.5 * fpair * delVdotDelR; f[i][0] += delx * fpair; f[i][1] += dely * fpair; f[i][2] += delz * fpair; // and change in density drho[i] += jmass * delVdotDelR * wfd; // change in thermal energy de[i] += deltaE; if (newton_pair || j < nlocal) { f[j][0] -= delx * fpair; f[j][1] -= dely * fpair; f[j][2] -= delz * fpair; de[j] += deltaE; drho[j] += imass * delVdotDelR * wfd; } if (evflag) ev_tally(i, j, nlocal, newton_pair, 0.0, 0.0, fpair, delx, dely, delz); } } } if (vflag_fdotr) virial_fdotr_compute(); } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairSPHTaitwater::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(rho0, n + 1, "pair:rho0"); memory->create(soundspeed, n + 1, "pair:soundspeed"); memory->create(B, n + 1, "pair:B"); memory->create(cut, n + 1, n + 1, "pair:cut"); memory->create(viscosity, n + 1, n + 1, "pair:viscosity"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairSPHTaitwater::settings(int narg, char **arg) { if (narg != 0) error->all(FLERR, "Illegal number of setting arguments for pair_style sph/taitwater"); } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairSPHTaitwater::coeff(int narg, char **arg) { if (narg != 6) error->all(FLERR, "Incorrect args for pair_style sph/taitwater 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); + force->bounds(FLERR,arg[0], atom->ntypes, ilo, ihi); + force->bounds(FLERR,arg[1], atom->ntypes, jlo, jhi); double rho0_one = force->numeric(FLERR,arg[2]); double soundspeed_one = force->numeric(FLERR,arg[3]); double viscosity_one = force->numeric(FLERR,arg[4]); double cut_one = force->numeric(FLERR,arg[5]); double B_one = soundspeed_one * soundspeed_one * rho0_one / 7.0; int count = 0; for (int i = ilo; i <= ihi; i++) { rho0[i] = rho0_one; soundspeed[i] = soundspeed_one; B[i] = B_one; for (int j = MAX(jlo,i); j <= jhi; j++) { viscosity[i][j] = viscosity_one; //printf("setting cut[%d][%d] = %f\n", i, j, cut_one); cut[i][j] = cut_one; setflag[i][j] = 1; //cut[j][i] = cut[i][j]; //viscosity[j][i] = viscosity[i][j]; //setflag[j][i] = 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 PairSPHTaitwater::init_one(int i, int j) { if (setflag[i][j] == 0) { error->all(FLERR,"Not all pair sph/taitwater coeffs are set"); } cut[j][i] = cut[i][j]; viscosity[j][i] = viscosity[i][j]; return cut[i][j]; } /* ---------------------------------------------------------------------- */ double PairSPHTaitwater::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { fforce = 0.0; return 0.0; } diff --git a/src/USER-SPH/pair_sph_taitwater_morris.cpp b/src/USER-SPH/pair_sph_taitwater_morris.cpp index d6a94f51c..76b538e46 100644 --- a/src/USER-SPH/pair_sph_taitwater_morris.cpp +++ b/src/USER-SPH/pair_sph_taitwater_morris.cpp @@ -1,297 +1,297 @@ /* ---------------------------------------------------------------------- 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 #include #include "pair_sph_taitwater_morris.h" #include "atom.h" #include "force.h" #include "comm.h" #include "neigh_list.h" #include "memory.h" #include "error.h" #include "domain.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ PairSPHTaitwaterMorris::PairSPHTaitwaterMorris(LAMMPS *lmp) : Pair(lmp) { restartinfo = 0; first = 1; } /* ---------------------------------------------------------------------- */ PairSPHTaitwaterMorris::~PairSPHTaitwaterMorris() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut); memory->destroy(rho0); memory->destroy(soundspeed); memory->destroy(B); memory->destroy(viscosity); } } /* ---------------------------------------------------------------------- */ void PairSPHTaitwaterMorris::compute(int eflag, int vflag) { int i, j, ii, jj, inum, jnum, itype, jtype; double xtmp, ytmp, ztmp, delx, dely, delz, fpair; int *ilist, *jlist, *numneigh, **firstneigh; double vxtmp, vytmp, vztmp, imass, jmass, fi, fj, fvisc, h, ih, ihsq, velx, vely, velz; double rsq, tmp, wfd, delVdotDelR, deltaE; if (eflag || vflag) ev_setup(eflag, vflag); else evflag = vflag_fdotr = 0; double **v = atom->vest; double **x = atom->x; double **f = atom->f; double *rho = atom->rho; double *mass = atom->mass; double *de = atom->de; double *drho = atom->drho; int *type = atom->type; int nlocal = atom->nlocal; int newton_pair = force->newton_pair; // check consistency of pair coefficients if (first) { for (i = 1; i <= atom->ntypes; i++) { for (j = 1; i <= atom->ntypes; i++) { if (cutsq[i][j] > 1.e-32) { if (!setflag[i][i] || !setflag[j][j]) { if (comm->me == 0) { printf( "SPH particle types %d and %d interact with cutoff=%g, but not all of their single particle properties are set.\n", i, j, sqrt(cutsq[i][j])); } } } } } first = 0; } 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]; vxtmp = v[i][0]; vytmp = v[i][1]; vztmp = v[i][2]; itype = type[i]; jlist = firstneigh[i]; jnum = numneigh[i]; imass = mass[itype]; // compute pressure of atom i with Tait EOS tmp = rho[i] / rho0[itype]; fi = tmp * tmp * tmp; fi = B[itype] * (fi * fi * tmp - 1.0) / (rho[i] * rho[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]; jmass = mass[jtype]; if (rsq < cutsq[itype][jtype]) { h = cut[itype][jtype]; ih = 1.0 / h; ihsq = ih * ih; wfd = h - sqrt(rsq); if (domain->dimension == 3) { // Lucy Kernel, 3d // Note that wfd, the derivative of the weight function with respect to r, // is lacking a factor of r. // The missing factor of r is recovered by // (1) using delV . delX instead of delV . (delX/r) and // (2) using f[i][0] += delx * fpair instead of f[i][0] += (delx/r) * fpair wfd = -25.066903536973515383e0 * wfd * wfd * ihsq * ihsq * ihsq * ih; } else { // Lucy Kernel, 2d wfd = -19.098593171027440292e0 * wfd * wfd * ihsq * ihsq * ihsq; } // compute pressure of atom j with Tait EOS tmp = rho[j] / rho0[jtype]; fj = tmp * tmp * tmp; fj = B[jtype] * (fj * fj * tmp - 1.0) / (rho[j] * rho[j]); velx=vxtmp - v[j][0]; vely=vytmp - v[j][1]; velz=vztmp - v[j][2]; // dot product of velocity delta and distance vector delVdotDelR = delx * velx + dely * vely + delz * velz; // Morris Viscosity (Morris, 1996) fvisc = 2 * viscosity[itype][jtype] / (rho[i] * rho[j]); fvisc *= imass * jmass * wfd; // total pair force & thermal energy increment fpair = -imass * jmass * (fi + fj) * wfd; deltaE = -0.5 *(fpair * delVdotDelR + fvisc * (velx*velx + vely*vely + velz*velz)); // printf("testvar= %f, %f \n", delx, dely); f[i][0] += delx * fpair + velx * fvisc; f[i][1] += dely * fpair + vely * fvisc; f[i][2] += delz * fpair + velz * fvisc; // and change in density drho[i] += jmass * delVdotDelR * wfd; // change in thermal energy de[i] += deltaE; if (newton_pair || j < nlocal) { f[j][0] -= delx * fpair + velx * fvisc; f[j][1] -= dely * fpair + vely * fvisc; f[j][2] -= delz * fpair + velz * fvisc; de[j] += deltaE; drho[j] += imass * delVdotDelR * wfd; } if (evflag) ev_tally(i, j, nlocal, newton_pair, 0.0, 0.0, fpair, delx, dely, delz); } } } if (vflag_fdotr) virial_fdotr_compute(); } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairSPHTaitwaterMorris::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(rho0, n + 1, "pair:rho0"); memory->create(soundspeed, n + 1, "pair:soundspeed"); memory->create(B, n + 1, "pair:B"); memory->create(cut, n + 1, n + 1, "pair:cut"); memory->create(viscosity, n + 1, n + 1, "pair:viscosity"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairSPHTaitwaterMorris::settings(int narg, char **arg) { if (narg != 0) error->all(FLERR, "Illegal number of setting arguments for pair_style sph/taitwater/morris"); } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairSPHTaitwaterMorris::coeff(int narg, char **arg) { if (narg != 6) error->all(FLERR, "Incorrect args for pair_style sph/taitwater/morris 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); + force->bounds(FLERR,arg[0], atom->ntypes, ilo, ihi); + force->bounds(FLERR,arg[1], atom->ntypes, jlo, jhi); double rho0_one = force->numeric(FLERR,arg[2]); double soundspeed_one = force->numeric(FLERR,arg[3]); double viscosity_one = force->numeric(FLERR,arg[4]); double cut_one = force->numeric(FLERR,arg[5]); double B_one = soundspeed_one * soundspeed_one * rho0_one / 7.0; int count = 0; for (int i = ilo; i <= ihi; i++) { rho0[i] = rho0_one; soundspeed[i] = soundspeed_one; B[i] = B_one; for (int j = MAX(jlo,i); j <= jhi; j++) { viscosity[i][j] = viscosity_one; //printf("setting cut[%d][%d] = %f\n", i, j, cut_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 PairSPHTaitwaterMorris::init_one(int i, int j) { if (setflag[i][j] == 0) { error->all(FLERR,"Not all pair sph/taitwater/morris coeffs are not set"); } cut[j][i] = cut[i][j]; viscosity[j][i] = viscosity[i][j]; return cut[i][j]; } /* ---------------------------------------------------------------------- */ double PairSPHTaitwaterMorris::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { fforce = 0.0; return 0.0; } diff --git a/src/angle_hybrid.cpp b/src/angle_hybrid.cpp index 42b6860b6..a477d7f8f 100644 --- a/src/angle_hybrid.cpp +++ b/src/angle_hybrid.cpp @@ -1,376 +1,376 @@ /* ---------------------------------------------------------------------- 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 #include #include #include "angle_hybrid.h" #include "atom.h" #include "neighbor.h" #include "domain.h" #include "comm.h" #include "force.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define EXTRA 1000 /* ---------------------------------------------------------------------- */ AngleHybrid::AngleHybrid(LAMMPS *lmp) : Angle(lmp) { writedata = 0; nstyles = 0; } /* ---------------------------------------------------------------------- */ AngleHybrid::~AngleHybrid() { if (nstyles) { for (int i = 0; i < nstyles; i++) delete styles[i]; delete [] styles; for (int i = 0; i < nstyles; i++) delete [] keywords[i]; delete [] keywords; } if (allocated) { memory->destroy(setflag); memory->destroy(map); delete [] nanglelist; delete [] maxangle; for (int i = 0; i < nstyles; i++) memory->destroy(anglelist[i]); delete [] anglelist; } } /* ---------------------------------------------------------------------- */ void AngleHybrid::compute(int eflag, int vflag) { int i,j,m,n; // save ptrs to original anglelist int nanglelist_orig = neighbor->nanglelist; int **anglelist_orig = neighbor->anglelist; // if this is re-neighbor step, create sub-style anglelists // nanglelist[] = length of each sub-style list // realloc sub-style anglelist if necessary // load sub-style anglelist with 4 values from original anglelist if (neighbor->ago == 0) { for (m = 0; m < nstyles; m++) nanglelist[m] = 0; for (i = 0; i < nanglelist_orig; i++) { m = map[anglelist_orig[i][3]]; if (m >= 0) nanglelist[m]++; } for (m = 0; m < nstyles; m++) { if (nanglelist[m] > maxangle[m]) { memory->destroy(anglelist[m]); maxangle[m] = nanglelist[m] + EXTRA; memory->create(anglelist[m],maxangle[m],4,"angle_hybrid:anglelist"); } nanglelist[m] = 0; } for (i = 0; i < nanglelist_orig; i++) { m = map[anglelist_orig[i][3]]; if (m < 0) continue; n = nanglelist[m]; anglelist[m][n][0] = anglelist_orig[i][0]; anglelist[m][n][1] = anglelist_orig[i][1]; anglelist[m][n][2] = anglelist_orig[i][2]; anglelist[m][n][3] = anglelist_orig[i][3]; nanglelist[m]++; } } // call each sub-style's compute function // set neighbor->anglelist to sub-style anglelist before call // accumulate sub-style global/peratom energy/virial in hybrid if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; for (m = 0; m < nstyles; m++) { neighbor->nanglelist = nanglelist[m]; neighbor->anglelist = anglelist[m]; styles[m]->compute(eflag,vflag); if (eflag_global) energy += styles[m]->energy; if (vflag_global) for (n = 0; n < 6; n++) virial[n] += styles[m]->virial[n]; if (eflag_atom) { n = atom->nlocal; if (force->newton_bond) 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_bond) 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]; } } // restore ptrs to original anglelist neighbor->nanglelist = nanglelist_orig; neighbor->anglelist = anglelist_orig; } /* ---------------------------------------------------------------------- */ void AngleHybrid::allocate() { allocated = 1; int n = atom->nangletypes; memory->create(map,n+1,"angle:map"); memory->create(setflag,n+1,"angle:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; nanglelist = new int[nstyles]; maxangle = new int[nstyles]; anglelist = new int**[nstyles]; for (int m = 0; m < nstyles; m++) maxangle[m] = 0; for (int m = 0; m < nstyles; m++) anglelist[m] = NULL; } /* ---------------------------------------------------------------------- create one angle style for each arg in list ------------------------------------------------------------------------- */ void AngleHybrid::settings(int narg, char **arg) { int i,m,istyle; if (narg < 1) error->all(FLERR,"Illegal angle_style command"); // delete old lists, since cannot just change settings if (nstyles) { for (int i = 0; i < nstyles; i++) delete styles[i]; delete [] styles; for (int i = 0; i < nstyles; i++) delete [] keywords[i]; delete [] keywords; } if (allocated) { memory->destroy(setflag); memory->destroy(map); delete [] nanglelist; delete [] maxangle; for (int i = 0; i < nstyles; i++) memory->destroy(anglelist[i]); delete [] anglelist; } allocated = 0; // count sub-styles by skipping numeric args // one exception is 1st arg of style "table", which is non-numeric word // need a better way to skip these exceptions nstyles = 0; i = 0; while (i < narg) { if (strcmp(arg[i],"table") == 0) i++; i++; while (i < narg && !isalpha(arg[i][0])) i++; nstyles++; } // allocate list of sub-styles styles = new Angle*[nstyles]; keywords = new char*[nstyles]; // allocate each sub-style and call its settings() with subset of args // allocate uses suffix, but don't store suffix version in keywords, // else syntax in coeff() will not match // define subset of args for a sub-style by skipping numeric args // one exception is 1st arg of style "table", which is non-numeric // 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,"Angle style hybrid cannot use " "same angle style twice"); if (strcmp(arg[i],"hybrid") == 0) error->all(FLERR,"Angle style hybrid cannot have hybrid as an argument"); if (strcmp(arg[i],"none") == 0) error->all(FLERR,"Angle style hybrid cannot have none as an argument"); styles[nstyles] = force->new_angle(arg[i],1,dummy); force->store_style(keywords[nstyles],arg[i],0); istyle = i; if (strcmp(arg[i],"table") == 0) i++; i++; while (i < narg && !isalpha(arg[i][0])) i++; styles[nstyles]->settings(i-istyle-1,&arg[istyle+1]); nstyles++; } } /* ---------------------------------------------------------------------- set coeffs for one type ---------------------------------------------------------------------- */ void AngleHybrid::coeff(int narg, char **arg) { if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->nangletypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->nangletypes,ilo,ihi); // 2nd arg = angle sub-style name // allow for "none" or "skip" as valid sub-style name int m; for (m = 0; m < nstyles; m++) if (strcmp(arg[1],keywords[m]) == 0) break; int none = 0; int skip = 0; if (m == nstyles) { if (strcmp(arg[1],"none") == 0) none = 1; else if (strcmp(arg[1],"skip") == 0) none = skip = 1; else if (strcmp(arg[1],"ba") == 0) error->all(FLERR,"BondAngle coeff for hybrid angle has invalid format"); else if (strcmp(arg[1],"bb") == 0) error->all(FLERR,"BondBond coeff for hybrid angle has invalid format"); else error->all(FLERR,"Angle coeff for hybrid has invalid style"); } // move 1st arg to 2nd arg // just copy ptrs, since arg[] points into original input line arg[1] = arg[0]; // invoke sub-style coeff() starting with 1st arg if (!none) styles[m]->coeff(narg-1,&arg[1]); // set setflag and which type maps to which sub-style // if sub-style is skip: auxiliary class2 setting in data file so ignore // if sub-style is none: set hybrid setflag, wipe out map for (int i = ilo; i <= ihi; i++) { if (skip) continue; else if (none) { setflag[i] = 1; map[i] = -1; } else { setflag[i] = styles[m]->setflag[i]; map[i] = m; } } } /* ---------------------------------------------------------------------- run angle style specific initialization ------------------------------------------------------------------------- */ void AngleHybrid::init_style() { for (int m = 0; m < nstyles; m++) if (styles[m]) styles[m]->init_style(); } /* ---------------------------------------------------------------------- return an equilbrium angle length ------------------------------------------------------------------------- */ double AngleHybrid::equilibrium_angle(int i) { if (map[i] < 0) error->one(FLERR,"Invoked angle equil angle on angle style none"); return styles[map[i]]->equilibrium_angle(i); } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void AngleHybrid::write_restart(FILE *fp) { fwrite(&nstyles,sizeof(int),1,fp); 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); } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void AngleHybrid::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 Angle*[nstyles]; keywords = new char*[nstyles]; allocate(); 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_angle(keywords[m],0,dummy); } } /* ---------------------------------------------------------------------- */ double AngleHybrid::single(int type, int i1, int i2, int i3) { if (map[type] < 0) error->one(FLERR,"Invoked angle single on angle style none"); return styles[map[type]]->single(type,i1,i2,i3); } /* ---------------------------------------------------------------------- memory usage ------------------------------------------------------------------------- */ double AngleHybrid::memory_usage() { double bytes = maxeatom * sizeof(double); bytes += maxvatom*6 * sizeof(double); for (int m = 0; m < nstyles; m++) bytes += maxangle[m]*4 * sizeof(int); for (int m = 0; m < nstyles; m++) if (styles[m]) bytes += styles[m]->memory_usage(); return bytes; } diff --git a/src/angle_zero.cpp b/src/angle_zero.cpp index 375d5ad81..ba84295ca 100644 --- a/src/angle_zero.cpp +++ b/src/angle_zero.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. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author: Carsten Svaneborg (SDU) ------------------------------------------------------------------------- */ #include #include #include #include "angle_zero.h" #include "atom.h" #include "force.h" #include "comm.h" #include "math_const.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace MathConst; /* ---------------------------------------------------------------------- */ AngleZero::AngleZero(LAMMPS *lmp) : Angle(lmp), coeffflag(1) {} /* ---------------------------------------------------------------------- */ AngleZero::~AngleZero() { if (allocated && !copymode) { memory->destroy(setflag); memory->destroy(theta0); } } /* ---------------------------------------------------------------------- */ void AngleZero::compute(int eflag, int vflag) { if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; } /* ---------------------------------------------------------------------- */ void AngleZero::settings(int narg, char **arg) { if ((narg != 0) && (narg != 1)) error->all(FLERR,"Illegal angle_style command"); if (narg == 1) { if (strcmp("nocoeff",arg[0]) == 0) coeffflag=0; else error->all(FLERR,"Illegal angle_style command"); } } /* ---------------------------------------------------------------------- */ void AngleZero::allocate() { allocated = 1; int n = atom->nangletypes; memory->create(theta0,n+1,"angle:theta0"); memory->create(setflag,n+1,"angle:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one or more types ------------------------------------------------------------------------- */ void AngleZero::coeff(int narg, char **arg) { if ((narg < 1) || (coeffflag && narg > 2)) error->all(FLERR,"Incorrect args for angle coefficients"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->nangletypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->nangletypes,ilo,ihi); double theta0_one = 0.0; if (coeffflag && (narg == 2)) theta0_one = force->numeric(FLERR,arg[1]); // convert theta0 from degrees to radians int count = 0; for (int i = ilo; i <= ihi; i++) { setflag[i] = 1; theta0[i] = theta0_one/180.0 * MY_PI; count++; } if (count == 0) error->all(FLERR,"Incorrect args for angle coefficients"); } /* ---------------------------------------------------------------------- */ double AngleZero::equilibrium_angle(int i) { return theta0[i]; } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void AngleZero::write_restart(FILE *fp) { fwrite(&theta0[1],sizeof(double),atom->nangletypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void AngleZero::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&theta0[1],sizeof(double),atom->nangletypes,fp); } MPI_Bcast(&theta0[1],atom->nangletypes,MPI_DOUBLE,0,world); for (int i = 1; i <= atom->nangletypes; i++) setflag[i] = 1; } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void AngleZero::write_data(FILE *fp) { for (int i = 1; i <= atom->nangletypes; i++) fprintf(fp,"%d %g\n",i,theta0[i]/MY_PI*180.0); } /* ---------------------------------------------------------------------- */ double AngleZero::single(int type, int i1, int i2, int i3) { return 0.0; } diff --git a/src/bond_hybrid.cpp b/src/bond_hybrid.cpp index 519a1a300..1244c2822 100644 --- a/src/bond_hybrid.cpp +++ b/src/bond_hybrid.cpp @@ -1,362 +1,362 @@ /* ---------------------------------------------------------------------- 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 #include #include #include "bond_hybrid.h" #include "atom.h" #include "neighbor.h" #include "domain.h" #include "comm.h" #include "force.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define EXTRA 1000 /* ---------------------------------------------------------------------- */ BondHybrid::BondHybrid(LAMMPS *lmp) : Bond(lmp) { writedata = 0; nstyles = 0; } /* ---------------------------------------------------------------------- */ BondHybrid::~BondHybrid() { if (nstyles) { for (int i = 0; i < nstyles; i++) delete styles[i]; delete [] styles; for (int i = 0; i < nstyles; i++) delete [] keywords[i]; delete [] keywords; } if (allocated) { memory->destroy(setflag); memory->destroy(map); delete [] nbondlist; delete [] maxbond; for (int i = 0; i < nstyles; i++) memory->destroy(bondlist[i]); delete [] bondlist; } } /* ---------------------------------------------------------------------- */ void BondHybrid::compute(int eflag, int vflag) { int i,j,m,n; // save ptrs to original bondlist int nbondlist_orig = neighbor->nbondlist; int **bondlist_orig = neighbor->bondlist; // if this is re-neighbor step, create sub-style bondlists // nbondlist[] = length of each sub-style list // realloc sub-style bondlist if necessary // load sub-style bondlist with 3 values from original bondlist if (neighbor->ago == 0) { for (m = 0; m < nstyles; m++) nbondlist[m] = 0; for (i = 0; i < nbondlist_orig; i++) { m = map[bondlist_orig[i][2]]; if (m >= 0) nbondlist[m]++; } for (m = 0; m < nstyles; m++) { if (nbondlist[m] > maxbond[m]) { memory->destroy(bondlist[m]); maxbond[m] = nbondlist[m] + EXTRA; memory->create(bondlist[m],maxbond[m],3,"bond_hybrid:bondlist"); } nbondlist[m] = 0; } for (i = 0; i < nbondlist_orig; i++) { m = map[bondlist_orig[i][2]]; if (m < 0) continue; n = nbondlist[m]; bondlist[m][n][0] = bondlist_orig[i][0]; bondlist[m][n][1] = bondlist_orig[i][1]; bondlist[m][n][2] = bondlist_orig[i][2]; nbondlist[m]++; } } // call each sub-style's compute function // set neighbor->bondlist to sub-style bondlist before call // accumulate sub-style global/peratom energy/virial in hybrid if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; for (m = 0; m < nstyles; m++) { neighbor->nbondlist = nbondlist[m]; neighbor->bondlist = bondlist[m]; styles[m]->compute(eflag,vflag); if (eflag_global) energy += styles[m]->energy; if (vflag_global) for (n = 0; n < 6; n++) virial[n] += styles[m]->virial[n]; if (eflag_atom) { n = atom->nlocal; if (force->newton_bond) 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_bond) 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]; } } // restore ptrs to original bondlist neighbor->nbondlist = nbondlist_orig; neighbor->bondlist = bondlist_orig; } /* ---------------------------------------------------------------------- */ void BondHybrid::allocate() { allocated = 1; int n = atom->nbondtypes; memory->create(map,n+1,"bond:map"); memory->create(setflag,n+1,"bond:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; nbondlist = new int[nstyles]; maxbond = new int[nstyles]; bondlist = new int**[nstyles]; for (int m = 0; m < nstyles; m++) maxbond[m] = 0; for (int m = 0; m < nstyles; m++) bondlist[m] = NULL; } /* ---------------------------------------------------------------------- create one bond style for each arg in list ------------------------------------------------------------------------- */ void BondHybrid::settings(int narg, char **arg) { int i,m,istyle; if (narg < 1) error->all(FLERR,"Illegal bond_style command"); // delete old lists, since cannot just change settings if (nstyles) { for (int i = 0; i < nstyles; i++) delete styles[i]; delete [] styles; for (int i = 0; i < nstyles; i++) delete [] keywords[i]; delete [] keywords; } if (allocated) { memory->destroy(setflag); memory->destroy(map); delete [] nbondlist; delete [] maxbond; for (int i = 0; i < nstyles; i++) memory->destroy(bondlist[i]); delete [] bondlist; } allocated = 0; // count sub-styles by skipping numeric args // one exception is 1st arg of style "table", which is non-numeric word // need a better way to skip these exceptions nstyles = 0; i = 0; while (i < narg) { if (strcmp(arg[i],"table") == 0) i++; i++; while (i < narg && !isalpha(arg[i][0])) i++; nstyles++; } // allocate list of sub-styles styles = new Bond*[nstyles]; keywords = new char*[nstyles]; // allocate each sub-style and call its settings() with subset of args // allocate uses suffix, but don't store suffix version in keywords, // else syntax in coeff() will not match // define subset of args for a sub-style by skipping numeric args // one exception is 1st arg of style "table", which is non-numeric // 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,"Bond style hybrid cannot use same bond style twice"); if (strcmp(arg[i],"hybrid") == 0) error->all(FLERR,"Bond style hybrid cannot have hybrid as an argument"); if (strcmp(arg[i],"none") == 0) error->all(FLERR,"Bond style hybrid cannot have none as an argument"); styles[nstyles] = force->new_bond(arg[i],1,dummy); force->store_style(keywords[nstyles],arg[i],0); istyle = i; if (strcmp(arg[i],"table") == 0) i++; i++; while (i < narg && !isalpha(arg[i][0])) i++; styles[nstyles]->settings(i-istyle-1,&arg[istyle+1]); nstyles++; } } /* ---------------------------------------------------------------------- set coeffs for one type ---------------------------------------------------------------------- */ void BondHybrid::coeff(int narg, char **arg) { if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->nbondtypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->nbondtypes,ilo,ihi); // 2nd arg = bond sub-style name // allow for "none" as valid sub-style name int m; for (m = 0; m < nstyles; m++) if (strcmp(arg[1],keywords[m]) == 0) break; int none = 0; if (m == nstyles) { if (strcmp(arg[1],"none") == 0) none = 1; else error->all(FLERR,"Bond coeff for hybrid has invalid style"); } // move 1st arg to 2nd arg // just copy ptrs, since arg[] points into original input line arg[1] = arg[0]; // invoke sub-style coeff() starting with 1st arg if (!none) styles[m]->coeff(narg-1,&arg[1]); // set setflag and which type maps to which sub-style // if sub-style is none: set hybrid setflag, wipe out map for (int i = ilo; i <= ihi; i++) { setflag[i] = 1; if (none) map[i] = -1; else map[i] = m; } } /* ---------------------------------------------------------------------- */ void BondHybrid::init_style() { for (int m = 0; m < nstyles; m++) if (styles[m]) styles[m]->init_style(); } /* ---------------------------------------------------------------------- return an equilbrium bond length ------------------------------------------------------------------------- */ double BondHybrid::equilibrium_distance(int i) { if (map[i] < 0) error->one(FLERR,"Invoked bond equil distance on bond style none"); return styles[map[i]]->equilibrium_distance(i); } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void BondHybrid::write_restart(FILE *fp) { fwrite(&nstyles,sizeof(int),1,fp); 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); } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void BondHybrid::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 Bond*[nstyles]; keywords = new char*[nstyles]; allocate(); 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_bond(keywords[m],0,dummy); } } /* ---------------------------------------------------------------------- */ double BondHybrid::single(int type, double rsq, int i, int j, double &fforce) { if (map[type] < 0) error->one(FLERR,"Invoked bond single on bond style none"); return styles[map[type]]->single(type,rsq,i,j,fforce); } /* ---------------------------------------------------------------------- memory usage ------------------------------------------------------------------------- */ double BondHybrid::memory_usage() { double bytes = maxeatom * sizeof(double); bytes += maxvatom*6 * sizeof(double); for (int m = 0; m < nstyles; m++) bytes += maxbond[m]*3 * sizeof(int); for (int m = 0; m < nstyles; m++) if (styles[m]) bytes += styles[m]->memory_usage(); return bytes; } diff --git a/src/bond_zero.cpp b/src/bond_zero.cpp index 0a354a758..f38b7754f 100644 --- a/src/bond_zero.cpp +++ b/src/bond_zero.cpp @@ -1,156 +1,156 @@ /* ---------------------------------------------------------------------- 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: Carsten Svaneborg (SDU) ------------------------------------------------------------------------- */ #include #include #include #include "bond_zero.h" #include "atom.h" #include "force.h" #include "comm.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ BondZero::BondZero(LAMMPS *lmp) : Bond(lmp), coeffflag(1) {} /* ---------------------------------------------------------------------- */ BondZero::~BondZero() { if (allocated && !copymode) { memory->destroy(setflag); memory->destroy(r0); } } /* ---------------------------------------------------------------------- */ void BondZero::compute(int eflag, int vflag) { if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; } /* ---------------------------------------------------------------------- */ void BondZero::settings(int narg, char **arg) { if ((narg != 0) && (narg != 1)) error->all(FLERR,"Illegal bond_style command"); if (narg == 1) { if (strcmp("nocoeff",arg[0]) == 0) coeffflag=0; else error->all(FLERR,"Illegal bond_style command"); } } /* ---------------------------------------------------------------------- */ void BondZero::allocate() { allocated = 1; int n = atom->nbondtypes; memory->create(r0,n+1,"bond:r0"); memory->create(setflag,n+1,"bond:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one or more types ------------------------------------------------------------------------- */ void BondZero::coeff(int narg, char **arg) { if ((narg < 1) || (coeffflag && narg > 2)) error->all(FLERR,"Incorrect args for bond coefficients"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->nbondtypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->nbondtypes,ilo,ihi); double r0_one = 0.0; if (coeffflag && (narg == 2)) r0_one = force->numeric(FLERR,arg[1]); int count = 0; for (int i = ilo; i <= ihi; i++) { setflag[i] = 1; r0[i] = r0_one; count++; } if (count == 0) error->all(FLERR,"Incorrect args for bond coefficients"); } /* ---------------------------------------------------------------------- return an equilbrium bond length ------------------------------------------------------------------------- */ double BondZero::equilibrium_distance(int i) { return r0[i]; } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void BondZero::write_restart(FILE *fp) { fwrite(&r0[1],sizeof(double),atom->nbondtypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void BondZero::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&r0[1],sizeof(double),atom->nbondtypes,fp); } MPI_Bcast(&r0[1],atom->nbondtypes,MPI_DOUBLE,0,world); for (int i = 1; i <= atom->nbondtypes; i++) setflag[i] = 1; } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void BondZero::write_data(FILE *fp) { for (int i = 1; i <= atom->nbondtypes; i++) fprintf(fp,"%d %g\n",i,r0[i]); } /* ---------------------------------------------------------------------- */ double BondZero::single(int type, double rsq, int i, int j, double &fforce) { return 0.0; } diff --git a/src/comm.cpp b/src/comm.cpp index a47807b41..b558b3fd8 100644 --- a/src/comm.cpp +++ b/src/comm.cpp @@ -1,789 +1,789 @@ /* ---------------------------------------------------------------------- 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 #include #include #include "comm.h" #include "universe.h" #include "atom.h" #include "atom_vec.h" #include "force.h" #include "pair.h" #include "modify.h" #include "fix.h" #include "compute.h" #include "domain.h" #include "output.h" #include "dump.h" #include "group.h" #include "procmap.h" #include "accelerator_kokkos.h" #include "memory.h" #include "error.h" #ifdef _OPENMP #include #endif using namespace LAMMPS_NS; #define BUFMIN 1000 // also in comm styles enum{SINGLE,MULTI}; // same as in Comm sub-styles enum{MULTIPLE}; // same as in ProcMap enum{ONELEVEL,TWOLEVEL,NUMA,CUSTOM}; enum{CART,CARTREORDER,XYZ}; enum{LAYOUT_UNIFORM,LAYOUT_NONUNIFORM,LAYOUT_TILED}; // several files /* ---------------------------------------------------------------------- */ Comm::Comm(LAMMPS *lmp) : Pointers(lmp) { MPI_Comm_rank(world,&me); MPI_Comm_size(world,&nprocs); mode = 0; bordergroup = 0; cutghostuser = 0.0; cutusermulti = NULL; ghost_velocity = 0; user_procgrid[0] = user_procgrid[1] = user_procgrid[2] = 0; coregrid[0] = coregrid[1] = coregrid[2] = 1; gridflag = ONELEVEL; mapflag = CART; customfile = NULL; outfile = NULL; recv_from_partition = send_to_partition = -1; otherflag = 0; maxexchange_atom = maxexchange_fix = 0; grid2proc = NULL; xsplit = ysplit = zsplit = NULL; rcbnew = 0; // use of OpenMP threads // query OpenMP for number of threads/process set by user at run-time // if the OMP_NUM_THREADS environment variable is not set, we default // to using 1 thread. This follows the principle of the least surprise, // while practically all OpenMP implementations violate it by using // as many threads as there are (virtual) CPU cores by default. nthreads = 1; #ifdef _OPENMP if (lmp->kokkos) { nthreads = lmp->kokkos->num_threads * lmp->kokkos->numa; } else if (getenv("OMP_NUM_THREADS") == NULL) { nthreads = 1; if (me == 0) error->message(FLERR,"OMP_NUM_THREADS environment is not set. " "Defaulting to 1 thread."); } else { nthreads = omp_get_max_threads(); } // enforce consistent number of threads across all MPI tasks MPI_Bcast(&nthreads,1,MPI_INT,0,world); if (!lmp->kokkos) omp_set_num_threads(nthreads); if (me == 0) { if (screen) fprintf(screen," using %d OpenMP thread(s) per MPI task\n",nthreads); if (logfile) fprintf(logfile," using %d OpenMP thread(s) per MPI task\n",nthreads); } #endif } /* ---------------------------------------------------------------------- */ Comm::~Comm() { memory->destroy(grid2proc); memory->destroy(xsplit); memory->destroy(ysplit); memory->destroy(zsplit); memory->destroy(cutusermulti); delete [] customfile; delete [] outfile; } /* ---------------------------------------------------------------------- deep copy of arrays from old Comm class to new one all public/protected vectors/arrays in parent Comm class must be copied called from alternate constructor of child classes when new comm style is created from Input ------------------------------------------------------------------------- */ void Comm::copy_arrays(Comm *oldcomm) { if (oldcomm->grid2proc) { memory->create(grid2proc,procgrid[0],procgrid[1],procgrid[2], "comm:grid2proc"); memcpy(&grid2proc[0][0][0],&oldcomm->grid2proc[0][0][0], (procgrid[0]*procgrid[1]*procgrid[2])*sizeof(int)); memory->create(xsplit,procgrid[0]+1,"comm:xsplit"); memory->create(ysplit,procgrid[1]+1,"comm:ysplit"); memory->create(zsplit,procgrid[2]+1,"comm:zsplit"); memcpy(xsplit,oldcomm->xsplit,(procgrid[0]+1)*sizeof(double)); memcpy(ysplit,oldcomm->ysplit,(procgrid[1]+1)*sizeof(double)); memcpy(zsplit,oldcomm->zsplit,(procgrid[2]+1)*sizeof(double)); } if (oldcomm->cutusermulti) { memory->create(cutusermulti,atom->ntypes+1,"comm:cutusermulti"); memcpy(cutusermulti,oldcomm->cutusermulti,atom->ntypes+1); } if (customfile) { int n = strlen(oldcomm->customfile) + 1; customfile = new char[n]; strcpy(customfile,oldcomm->customfile); } if (outfile) { int n = strlen(oldcomm->outfile) + 1; outfile = new char[n]; strcpy(outfile,oldcomm->outfile); } } /* ---------------------------------------------------------------------- common to all Comm styles ------------------------------------------------------------------------- */ void Comm::init() { triclinic = domain->triclinic; map_style = atom->map_style; // check warn if any proc's subbox is smaller than neigh skin // since may lead to lost atoms in exchange() // really should check every exchange() in case box size is shrinking // but seems overkill to do that (fix balance does perform this check) domain->subbox_too_small_check(neighbor->skin); // comm_only = 1 if only x,f are exchanged in forward/reverse comm // comm_x_only = 0 if ghost_velocity since velocities are added comm_x_only = atom->avec->comm_x_only; comm_f_only = atom->avec->comm_f_only; if (ghost_velocity) comm_x_only = 0; // set per-atom sizes for forward/reverse/border comm // augment by velocity and fix quantities if needed size_forward = atom->avec->size_forward; size_reverse = atom->avec->size_reverse; size_border = atom->avec->size_border; if (ghost_velocity) size_forward += atom->avec->size_velocity; if (ghost_velocity) size_border += atom->avec->size_velocity; for (int i = 0; i < modify->nfix; i++) size_border += modify->fix[i]->comm_border; // per-atom limits for communication // maxexchange = max # of datums in exchange comm, set in exchange() // maxforward = # of datums in largest forward comm // maxreverse = # of datums in largest reverse comm // query pair,fix,compute,dump for their requirements // pair style can force reverse comm even if newton off maxforward = MAX(size_forward,size_border); maxreverse = size_reverse; if (force->pair) maxforward = MAX(maxforward,force->pair->comm_forward); if (force->pair) maxreverse = MAX(maxreverse,force->pair->comm_reverse); for (int i = 0; i < modify->nfix; i++) { maxforward = MAX(maxforward,modify->fix[i]->comm_forward); maxreverse = MAX(maxreverse,modify->fix[i]->comm_reverse); } for (int i = 0; i < modify->ncompute; i++) { maxforward = MAX(maxforward,modify->compute[i]->comm_forward); maxreverse = MAX(maxreverse,modify->compute[i]->comm_reverse); } for (int i = 0; i < output->ndump; i++) { maxforward = MAX(maxforward,output->dump[i]->comm_forward); maxreverse = MAX(maxreverse,output->dump[i]->comm_reverse); } if (force->newton == 0) maxreverse = 0; if (force->pair) maxreverse = MAX(maxreverse,force->pair->comm_reverse_off); } /* ---------------------------------------------------------------------- modify communication params invoked from input script by comm_modify command ------------------------------------------------------------------------- */ void Comm::modify_params(int narg, char **arg) { if (narg < 1) error->all(FLERR,"Illegal comm_modify command"); int iarg = 0; while (iarg < narg) { if (strcmp(arg[iarg],"mode") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal comm_modify command"); if (strcmp(arg[iarg+1],"single") == 0) { // need to reset cutghostuser when switching comm mode if (mode == MULTI) cutghostuser = 0.0; memory->destroy(cutusermulti); cutusermulti = NULL; mode = SINGLE; } else if (strcmp(arg[iarg+1],"multi") == 0) { // need to reset cutghostuser when switching comm mode if (mode == SINGLE) cutghostuser = 0.0; mode = MULTI; } else error->all(FLERR,"Illegal comm_modify command"); iarg += 2; } else if (strcmp(arg[iarg],"group") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal comm_modify command"); bordergroup = group->find(arg[iarg+1]); if (bordergroup < 0) error->all(FLERR,"Invalid group in comm_modify command"); if (bordergroup && (atom->firstgroupname == NULL || strcmp(arg[iarg+1],atom->firstgroupname) != 0)) error->all(FLERR,"Comm_modify group != atom_modify first group"); iarg += 2; } else if (strcmp(arg[iarg],"cutoff") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal comm_modify command"); if (mode == MULTI) error->all(FLERR,"Use cutoff/multi keyword to set cutoff in multi mode"); cutghostuser = force->numeric(FLERR,arg[iarg+1]); if (cutghostuser < 0.0) error->all(FLERR,"Invalid cutoff in comm_modify command"); iarg += 2; } else if (strcmp(arg[iarg],"cutoff/multi") == 0) { int i,nlo,nhi; double cut; if (mode == SINGLE) error->all(FLERR,"Use cutoff keyword to set cutoff in single mode"); if (domain->box_exist == 0) error->all(FLERR, "Cannot set cutoff/multi before simulation box is defined"); const int ntypes = atom->ntypes; if (iarg+3 > narg) error->all(FLERR,"Illegal comm_modify command"); if (cutusermulti == NULL) { memory->create(cutusermulti,ntypes+1,"comm:cutusermulti"); for (i=0; i < ntypes+1; ++i) cutusermulti[i] = -1.0; } - force->bounds(arg[iarg+1],ntypes,nlo,nhi,1); + force->bounds(FLERR,arg[iarg+1],ntypes,nlo,nhi,1); cut = force->numeric(FLERR,arg[iarg+2]); cutghostuser = MAX(cutghostuser,cut); if (cut < 0.0) error->all(FLERR,"Invalid cutoff in comm_modify command"); for (i=nlo; i<=nhi; ++i) cutusermulti[i] = cut; iarg += 3; } else if (strcmp(arg[iarg],"vel") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal comm_modify command"); if (strcmp(arg[iarg+1],"yes") == 0) ghost_velocity = 1; else if (strcmp(arg[iarg+1],"no") == 0) ghost_velocity = 0; else error->all(FLERR,"Illegal comm_modify command"); iarg += 2; } else error->all(FLERR,"Illegal comm_modify command"); } } /* ---------------------------------------------------------------------- set dimensions for 3d grid of processors, and associated flags invoked from input script by processors command ------------------------------------------------------------------------- */ void Comm::set_processors(int narg, char **arg) { if (narg < 3) error->all(FLERR,"Illegal processors command"); if (strcmp(arg[0],"*") == 0) user_procgrid[0] = 0; else user_procgrid[0] = force->inumeric(FLERR,arg[0]); if (strcmp(arg[1],"*") == 0) user_procgrid[1] = 0; else user_procgrid[1] = force->inumeric(FLERR,arg[1]); if (strcmp(arg[2],"*") == 0) user_procgrid[2] = 0; else user_procgrid[2] = force->inumeric(FLERR,arg[2]); if (user_procgrid[0] < 0 || user_procgrid[1] < 0 || user_procgrid[2] < 0) error->all(FLERR,"Illegal processors command"); int p = user_procgrid[0]*user_procgrid[1]*user_procgrid[2]; if (p && p != nprocs) error->all(FLERR,"Specified processors != physical processors"); int iarg = 3; while (iarg < narg) { if (strcmp(arg[iarg],"grid") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal processors command"); if (strcmp(arg[iarg+1],"onelevel") == 0) { gridflag = ONELEVEL; } else if (strcmp(arg[iarg+1],"twolevel") == 0) { if (iarg+6 > narg) error->all(FLERR,"Illegal processors command"); gridflag = TWOLEVEL; ncores = force->inumeric(FLERR,arg[iarg+2]); if (strcmp(arg[iarg+3],"*") == 0) user_coregrid[0] = 0; else user_coregrid[0] = force->inumeric(FLERR,arg[iarg+3]); if (strcmp(arg[iarg+4],"*") == 0) user_coregrid[1] = 0; else user_coregrid[1] = force->inumeric(FLERR,arg[iarg+4]); if (strcmp(arg[iarg+5],"*") == 0) user_coregrid[2] = 0; else user_coregrid[2] = force->inumeric(FLERR,arg[iarg+5]); if (ncores <= 0 || user_coregrid[0] < 0 || user_coregrid[1] < 0 || user_coregrid[2] < 0) error->all(FLERR,"Illegal processors command"); iarg += 4; } else if (strcmp(arg[iarg+1],"numa") == 0) { gridflag = NUMA; } else if (strcmp(arg[iarg+1],"custom") == 0) { if (iarg+3 > narg) error->all(FLERR,"Illegal processors command"); gridflag = CUSTOM; delete [] customfile; int n = strlen(arg[iarg+2]) + 1; customfile = new char[n]; strcpy(customfile,arg[iarg+2]); iarg += 1; } else error->all(FLERR,"Illegal processors command"); iarg += 2; } else if (strcmp(arg[iarg],"map") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal processors command"); if (strcmp(arg[iarg+1],"cart") == 0) mapflag = CART; else if (strcmp(arg[iarg+1],"cart/reorder") == 0) mapflag = CARTREORDER; else if (strcmp(arg[iarg+1],"xyz") == 0 || strcmp(arg[iarg+1],"xzy") == 0 || strcmp(arg[iarg+1],"yxz") == 0 || strcmp(arg[iarg+1],"yzx") == 0 || strcmp(arg[iarg+1],"zxy") == 0 || strcmp(arg[iarg+1],"zyx") == 0) { mapflag = XYZ; strncpy(xyz,arg[iarg+1],3); } else error->all(FLERR,"Illegal processors command"); iarg += 2; } else if (strcmp(arg[iarg],"part") == 0) { if (iarg+4 > narg) error->all(FLERR,"Illegal processors command"); if (universe->nworlds == 1) error->all(FLERR, "Cannot use processors part command " "without using partitions"); int isend = force->inumeric(FLERR,arg[iarg+1]); int irecv = force->inumeric(FLERR,arg[iarg+2]); if (isend < 1 || isend > universe->nworlds || irecv < 1 || irecv > universe->nworlds || isend == irecv) error->all(FLERR,"Invalid partitions in processors part command"); if (isend-1 == universe->iworld) { if (send_to_partition >= 0) error->all(FLERR, "Sending partition in processors part command " "is already a sender"); send_to_partition = irecv-1; } if (irecv-1 == universe->iworld) { if (recv_from_partition >= 0) error->all(FLERR, "Receiving partition in processors part command " "is already a receiver"); recv_from_partition = isend-1; } // only receiver has otherflag dependency if (strcmp(arg[iarg+3],"multiple") == 0) { if (universe->iworld == irecv-1) { otherflag = 1; other_style = MULTIPLE; } } else error->all(FLERR,"Illegal processors command"); iarg += 4; } else if (strcmp(arg[iarg],"file") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal processors command"); delete [] outfile; int n = strlen(arg[iarg+1]) + 1; outfile = new char[n]; strcpy(outfile,arg[iarg+1]); iarg += 2; } else error->all(FLERR,"Illegal processors command"); } // error checks if (gridflag == NUMA && mapflag != CART) error->all(FLERR,"Processors grid numa and map style are incompatible"); if (otherflag && (gridflag == NUMA || gridflag == CUSTOM)) error->all(FLERR, "Processors part option and grid style are incompatible"); } /* ---------------------------------------------------------------------- create a 3d grid of procs based on Nprocs and box size & shape map processors to grid, setup xyz split for a uniform grid ------------------------------------------------------------------------- */ void Comm::set_proc_grid(int outflag) { // recv 3d proc grid of another partition if my 3d grid depends on it if (recv_from_partition >= 0) { if (me == 0) { MPI_Recv(other_procgrid,3,MPI_INT, universe->root_proc[recv_from_partition],0, universe->uworld,MPI_STATUS_IGNORE); MPI_Recv(other_coregrid,3,MPI_INT, universe->root_proc[recv_from_partition],0, universe->uworld,MPI_STATUS_IGNORE); } MPI_Bcast(other_procgrid,3,MPI_INT,0,world); MPI_Bcast(other_coregrid,3,MPI_INT,0,world); } // create ProcMap class to create 3d grid and map procs to it ProcMap *pmap = new ProcMap(lmp); // create 3d grid of processors // produces procgrid and coregrid (if relevant) if (gridflag == ONELEVEL) { pmap->onelevel_grid(nprocs,user_procgrid,procgrid, otherflag,other_style,other_procgrid,other_coregrid); } else if (gridflag == TWOLEVEL) { pmap->twolevel_grid(nprocs,user_procgrid,procgrid, ncores,user_coregrid,coregrid, otherflag,other_style,other_procgrid,other_coregrid); } else if (gridflag == NUMA) { pmap->numa_grid(nprocs,user_procgrid,procgrid,coregrid); } else if (gridflag == CUSTOM) { pmap->custom_grid(customfile,nprocs,user_procgrid,procgrid); } // error check on procgrid // should not be necessary due to ProcMap if (procgrid[0]*procgrid[1]*procgrid[2] != nprocs) error->all(FLERR,"Bad grid of processors"); if (domain->dimension == 2 && procgrid[2] != 1) error->all(FLERR,"Processor count in z must be 1 for 2d simulation"); // grid2proc[i][j][k] = proc that owns i,j,k location in 3d grid if (grid2proc) memory->destroy(grid2proc); memory->create(grid2proc,procgrid[0],procgrid[1],procgrid[2], "comm:grid2proc"); // map processor IDs to 3d processor grid // produces myloc, procneigh, grid2proc if (gridflag == ONELEVEL) { if (mapflag == CART) pmap->cart_map(0,procgrid,myloc,procneigh,grid2proc); else if (mapflag == CARTREORDER) pmap->cart_map(1,procgrid,myloc,procneigh,grid2proc); else if (mapflag == XYZ) pmap->xyz_map(xyz,procgrid,myloc,procneigh,grid2proc); } else if (gridflag == TWOLEVEL) { if (mapflag == CART) pmap->cart_map(0,procgrid,ncores,coregrid,myloc,procneigh,grid2proc); else if (mapflag == CARTREORDER) pmap->cart_map(1,procgrid,ncores,coregrid,myloc,procneigh,grid2proc); else if (mapflag == XYZ) pmap->xyz_map(xyz,procgrid,ncores,coregrid,myloc,procneigh,grid2proc); } else if (gridflag == NUMA) { pmap->numa_map(0,coregrid,myloc,procneigh,grid2proc); } else if (gridflag == CUSTOM) { pmap->custom_map(procgrid,myloc,procneigh,grid2proc); } // print 3d grid info to screen and logfile if (outflag && me == 0) { if (screen) { fprintf(screen," %d by %d by %d MPI processor grid\n", procgrid[0],procgrid[1],procgrid[2]); if (gridflag == NUMA || gridflag == TWOLEVEL) fprintf(screen," %d by %d by %d core grid within node\n", coregrid[0],coregrid[1],coregrid[2]); } if (logfile) { fprintf(logfile," %d by %d by %d MPI processor grid\n", procgrid[0],procgrid[1],procgrid[2]); if (gridflag == NUMA || gridflag == TWOLEVEL) fprintf(logfile," %d by %d by %d core grid within node\n", coregrid[0],coregrid[1],coregrid[2]); } } // print 3d grid details to outfile if (outfile) pmap->output(outfile,procgrid,grid2proc); // free ProcMap class delete pmap; // set xsplit,ysplit,zsplit for uniform spacings memory->destroy(xsplit); memory->destroy(ysplit); memory->destroy(zsplit); memory->create(xsplit,procgrid[0]+1,"comm:xsplit"); memory->create(ysplit,procgrid[1]+1,"comm:ysplit"); memory->create(zsplit,procgrid[2]+1,"comm:zsplit"); for (int i = 0; i < procgrid[0]; i++) xsplit[i] = i * 1.0/procgrid[0]; for (int i = 0; i < procgrid[1]; i++) ysplit[i] = i * 1.0/procgrid[1]; for (int i = 0; i < procgrid[2]; i++) zsplit[i] = i * 1.0/procgrid[2]; xsplit[procgrid[0]] = ysplit[procgrid[1]] = zsplit[procgrid[2]] = 1.0; // set lamda box params after procs are assigned // only set once unless load-balancing occurs if (domain->triclinic) domain->set_lamda_box(); // send my 3d proc grid to another partition if requested if (send_to_partition >= 0) { if (me == 0) { MPI_Send(procgrid,3,MPI_INT, universe->root_proc[send_to_partition],0, universe->uworld); MPI_Send(coregrid,3,MPI_INT, universe->root_proc[send_to_partition],0, universe->uworld); } } } /* ---------------------------------------------------------------------- determine which proc owns atom with coord x[3] based on current decomp x will be in box (orthogonal) or lamda coords (triclinic) if layout = UNIFORM, calculate owning proc directly if layout = NONUNIFORM, iteratively find owning proc via binary search if layout = TILED, CommTiled has its own method return owning proc ID via grid2proc return igx,igy,igz = logical grid loc of owing proc within 3d grid of procs ------------------------------------------------------------------------- */ int Comm::coord2proc(double *x, int &igx, int &igy, int &igz) { double *prd = domain->prd; double *boxlo = domain->boxlo; // initialize triclinic b/c coord2proc can be called before Comm::init() // via Irregular::migrate_atoms() triclinic = domain->triclinic; if (layout == LAYOUT_UNIFORM) { if (triclinic == 0) { igx = static_cast (procgrid[0] * (x[0]-boxlo[0]) / prd[0]); igy = static_cast (procgrid[1] * (x[1]-boxlo[1]) / prd[1]); igz = static_cast (procgrid[2] * (x[2]-boxlo[2]) / prd[2]); } else { igx = static_cast (procgrid[0] * x[0]); igy = static_cast (procgrid[1] * x[1]); igz = static_cast (procgrid[2] * x[2]); } } else if (layout == LAYOUT_NONUNIFORM) { if (triclinic == 0) { igx = binary((x[0]-boxlo[0])/prd[0],procgrid[0],xsplit); igy = binary((x[1]-boxlo[1])/prd[1],procgrid[1],ysplit); igz = binary((x[2]-boxlo[2])/prd[2],procgrid[2],zsplit); } else { igx = binary(x[0],procgrid[0],xsplit); igy = binary(x[1],procgrid[1],ysplit); igz = binary(x[2],procgrid[2],zsplit); } } if (igx < 0) igx = 0; if (igx >= procgrid[0]) igx = procgrid[0] - 1; if (igy < 0) igy = 0; if (igy >= procgrid[1]) igy = procgrid[1] - 1; if (igz < 0) igz = 0; if (igz >= procgrid[2]) igz = procgrid[2] - 1; return grid2proc[igx][igy][igz]; } /* ---------------------------------------------------------------------- binary search for value in N-length ascending vec value may be outside range of vec limits always return index from 0 to N-1 inclusive return 0 if value < vec[0] reutrn N-1 if value >= vec[N-1] return index = 1 to N-2 if vec[index] <= value < vec[index+1] ------------------------------------------------------------------------- */ int Comm::binary(double value, int n, double *vec) { int lo = 0; int hi = n-1; if (value < vec[lo]) return lo; if (value >= vec[hi]) return hi; // insure vec[lo] <= value < vec[hi] at every iteration // done when lo,hi are adjacent int index = (lo+hi)/2; while (lo < hi-1) { if (value < vec[index]) hi = index; else if (value >= vec[index]) lo = index; index = (lo+hi)/2; } return index; } /* ---------------------------------------------------------------------- communicate inbuf around full ring of processors with messtag nbytes = size of inbuf = n datums * nper bytes callback() is invoked to allow caller to process/update each proc's inbuf if self=1 (default), then callback() is invoked on final iteration using original inbuf, which may have been updated for non-NULL outbuf, final updated inbuf is copied to it ok to specify outbuf = inbuf ------------------------------------------------------------------------- */ void Comm::ring(int n, int nper, void *inbuf, int messtag, void (*callback)(int, char *), void *outbuf, int self) { MPI_Request request; MPI_Status status; int nbytes = n*nper; int maxbytes; MPI_Allreduce(&nbytes,&maxbytes,1,MPI_INT,MPI_MAX,world); // no need to communicate without data if (maxbytes == 0) return; char *buf,*bufcopy; memory->create(buf,maxbytes,"comm:buf"); memory->create(bufcopy,maxbytes,"comm:bufcopy"); memcpy(buf,inbuf,nbytes); int next = me + 1; int prev = me - 1; if (next == nprocs) next = 0; if (prev < 0) prev = nprocs - 1; for (int loop = 0; loop < nprocs; loop++) { if (me != next) { MPI_Irecv(bufcopy,maxbytes,MPI_CHAR,prev,messtag,world,&request); MPI_Send(buf,nbytes,MPI_CHAR,next,messtag,world); MPI_Wait(&request,&status); MPI_Get_count(&status,MPI_CHAR,&nbytes); memcpy(buf,bufcopy,nbytes); } if (self || loop < nprocs-1) callback(nbytes/nper,buf); } if (outbuf) memcpy(outbuf,buf,nbytes); memory->destroy(buf); memory->destroy(bufcopy); } /* ---------------------------------------------------------------------- proc 0 reads Nlines from file into buf and bcasts buf to all procs caller allocates buf to max size needed each line is terminated by newline, even if last line in file is not return 0 if successful, 1 if get EOF error before read is complete ------------------------------------------------------------------------- */ int Comm::read_lines_from_file(FILE *fp, int nlines, int maxline, char *buf) { int m; if (me == 0) { m = 0; for (int i = 0; i < nlines; i++) { if (!fgets(&buf[m],maxline,fp)) { m = 0; break; } m += strlen(&buf[m]); } if (m) { if (buf[m-1] != '\n') strcpy(&buf[m++],"\n"); m++; } } MPI_Bcast(&m,1,MPI_INT,0,world); if (m == 0) return 1; MPI_Bcast(buf,m,MPI_CHAR,0,world); return 0; } /* ---------------------------------------------------------------------- proc 0 reads Nlines from file into buf and bcasts buf to all procs caller allocates buf to max size needed each line is terminated by newline, even if last line in file is not return 0 if successful, 1 if get EOF error before read is complete ------------------------------------------------------------------------- */ int Comm::read_lines_from_file_universe(FILE *fp, int nlines, int maxline, char *buf) { int m; int me_universe = universe->me; MPI_Comm uworld = universe->uworld; if (me_universe == 0) { m = 0; for (int i = 0; i < nlines; i++) { if (!fgets(&buf[m],maxline,fp)) { m = 0; break; } m += strlen(&buf[m]); } if (m) { if (buf[m-1] != '\n') strcpy(&buf[m++],"\n"); m++; } } MPI_Bcast(&m,1,MPI_INT,0,uworld); if (m == 0) return 1; MPI_Bcast(buf,m,MPI_CHAR,0,uworld); return 0; } diff --git a/src/compute_coord_atom.cpp b/src/compute_coord_atom.cpp index 5747c869d..21744dcc9 100644 --- a/src/compute_coord_atom.cpp +++ b/src/compute_coord_atom.cpp @@ -1,226 +1,226 @@ /* ---------------------------------------------------------------------- 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 #include #include #include "compute_coord_atom.h" #include "atom.h" #include "update.h" #include "modify.h" #include "neighbor.h" #include "neigh_list.h" #include "neigh_request.h" #include "force.h" #include "pair.h" #include "comm.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ ComputeCoordAtom::ComputeCoordAtom(LAMMPS *lmp, int narg, char **arg) : Compute(lmp, narg, arg), typelo(NULL), typehi(NULL), cvec(NULL), carray(NULL) { if (narg < 4) error->all(FLERR,"Illegal compute coord/atom command"); double cutoff = force->numeric(FLERR,arg[3]); cutsq = cutoff*cutoff; ncol = narg-4 + 1; int ntypes = atom->ntypes; typelo = new int[ncol]; typehi = new int[ncol]; if (narg == 4) { ncol = 1; typelo[0] = 1; typehi[0] = ntypes; } else { ncol = 0; int iarg = 4; while (iarg < narg) { - force->bounds(arg[iarg],ntypes,typelo[ncol],typehi[ncol]); + force->bounds(FLERR,arg[iarg],ntypes,typelo[ncol],typehi[ncol]); if (typelo[ncol] > typehi[ncol]) error->all(FLERR,"Illegal compute coord/atom command"); ncol++; iarg++; } } peratom_flag = 1; if (ncol == 1) size_peratom_cols = 0; else size_peratom_cols = ncol; nmax = 0; } /* ---------------------------------------------------------------------- */ ComputeCoordAtom::~ComputeCoordAtom() { delete [] typelo; delete [] typehi; memory->destroy(cvec); memory->destroy(carray); } /* ---------------------------------------------------------------------- */ void ComputeCoordAtom::init() { if (force->pair == NULL) error->all(FLERR,"Compute coord/atom requires a pair style be defined"); if (sqrt(cutsq) > force->pair->cutforce) error->all(FLERR, "Compute coord/atom cutoff is longer than pairwise cutoff"); // need an occasional full neighbor list int irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->pair = 0; neighbor->requests[irequest]->compute = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->full = 1; neighbor->requests[irequest]->occasional = 1; int count = 0; for (int i = 0; i < modify->ncompute; i++) if (strcmp(modify->compute[i]->style,"coord/atom") == 0) count++; if (count > 1 && comm->me == 0) error->warning(FLERR,"More than one compute coord/atom"); } /* ---------------------------------------------------------------------- */ void ComputeCoordAtom::init_list(int id, NeighList *ptr) { list = ptr; } /* ---------------------------------------------------------------------- */ void ComputeCoordAtom::compute_peratom() { int i,j,m,ii,jj,inum,jnum,jtype,n; double xtmp,ytmp,ztmp,delx,dely,delz,rsq; int *ilist,*jlist,*numneigh,**firstneigh; double *count; invoked_peratom = update->ntimestep; // grow coordination array if necessary if (atom->nmax > nmax) { if (ncol == 1) { memory->destroy(cvec); nmax = atom->nmax; memory->create(cvec,nmax,"coord/atom:cvec"); vector_atom = cvec; } else { memory->destroy(carray); nmax = atom->nmax; memory->create(carray,nmax,ncol,"coord/atom:carray"); array_atom = carray; } } // invoke full neighbor list (will copy or build if necessary) neighbor->build_one(list); inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // compute coordination number(s) for each atom in group // use full neighbor list to count atoms less than cutoff double **x = atom->x; int *type = atom->type; int *mask = atom->mask; if (ncol == 1) { for (ii = 0; ii < inum; ii++) { i = ilist[ii]; if (mask[i] & groupbit) { xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; jlist = firstneigh[i]; jnum = numneigh[i]; n = 0; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; j &= NEIGHMASK; jtype = type[j]; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; if (rsq < cutsq && jtype >= typelo[0] && jtype <= typehi[0]) n++; } cvec[i] = n; } else cvec[i] = 0.0; } } else { for (ii = 0; ii < inum; ii++) { i = ilist[ii]; count = carray[i]; for (m = 0; m < ncol; m++) count[m] = 0.0; if (mask[i] & groupbit) { xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; j &= NEIGHMASK; jtype = type[j]; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; if (rsq < cutsq) { for (m = 0; m < ncol; m++) if (jtype >= typelo[m] && jtype <= typehi[m]) count[m] += 1.0; } } } } } } /* ---------------------------------------------------------------------- memory usage of local atom-based array ------------------------------------------------------------------------- */ double ComputeCoordAtom::memory_usage() { double bytes = ncol*nmax * sizeof(double); return bytes; } diff --git a/src/compute_rdf.cpp b/src/compute_rdf.cpp index 862450801..088639406 100644 --- a/src/compute_rdf.cpp +++ b/src/compute_rdf.cpp @@ -1,327 +1,327 @@ /* ---------------------------------------------------------------------- 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: Paul Crozier (SNL), Jeff Greathouse (SNL) ------------------------------------------------------------------------- */ #include #include #include #include "compute_rdf.h" #include "atom.h" #include "update.h" #include "force.h" #include "pair.h" #include "domain.h" #include "neighbor.h" #include "neigh_request.h" #include "neigh_list.h" #include "group.h" #include "math_const.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace MathConst; /* ---------------------------------------------------------------------- */ ComputeRDF::ComputeRDF(LAMMPS *lmp, int narg, char **arg) : Compute(lmp, narg, arg), rdfpair(NULL), nrdfpair(NULL), ilo(NULL), ihi(NULL), jlo(NULL), jhi(NULL), hist(NULL), histall(NULL), typecount(NULL), icount(NULL), jcount(NULL), duplicates(NULL) { if (narg < 4 || (narg-4) % 2) error->all(FLERR,"Illegal compute rdf command"); array_flag = 1; extarray = 0; nbin = force->inumeric(FLERR,arg[3]); if (nbin < 1) error->all(FLERR,"Illegal compute rdf command"); if (narg == 4) npairs = 1; else npairs = (narg-4)/2; size_array_rows = nbin; size_array_cols = 1 + 2*npairs; int ntypes = atom->ntypes; memory->create(rdfpair,npairs,ntypes+1,ntypes+1,"rdf:rdfpair"); memory->create(nrdfpair,ntypes+1,ntypes+1,"rdf:nrdfpair"); ilo = new int[npairs]; ihi = new int[npairs]; jlo = new int[npairs]; jhi = new int[npairs]; if (narg == 4) { ilo[0] = 1; ihi[0] = ntypes; jlo[0] = 1; jhi[0] = ntypes; npairs = 1; } else { npairs = 0; int iarg = 4; while (iarg < narg) { - force->bounds(arg[iarg],atom->ntypes,ilo[npairs],ihi[npairs]); - force->bounds(arg[iarg+1],atom->ntypes,jlo[npairs],jhi[npairs]); + force->bounds(FLERR,arg[iarg],atom->ntypes,ilo[npairs],ihi[npairs]); + force->bounds(FLERR,arg[iarg+1],atom->ntypes,jlo[npairs],jhi[npairs]); if (ilo[npairs] > ihi[npairs] || jlo[npairs] > jhi[npairs]) error->all(FLERR,"Illegal compute rdf command"); npairs++; iarg += 2; } } int i,j; for (i = 1; i <= ntypes; i++) for (j = 1; j <= ntypes; j++) nrdfpair[i][j] = 0; for (int m = 0; m < npairs; m++) for (i = ilo[m]; i <= ihi[m]; i++) for (j = jlo[m]; j <= jhi[m]; j++) rdfpair[nrdfpair[i][j]++][i][j] = m; memory->create(hist,npairs,nbin,"rdf:hist"); memory->create(histall,npairs,nbin,"rdf:histall"); memory->create(array,nbin,1+2*npairs,"rdf:array"); typecount = new int[ntypes+1]; icount = new int[npairs]; jcount = new int[npairs]; duplicates = new int[npairs]; } /* ---------------------------------------------------------------------- */ ComputeRDF::~ComputeRDF() { memory->destroy(rdfpair); memory->destroy(nrdfpair); delete [] ilo; delete [] ihi; delete [] jlo; delete [] jhi; memory->destroy(hist); memory->destroy(histall); memory->destroy(array); delete [] typecount; delete [] icount; delete [] jcount; delete [] duplicates; } /* ---------------------------------------------------------------------- */ void ComputeRDF::init() { int i,j,m; if (force->pair) delr = force->pair->cutforce / nbin; else error->all(FLERR,"Compute rdf requires a pair style be defined"); delrinv = 1.0/delr; // set 1st column of output array to bin coords for (int i = 0; i < nbin; i++) array[i][0] = (i+0.5) * delr; // count atoms of each type that are also in group int *mask = atom->mask; int *type = atom->type; int nlocal = atom->nlocal; int ntypes = atom->ntypes; for (i = 1; i <= ntypes; i++) typecount[i] = 0; for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) typecount[type[i]]++; // icount = # of I atoms participating in I,J pairs for each histogram // jcount = # of J atoms participating in I,J pairs for each histogram // duplicates = # of atoms in both groups I and J for each histogram for (m = 0; m < npairs; m++) { icount[m] = 0; for (i = ilo[m]; i <= ihi[m]; i++) icount[m] += typecount[i]; jcount[m] = 0; for (i = jlo[m]; i <= jhi[m]; i++) jcount[m] += typecount[i]; duplicates[m] = 0; for (i = ilo[m]; i <= ihi[m]; i++) for (j = jlo[m]; j <= jhi[m]; j++) if (i == j) duplicates[m] += typecount[i]; } int *scratch = new int[npairs]; MPI_Allreduce(icount,scratch,npairs,MPI_INT,MPI_SUM,world); for (i = 0; i < npairs; i++) icount[i] = scratch[i]; MPI_Allreduce(jcount,scratch,npairs,MPI_INT,MPI_SUM,world); for (i = 0; i < npairs; i++) jcount[i] = scratch[i]; MPI_Allreduce(duplicates,scratch,npairs,MPI_INT,MPI_SUM,world); for (i = 0; i < npairs; i++) duplicates[i] = scratch[i]; delete [] scratch; // need an occasional half neighbor list int irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->pair = 0; neighbor->requests[irequest]->compute = 1; neighbor->requests[irequest]->occasional = 1; } /* ---------------------------------------------------------------------- */ void ComputeRDF::init_list(int id, NeighList *ptr) { list = ptr; } /* ---------------------------------------------------------------------- */ void ComputeRDF::compute_array() { int i,j,m,ii,jj,inum,jnum,itype,jtype,ipair,jpair,ibin,ihisto; double xtmp,ytmp,ztmp,delx,dely,delz,r; int *ilist,*jlist,*numneigh,**firstneigh; double factor_lj,factor_coul; invoked_array = update->ntimestep; // invoke half neighbor list (will copy or build if necessary) neighbor->build_one(list); inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // zero the histogram counts for (i = 0; i < npairs; i++) for (j = 0; j < nbin; j++) hist[i][j] = 0; // tally the RDF // both atom i and j must be in fix group // itype,jtype must have been specified by user // consider I,J as one interaction even if neighbor pair is stored on 2 procs // tally I,J pair each time I is central atom, and each time J is central double **x = atom->x; int *type = atom->type; int *mask = atom->mask; int nlocal = atom->nlocal; double *special_coul = force->special_coul; double *special_lj = force->special_lj; int newton_pair = force->newton_pair; for (ii = 0; ii < inum; ii++) { i = ilist[ii]; if (!(mask[i] & groupbit)) continue; 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; // if both weighting factors are 0, skip this pair // could be 0 and still be in neigh list for long-range Coulombics // want consistency with non-charged pairs which wouldn't be in list if (factor_lj == 0.0 && factor_coul == 0.0) continue; if (!(mask[j] & groupbit)) continue; jtype = type[j]; ipair = nrdfpair[itype][jtype]; jpair = nrdfpair[jtype][itype]; if (!ipair && !jpair) continue; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; r = sqrt(delx*delx + dely*dely + delz*delz); ibin = static_cast (r*delrinv); if (ibin >= nbin) continue; if (ipair) for (ihisto = 0; ihisto < ipair; ihisto++) hist[rdfpair[ihisto][itype][jtype]][ibin] += 1.0; if (newton_pair || j < nlocal) { if (jpair) for (ihisto = 0; ihisto < jpair; ihisto++) hist[rdfpair[ihisto][jtype][itype]][ibin] += 1.0; } } } // sum histograms across procs MPI_Allreduce(hist[0],histall[0],npairs*nbin,MPI_DOUBLE,MPI_SUM,world); // convert counts to g(r) and coord(r) and copy into output array // vfrac = fraction of volume in shell m // npairs = number of pairs, corrected for duplicates // duplicates = pairs in which both atoms are the same double constant,vfrac,gr,ncoord,rlower,rupper,normfac; if (domain->dimension == 3) { constant = 4.0*MY_PI / (3.0*domain->xprd*domain->yprd*domain->zprd); for (m = 0; m < npairs; m++) { normfac = (icount[m] > 0) ? static_cast(jcount[m]) - static_cast(duplicates[m])/icount[m] : 0.0; ncoord = 0.0; for (ibin = 0; ibin < nbin; ibin++) { rlower = ibin*delr; rupper = (ibin+1)*delr; vfrac = constant * (rupper*rupper*rupper - rlower*rlower*rlower); if (vfrac * normfac != 0.0) gr = histall[m][ibin] / (vfrac * normfac * icount[m]); else gr = 0.0; if (icount[m] != 0) ncoord += gr * vfrac * normfac; array[ibin][1+2*m] = gr; array[ibin][2+2*m] = ncoord; } } } else { constant = MY_PI / (domain->xprd*domain->yprd); for (m = 0; m < npairs; m++) { ncoord = 0.0; normfac = (icount[m] > 0) ? static_cast(jcount[m]) - static_cast(duplicates[m])/icount[m] : 0.0; for (ibin = 0; ibin < nbin; ibin++) { rlower = ibin*delr; rupper = (ibin+1)*delr; vfrac = constant * (rupper*rupper - rlower*rlower); if (vfrac * normfac != 0.0) gr = histall[m][ibin] / (vfrac * normfac * icount[m]); else gr = 0.0; if (icount[m] != 0) ncoord += gr * vfrac * normfac; array[ibin][1+2*m] = gr; array[ibin][2+2*m] = ncoord; } } } } diff --git a/src/delete_bonds.cpp b/src/delete_bonds.cpp index 3871641e0..97eb1c09a 100644 --- a/src/delete_bonds.cpp +++ b/src/delete_bonds.cpp @@ -1,591 +1,591 @@ /* ---------------------------------------------------------------------- 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 #include #include #include "delete_bonds.h" #include "atom.h" #include "atom_vec.h" #include "domain.h" #include "neighbor.h" #include "comm.h" #include "force.h" #include "group.h" #include "special.h" #include "error.h" using namespace LAMMPS_NS; enum{MULTI,ATOM,BOND,ANGLE,DIHEDRAL,IMPROPER,STATS}; /* ---------------------------------------------------------------------- */ DeleteBonds::DeleteBonds(LAMMPS *lmp) : Pointers(lmp) {} /* ---------------------------------------------------------------------- */ void DeleteBonds::command(int narg, char **arg) { if (domain->box_exist == 0) error->all(FLERR,"Delete_bonds command before simulation box is defined"); if (atom->natoms == 0) error->all(FLERR,"Delete_bonds command with no atoms existing"); if (atom->molecular != 1) error->all(FLERR,"Cannot use delete_bonds with non-molecular system"); if (narg < 2) error->all(FLERR,"Illegal delete_bonds command"); // init entire system since comm->borders is done // comm::init needs neighbor::init needs pair::init needs kspace::init, etc if (comm->me == 0 && screen) fprintf(screen,"System init for delete_bonds ...\n"); lmp->init(); if (comm->me == 0 && screen) fprintf(screen,"Deleting bonds ...\n"); // identify group int igroup = group->find(arg[0]); if (igroup == -1) error->all(FLERR,"Cannot find delete_bonds group ID"); int groupbit = group->bitmask[igroup]; // set style and which = type value int style = -1; if (strcmp(arg[1],"multi") == 0) style = MULTI; else if (strcmp(arg[1],"atom") == 0) style = ATOM; else if (strcmp(arg[1],"bond") == 0) style = BOND; else if (strcmp(arg[1],"angle") == 0) style = ANGLE; else if (strcmp(arg[1],"dihedral") == 0) style = DIHEDRAL; else if (strcmp(arg[1],"improper") == 0) style = IMPROPER; else if (strcmp(arg[1],"stats") == 0) style = STATS; else error->all(FLERR,"Illegal delete_bonds command"); // setup list of types (atom,bond,etc) to consider - // use force->bounds() to allow setting of range of types + // use force->bounds(FLERR,) to allow setting of range of types // range can be 0 to ntypes inclusive int *tlist = NULL; int iarg = 2; if (style != MULTI && style != STATS) { if (narg < 3) error->all(FLERR,"Illegal delete_bonds command"); int n = -1; if (style == ATOM) n = atom->ntypes; if (style == BOND) n = atom->nbondtypes; if (style == ANGLE) n = atom->nangletypes; if (style == DIHEDRAL) n = atom->ndihedraltypes; if (style == IMPROPER) n = atom->nimpropertypes; tlist = new int[n+1]; for (int i = 0; i <= n; i++) tlist[i] = 0; int nlo,nhi; - force->bounds(arg[2],n,nlo,nhi,0); + force->bounds(FLERR,arg[2],n,nlo,nhi,0); for (int i = nlo; i <= nhi; i++) tlist[i] = 1; iarg++; } // grab optional keywords int any_flag = 0; int undo_flag = 0; int remove_flag = 0; int special_flag = 0; int induce_flag = 0; while (iarg < narg) { if (strcmp(arg[iarg],"any") == 0) any_flag = 1; else if (strcmp(arg[iarg],"undo") == 0) undo_flag = 1; else if (strcmp(arg[iarg],"remove") == 0) remove_flag = 1; else if (strcmp(arg[iarg],"special") == 0) special_flag = 1; else if (strcmp(arg[iarg],"induce") == 0) induce_flag = 1; else error->all(FLERR,"Illegal delete_bonds command"); iarg++; } // border swap to insure type and mask is current for off-proc atoms // enforce PBC before in case atoms are outside box if (domain->triclinic) domain->x2lamda(atom->nlocal); domain->pbc(); domain->reset_box(); comm->setup(); comm->exchange(); comm->borders(); if (domain->triclinic) domain->lamda2x(atom->nlocal+atom->nghost); // set topology interactions either off or on // criteria for an interaction to potentially be changed (set flag = 1) // all atoms or any atom in interaction must be in group, based on any_flag // for style = MULTI, all bond/angle/dihedral/improper, no other criteria // for style = ATOM, same as MULTI, plus at least one atom is specified type // for style = BOND/ANGLE/DIHEDRAL/IMPROPER, interaction is specified type // for style = STATS only compute stats, flag is always 0 // if flag = 1 // set interaction type negative if undo_flag = 0 // set interaction type positive if undo_flag = 1 int *mask = atom->mask; int *type = atom->type; int nlocal = atom->nlocal; int i,m,n,consider,flag,itype; int atom1,atom2,atom3,atom4; if (atom->avec->bonds_allow && (style == BOND || style == MULTI || style == ATOM)) { int *num_bond = atom->num_bond; int **bond_type = atom->bond_type; for (i = 0; i < nlocal; i++) { for (m = 0; m < num_bond[i]; m++) { atom1 = atom->map(atom->bond_atom[i][m]); if (atom1 == -1) error->one(FLERR,"Bond atom missing in delete_bonds"); consider = 0; if (!any_flag && mask[i] & groupbit && mask[atom1] & groupbit) consider = 1; if (any_flag && (mask[i] & groupbit || mask[atom1] & groupbit)) consider = 1; if (consider) { flag = 0; if (style == MULTI) flag = 1; else if (style == ATOM) { if (tlist[type[i]] || tlist[type[atom1]]) flag = 1; } else if (style == BOND) { itype = abs(bond_type[i][m]); if (tlist[itype]) flag = 1; } if (flag) { if (undo_flag == 0 && bond_type[i][m] > 0) bond_type[i][m] = -bond_type[i][m]; if (undo_flag == 1 && bond_type[i][m] < 0) bond_type[i][m] = -bond_type[i][m]; } } } } } if (atom->avec->angles_allow && (style == ANGLE || style == MULTI || style == ATOM)) { int *num_angle = atom->num_angle; int **angle_type = atom->angle_type; for (i = 0; i < nlocal; i++) { for (m = 0; m < num_angle[i]; m++) { atom1 = atom->map(atom->angle_atom1[i][m]); atom2 = atom->map(atom->angle_atom2[i][m]); atom3 = atom->map(atom->angle_atom3[i][m]); if (atom1 == -1 || atom2 == -1 || atom3 == -1) error->one(FLERR,"Angle atom missing in delete_bonds"); consider = 0; if (!any_flag && mask[atom1] & groupbit && mask[atom2] & groupbit && mask[atom3] & groupbit) consider = 1; if (any_flag && (mask[atom1] & groupbit || mask[atom2] & groupbit || mask[atom3] & groupbit)) consider = 1; if (consider) { flag = 0; if (style == MULTI) flag = 1; else if (style == ATOM) { if (tlist[type[atom1]] || tlist[type[atom2]] || tlist[type[atom3]]) flag = 1; } else if (style == ANGLE) { itype = abs(angle_type[i][m]); if (tlist[itype]) flag = 1; } if (flag) { if (undo_flag == 0 && angle_type[i][m] > 0) angle_type[i][m] = -angle_type[i][m]; if (undo_flag == 1 && angle_type[i][m] < 0) angle_type[i][m] = -angle_type[i][m]; } } } } } if (atom->avec->dihedrals_allow && (style == DIHEDRAL || style == MULTI || style == ATOM)) { int *num_dihedral = atom->num_dihedral; int **dihedral_type = atom->dihedral_type; for (i = 0; i < nlocal; i++) { for (m = 0; m < num_dihedral[i]; m++) { atom1 = atom->map(atom->dihedral_atom1[i][m]); atom2 = atom->map(atom->dihedral_atom2[i][m]); atom3 = atom->map(atom->dihedral_atom3[i][m]); atom4 = atom->map(atom->dihedral_atom4[i][m]); if (atom1 == -1 || atom2 == -1 || atom3 == -1 || atom4 == -1) error->one(FLERR,"Dihedral atom missing in delete_bonds"); consider = 0; if (!any_flag && mask[atom1] & groupbit && mask[atom2] & groupbit && mask[atom3] & groupbit && mask[atom4] & groupbit) consider = 1; if (any_flag && (mask[atom1] & groupbit || mask[atom2] & groupbit || mask[atom3] & groupbit || mask[atom4] & groupbit)) consider = 1; if (consider) { flag = 0; if (style == MULTI) flag = 1; else if (style == ATOM) { if (tlist[type[atom1]] || tlist[type[atom2]] || tlist[type[atom3]] || tlist[type[atom4]]) flag = 1; } else if (style == DIHEDRAL) { itype = abs(dihedral_type[i][m]); if (tlist[itype]) flag = 1; } if (flag) { if (undo_flag == 0 && dihedral_type[i][m] > 0) dihedral_type[i][m] = -dihedral_type[i][m]; if (undo_flag == 1 && dihedral_type[i][m] < 0) dihedral_type[i][m] = -dihedral_type[i][m]; } } } } } if (atom->avec->impropers_allow && (style == IMPROPER || style == MULTI || style == ATOM)) { int *num_improper = atom->num_improper; int **improper_type = atom->improper_type; for (i = 0; i < nlocal; i++) { for (m = 0; m < num_improper[i]; m++) { atom1 = atom->map(atom->improper_atom1[i][m]); atom2 = atom->map(atom->improper_atom2[i][m]); atom3 = atom->map(atom->improper_atom3[i][m]); atom4 = atom->map(atom->improper_atom4[i][m]); if (atom1 == -1 || atom2 == -1 || atom3 == -1 || atom4 == -1) error->one(FLERR,"Improper atom missing in delete_bonds"); consider = 0; if (!any_flag && mask[atom1] & groupbit && mask[atom2] & groupbit && mask[atom3] & groupbit && mask[atom4] & groupbit) consider = 1; if (any_flag && (mask[atom1] & groupbit || mask[atom2] & groupbit || mask[atom3] & groupbit || mask[atom4] & groupbit)) consider = 1; if (consider) { flag = 0; if (style == MULTI) flag = 1; else if (style == ATOM) { if (tlist[type[atom1]] || tlist[type[atom2]] || tlist[type[atom3]] || tlist[type[atom4]]) flag = 1; } else if (style == IMPROPER) { itype = abs(improper_type[i][m]); if (tlist[itype]) flag = 1; } if (flag) { if (undo_flag == 0 && improper_type[i][m] > 0) improper_type[i][m] = -improper_type[i][m]; if (undo_flag == 1 && improper_type[i][m] < 0) improper_type[i][m] = -improper_type[i][m]; } } } } } delete [] tlist; // induce turn off of angles, dihedral, impropers due to turned off bonds // induce turn off of dihedrals due to turned off angles // all atoms or any atom in interaction must be in group, based on any_flag if (induce_flag) { // circulate list of turned off bonds around ring of procs // circulate list of turned off angles around ring of procs } // remove interactions if requested // all atoms or any atom in interaction must be in group, based on any_flag if (remove_flag) { if (atom->avec->bonds_allow) { for (i = 0; i < nlocal; i++) { m = 0; while (m < atom->num_bond[i]) { if (atom->bond_type[i][m] <= 0) { atom1 = atom->map(atom->bond_atom[i][m]); flag = 0; if (!any_flag && mask[i] & groupbit && mask[atom1] & groupbit) flag = 1; if (any_flag && (mask[i] & groupbit || mask[atom1] & groupbit)) flag = 1; if (flag) { n = atom->num_bond[i]; atom->bond_type[i][m] = atom->bond_type[i][n-1]; atom->bond_atom[i][m] = atom->bond_atom[i][n-1]; atom->num_bond[i]--; } else m++; } else m++; } } } if (atom->avec->angles_allow) { for (i = 0; i < nlocal; i++) { m = 0; while (m < atom->num_angle[i]) { if (atom->angle_type[i][m] <= 0) { atom1 = atom->map(atom->angle_atom1[i][m]); atom2 = atom->map(atom->angle_atom2[i][m]); atom3 = atom->map(atom->angle_atom3[i][m]); flag = 0; if (!any_flag && mask[atom1] & groupbit && mask[atom2] & groupbit && mask[atom3] & groupbit) flag = 1; if (any_flag && (mask[atom1] & groupbit || mask[atom2] & groupbit || mask[atom3] & groupbit)) flag = 1; if (flag) { n = atom->num_angle[i]; atom->angle_type[i][m] = atom->angle_type[i][n-1]; atom->angle_atom1[i][m] = atom->angle_atom1[i][n-1]; atom->angle_atom2[i][m] = atom->angle_atom2[i][n-1]; atom->angle_atom3[i][m] = atom->angle_atom3[i][n-1]; atom->num_angle[i]--; } else m++; } else m++; } } } if (atom->avec->dihedrals_allow) { for (i = 0; i < nlocal; i++) { m = 0; while (m < atom->num_dihedral[i]) { if (atom->dihedral_type[i][m] <= 0) { atom1 = atom->map(atom->dihedral_atom1[i][m]); atom2 = atom->map(atom->dihedral_atom2[i][m]); atom3 = atom->map(atom->dihedral_atom3[i][m]); atom4 = atom->map(atom->dihedral_atom4[i][m]); flag = 0; if (!any_flag && mask[atom1] & groupbit && mask[atom2] & groupbit && mask[atom3] & groupbit && mask[atom4] & groupbit) flag = 1; if (any_flag && (mask[atom1] & groupbit || mask[atom2] & groupbit || mask[atom3] & groupbit || mask[atom4] & groupbit)) flag = 1; if (flag) { n = atom->num_dihedral[i]; atom->dihedral_type[i][m] = atom->dihedral_type[i][n-1]; atom->dihedral_atom1[i][m] = atom->dihedral_atom1[i][n-1]; atom->dihedral_atom2[i][m] = atom->dihedral_atom2[i][n-1]; atom->dihedral_atom3[i][m] = atom->dihedral_atom3[i][n-1]; atom->dihedral_atom4[i][m] = atom->dihedral_atom4[i][n-1]; atom->num_dihedral[i]--; } else m++; } else m++; } } } if (atom->avec->impropers_allow) { for (i = 0; i < nlocal; i++) { m = 0; while (m < atom->num_improper[i]) { if (atom->improper_type[i][m] <= 0) { atom1 = atom->map(atom->improper_atom1[i][m]); atom2 = atom->map(atom->improper_atom2[i][m]); atom3 = atom->map(atom->improper_atom3[i][m]); atom4 = atom->map(atom->improper_atom4[i][m]); flag = 0; if (!any_flag && mask[atom1] & groupbit && mask[atom2] & groupbit && mask[atom3] & groupbit && mask[atom4] & groupbit) flag = 1; if (any_flag && (mask[atom1] & groupbit || mask[atom2] & groupbit || mask[atom3] & groupbit || mask[atom4] & groupbit)) flag = 1; if (flag) { n = atom->num_improper[i]; atom->improper_type[i][m] = atom->improper_type[i][n-1]; atom->improper_atom1[i][m] = atom->improper_atom1[i][n-1]; atom->improper_atom2[i][m] = atom->improper_atom2[i][n-1]; atom->improper_atom3[i][m] = atom->improper_atom3[i][n-1]; atom->improper_atom4[i][m] = atom->improper_atom4[i][n-1]; atom->num_improper[i]--; } else m++; } else m++; } } } } // if interactions were removed, recompute global counts if (remove_flag) { if (atom->avec->bonds_allow) { bigint nbonds = 0; for (i = 0; i < nlocal; i++) nbonds += atom->num_bond[i]; MPI_Allreduce(&nbonds,&atom->nbonds,1,MPI_LMP_BIGINT, MPI_SUM,world); if (force->newton_bond == 0) atom->nbonds /= 2; } if (atom->avec->angles_allow) { bigint nangles = 0; for (i = 0; i < nlocal; i++) nangles += atom->num_angle[i]; MPI_Allreduce(&nangles,&atom->nangles,1,MPI_LMP_BIGINT, MPI_SUM,world); if (force->newton_bond == 0) atom->nangles /= 3; } if (atom->avec->dihedrals_allow) { bigint ndihedrals = 0; for (i = 0; i < nlocal; i++) ndihedrals += atom->num_dihedral[i]; MPI_Allreduce(&ndihedrals,&atom->ndihedrals, 1,MPI_LMP_BIGINT,MPI_SUM,world); if (force->newton_bond == 0) atom->ndihedrals /= 4; } if (atom->avec->impropers_allow) { bigint nimpropers = 0; for (i = 0; i < nlocal; i++) nimpropers += atom->num_improper[i]; MPI_Allreduce(&nimpropers,&atom->nimpropers, 1,MPI_LMP_BIGINT,MPI_SUM,world); if (force->newton_bond == 0) atom->nimpropers /= 4; } } // compute and print stats bigint tmp; bigint bond_on,bond_off; bigint angle_on,angle_off; bigint dihedral_on,dihedral_off; bigint improper_on,improper_off; if (atom->avec->bonds_allow) { bond_on = bond_off = 0; for (i = 0; i < nlocal; i++) for (m = 0; m < atom->num_bond[i]; m++) if (atom->bond_type[i][m] > 0) bond_on++; else bond_off++; MPI_Allreduce(&bond_on,&tmp,1,MPI_LMP_BIGINT,MPI_SUM,world); bond_on = tmp; MPI_Allreduce(&bond_off,&tmp,1,MPI_LMP_BIGINT,MPI_SUM,world); bond_off = tmp; if (force->newton_bond == 0) { bond_on /= 2; bond_off /= 2; } } if (atom->avec->angles_allow) { angle_on = angle_off = 0; for (i = 0; i < nlocal; i++) for (m = 0; m < atom->num_angle[i]; m++) if (atom->angle_type[i][m] > 0) angle_on++; else angle_off++; MPI_Allreduce(&angle_on,&tmp,1,MPI_LMP_BIGINT,MPI_SUM,world); angle_on = tmp; MPI_Allreduce(&angle_off,&tmp,1,MPI_LMP_BIGINT,MPI_SUM,world); angle_off = tmp; if (force->newton_bond == 0) { angle_on /= 3; angle_off /= 3; } } if (atom->avec->dihedrals_allow) { dihedral_on = dihedral_off = 0; for (i = 0; i < nlocal; i++) for (m = 0; m < atom->num_dihedral[i]; m++) if (atom->dihedral_type[i][m] > 0) dihedral_on++; else dihedral_off++; MPI_Allreduce(&dihedral_on,&tmp,1,MPI_LMP_BIGINT,MPI_SUM,world); dihedral_on = tmp; MPI_Allreduce(&dihedral_off,&tmp,1,MPI_LMP_BIGINT,MPI_SUM,world); dihedral_off = tmp; if (force->newton_bond == 0) { dihedral_on /= 4; dihedral_off /= 4; } } if (atom->avec->impropers_allow) { improper_on = improper_off = 0; for (i = 0; i < nlocal; i++) for (m = 0; m < atom->num_improper[i]; m++) if (atom->improper_type[i][m] > 0) improper_on++; else improper_off++; MPI_Allreduce(&improper_on,&tmp,1,MPI_LMP_BIGINT,MPI_SUM,world); improper_on = tmp; MPI_Allreduce(&improper_off,&tmp,1,MPI_LMP_BIGINT,MPI_SUM,world); improper_off = tmp; if (force->newton_bond == 0) { improper_on /= 4; improper_off /= 4; } } if (comm->me == 0) { if (atom->avec->bonds_allow) { if (screen) fprintf(screen, " " BIGINT_FORMAT " total bonds, " BIGINT_FORMAT " turned on, " BIGINT_FORMAT " turned off\n", atom->nbonds,bond_on,bond_off); if (logfile) fprintf(logfile, " " BIGINT_FORMAT " total bonds, " BIGINT_FORMAT " turned on, " BIGINT_FORMAT " turned off\n", atom->nbonds,bond_on,bond_off); } if (atom->avec->angles_allow) { if (screen) fprintf(screen, " " BIGINT_FORMAT " total angles, " BIGINT_FORMAT " turned on, " BIGINT_FORMAT " turned off\n", atom->nangles,angle_on,angle_off); if (logfile) fprintf(logfile, " " BIGINT_FORMAT " total angles, " BIGINT_FORMAT " turned on, " BIGINT_FORMAT " turned off\n", atom->nangles,angle_on,angle_off); } if (atom->avec->dihedrals_allow) { if (screen) fprintf(screen, " " BIGINT_FORMAT " total dihedrals, " BIGINT_FORMAT " turned on, " BIGINT_FORMAT " turned off\n", atom->ndihedrals,dihedral_on,dihedral_off); if (logfile) fprintf(logfile, " " BIGINT_FORMAT " total dihedrals, " BIGINT_FORMAT " turned on, " BIGINT_FORMAT " turned off\n", atom->ndihedrals,dihedral_on,dihedral_off); } if (atom->avec->impropers_allow) { if (screen) fprintf(screen, " " BIGINT_FORMAT " total impropers, " BIGINT_FORMAT " turned on, " BIGINT_FORMAT " turned off\n", atom->nimpropers,improper_on,improper_off); if (logfile) fprintf(logfile, " " BIGINT_FORMAT " total impropers, " BIGINT_FORMAT " turned on, " BIGINT_FORMAT " turned off\n", atom->nimpropers,improper_on,improper_off); } } // re-compute special list if requested if (special_flag) { Special special(lmp); special.build(); } } diff --git a/src/dihedral_hybrid.cpp b/src/dihedral_hybrid.cpp index ed73351b3..0ae396b88 100644 --- a/src/dihedral_hybrid.cpp +++ b/src/dihedral_hybrid.cpp @@ -1,353 +1,353 @@ /* ---------------------------------------------------------------------- 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 #include #include #include "dihedral_hybrid.h" #include "atom.h" #include "neighbor.h" #include "domain.h" #include "comm.h" #include "force.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define EXTRA 1000 /* ---------------------------------------------------------------------- */ DihedralHybrid::DihedralHybrid(LAMMPS *lmp) : Dihedral(lmp) { nstyles = 0; } /* ---------------------------------------------------------------------- */ DihedralHybrid::~DihedralHybrid() { if (nstyles) { for (int i = 0; i < nstyles; i++) delete styles[i]; delete [] styles; for (int i = 0; i < nstyles; i++) delete [] keywords[i]; delete [] keywords; } if (allocated) { memory->destroy(setflag); memory->destroy(map); delete [] ndihedrallist; delete [] maxdihedral; for (int i = 0; i < nstyles; i++) memory->destroy(dihedrallist[i]); delete [] dihedrallist; } } /* ---------------------------------------------------------------------- */ void DihedralHybrid::compute(int eflag, int vflag) { int i,j,m,n; // save ptrs to original dihedrallist int ndihedrallist_orig = neighbor->ndihedrallist; int **dihedrallist_orig = neighbor->dihedrallist; // if this is re-neighbor step, create sub-style dihedrallists // ndihedrallist[] = length of each sub-style list // realloc sub-style dihedrallist if necessary // load sub-style dihedrallist with 5 values from original dihedrallist if (neighbor->ago == 0) { for (m = 0; m < nstyles; m++) ndihedrallist[m] = 0; for (i = 0; i < ndihedrallist_orig; i++) { m = map[dihedrallist_orig[i][4]]; if (m >= 0) ndihedrallist[m]++; } for (m = 0; m < nstyles; m++) { if (ndihedrallist[m] > maxdihedral[m]) { memory->destroy(dihedrallist[m]); maxdihedral[m] = ndihedrallist[m] + EXTRA; memory->create(dihedrallist[m],maxdihedral[m],5, "dihedral_hybrid:dihedrallist"); } ndihedrallist[m] = 0; } for (i = 0; i < ndihedrallist_orig; i++) { m = map[dihedrallist_orig[i][4]]; if (m < 0) continue; n = ndihedrallist[m]; dihedrallist[m][n][0] = dihedrallist_orig[i][0]; dihedrallist[m][n][1] = dihedrallist_orig[i][1]; dihedrallist[m][n][2] = dihedrallist_orig[i][2]; dihedrallist[m][n][3] = dihedrallist_orig[i][3]; dihedrallist[m][n][4] = dihedrallist_orig[i][4]; ndihedrallist[m]++; } } // call each sub-style's compute function // set neighbor->dihedrallist to sub-style dihedrallist before call // accumulate sub-style global/peratom energy/virial in hybrid if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; for (m = 0; m < nstyles; m++) { neighbor->ndihedrallist = ndihedrallist[m]; neighbor->dihedrallist = dihedrallist[m]; styles[m]->compute(eflag,vflag); if (eflag_global) energy += styles[m]->energy; if (vflag_global) for (n = 0; n < 6; n++) virial[n] += styles[m]->virial[n]; if (eflag_atom) { n = atom->nlocal; if (force->newton_bond) 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_bond) 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]; } } // restore ptrs to original dihedrallist neighbor->ndihedrallist = ndihedrallist_orig; neighbor->dihedrallist = dihedrallist_orig; } /* ---------------------------------------------------------------------- */ void DihedralHybrid::allocate() { allocated = 1; int n = atom->ndihedraltypes; memory->create(map,n+1,"dihedral:map"); memory->create(setflag,n+1,"dihedral:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; ndihedrallist = new int[nstyles]; maxdihedral = new int[nstyles]; dihedrallist = new int**[nstyles]; for (int m = 0; m < nstyles; m++) maxdihedral[m] = 0; for (int m = 0; m < nstyles; m++) dihedrallist[m] = NULL; } /* ---------------------------------------------------------------------- create one dihedral style for each arg in list ------------------------------------------------------------------------- */ void DihedralHybrid::settings(int narg, char **arg) { int i,m,istyle; if (narg < 1) error->all(FLERR,"Illegal dihedral_style command"); // delete old lists, since cannot just change settings if (nstyles) { for (int i = 0; i < nstyles; i++) delete styles[i]; delete [] styles; for (int i = 0; i < nstyles; i++) delete [] keywords[i]; delete [] keywords; } if (allocated) { memory->destroy(setflag); memory->destroy(map); delete [] ndihedrallist; delete [] maxdihedral; for (int i = 0; i < nstyles; i++) memory->destroy(dihedrallist[i]); delete [] dihedrallist; } allocated = 0; // count sub-styles by skipping numeric args // one exception is 1st arg of style "table", which is non-numeric word // need a better way to skip these exceptions nstyles = 0; i = 0; while (i < narg) { if (strcmp(arg[i],"table") == 0) i++; i++; while (i < narg && !isalpha(arg[i][0])) i++; nstyles++; } // allocate list of sub-styles styles = new Dihedral*[nstyles]; keywords = new char*[nstyles]; // allocate each sub-style and call its settings() with subset of args // allocate uses suffix, but don't store suffix version in keywords, // else syntax in coeff() will not match // define subset of args for a sub-style by skipping numeric args // one exception is 1st arg of style "table", which is non-numeric // 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,"Dihedral style hybrid cannot use " "same dihedral style twice"); if (strcmp(arg[i],"hybrid") == 0) error->all(FLERR, "Dihedral style hybrid cannot have hybrid as an argument"); if (strcmp(arg[i],"none") == 0) error->all(FLERR,"Dihedral style hybrid cannot have none as an argument"); styles[nstyles] = force->new_dihedral(arg[i],1,dummy); force->store_style(keywords[nstyles],arg[i],0); istyle = i; if (strcmp(arg[i],"table") == 0) i++; i++; while (i < narg && !isalpha(arg[i][0])) i++; styles[nstyles]->settings(i-istyle-1,&arg[istyle+1]); nstyles++; } } /* ---------------------------------------------------------------------- set coeffs for one type ---------------------------------------------------------------------- */ void DihedralHybrid::coeff(int narg, char **arg) { if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->ndihedraltypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->ndihedraltypes,ilo,ihi); // 2nd arg = dihedral sub-style name // allow for "none" or "skip" as valid sub-style name int m; for (m = 0; m < nstyles; m++) if (strcmp(arg[1],keywords[m]) == 0) break; int none = 0; int skip = 0; if (m == nstyles) { if (strcmp(arg[1],"none") == 0) none = 1; else if (strcmp(arg[1],"skip") == 0) none = skip = 1; else error->all(FLERR,"Dihedral coeff for hybrid has invalid style"); } // move 1st arg to 2nd arg // just copy ptrs, since arg[] points into original input line arg[1] = arg[0]; // invoke sub-style coeff() starting with 1st arg if (!none) styles[m]->coeff(narg-1,&arg[1]); // set setflag and which type maps to which sub-style // if sub-style is skip: auxiliary class2 setting in data file so ignore // if sub-style is none and not skip: set hybrid setflag, wipe out map for (int i = ilo; i <= ihi; i++) { if (skip) continue; else if (none) { setflag[i] = 1; map[i] = -1; } else { setflag[i] = styles[m]->setflag[i]; map[i] = m; } } } /* ---------------------------------------------------------------------- */ void DihedralHybrid::init_style() { for (int m = 0; m < nstyles; m++) if (styles[m]) styles[m]->init_style(); } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void DihedralHybrid::write_restart(FILE *fp) { fwrite(&nstyles,sizeof(int),1,fp); 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); } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void DihedralHybrid::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 Dihedral*[nstyles]; keywords = new char*[nstyles]; allocate(); 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_dihedral(keywords[m],0,dummy); } } /* ---------------------------------------------------------------------- memory usage ------------------------------------------------------------------------- */ double DihedralHybrid::memory_usage() { double bytes = maxeatom * sizeof(double); bytes += maxvatom*6 * sizeof(double); for (int m = 0; m < nstyles; m++) bytes += maxdihedral[m]*5 * sizeof(int); for (int m = 0; m < nstyles; m++) if (styles[m]) bytes += styles[m]->memory_usage(); return bytes; } diff --git a/src/dihedral_zero.cpp b/src/dihedral_zero.cpp index 1e4a4ab3a..9b0c569fc 100644 --- a/src/dihedral_zero.cpp +++ b/src/dihedral_zero.cpp @@ -1,122 +1,122 @@ /* ---------------------------------------------------------------------- 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: Carsten Svaneborg (SDU) ------------------------------------------------------------------------- */ #include #include #include #include "dihedral_zero.h" #include "atom.h" #include "force.h" #include "comm.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ DihedralZero::DihedralZero(LAMMPS *lmp) : Dihedral(lmp), coeffflag(1) {} /* ---------------------------------------------------------------------- */ DihedralZero::~DihedralZero() { if (allocated && !copymode) { memory->destroy(setflag); } } /* ---------------------------------------------------------------------- */ void DihedralZero::compute(int eflag, int vflag) { if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; } /* ---------------------------------------------------------------------- */ void DihedralZero::settings(int narg, char **arg) { if ((narg != 0) && (narg != 1)) error->all(FLERR,"Illegal dihedral_style command"); if (narg == 1) { if (strcmp("nocoeff",arg[0]) == 0) coeffflag=0; else error->all(FLERR,"Illegal dihedral_style command"); } } /* ---------------------------------------------------------------------- */ void DihedralZero::allocate() { allocated = 1; int n = atom->ndihedraltypes; memory->create(setflag,n+1,"dihedral:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one or more types ------------------------------------------------------------------------- */ void DihedralZero::coeff(int narg, char **arg) { if ((narg < 1) || (coeffflag && narg > 1)) error->all(FLERR,"Incorrect args for dihedral coefficients"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->ndihedraltypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->ndihedraltypes,ilo,ihi); int count = 0; for (int i = ilo; i <= ihi; i++) { setflag[i] = 1; count++; } if (count == 0) error->all(FLERR,"Incorrect args for dihedral coefficients"); } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void DihedralZero::write_restart(FILE *fp) {} /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void DihedralZero::read_restart(FILE *fp) { allocate(); for (int i = 1; i <= atom->ndihedraltypes; i++) setflag[i] = 1; } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void DihedralZero::write_data(FILE *fp) { for (int i = 1; i <= atom->ndihedraltypes; i++) fprintf(fp,"%d\n",i); } diff --git a/src/dump_image.cpp b/src/dump_image.cpp index fd3dbed9e..6d971d016 100644 --- a/src/dump_image.cpp +++ b/src/dump_image.cpp @@ -1,1376 +1,1376 @@ /* ---------------------------------------------------------------------- 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 #include #include #include #include "dump_image.h" #include "image.h" #include "atom.h" #include "atom_vec_line.h" #include "atom_vec_tri.h" #include "atom_vec_body.h" #include "body.h" #include "molecule.h" #include "domain.h" #include "group.h" #include "force.h" #include "comm.h" #include "modify.h" #include "fix.h" #include "input.h" #include "variable.h" #include "math_const.h" #include "math_extra.h" #include "error.h" #include "memory.h" using namespace LAMMPS_NS; using namespace MathConst; #define BIG 1.0e20 enum{NUMERIC,ATOM,TYPE,ELEMENT,ATTRIBUTE}; enum{SPHERE,LINE,TRI}; // also in some Body and Fix child classes enum{STATIC,DYNAMIC}; 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"); // force binary flag on to avoid corrupted output on Windows binary = 1; multifile_override = 0; // 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) > 4 && strcmp(&filename[n-4],".JPG") == 0) filetype = JPG; else if (strlen(filename) > 5 && strcmp(&filename[n-5],".jpeg") == 0) filetype = JPG; else if (strlen(filename) > 5 && strcmp(&filename[n-5],".JPEG") == 0) filetype = JPG; else if (strlen(filename) > 4 && strcmp(&filename[n-4],".png") == 0) filetype = PNG; else if (strlen(filename) > 4 && strcmp(&filename[n-4],".PNG") == 0) filetype = PNG; else filetype = PPM; #ifndef LAMMPS_JPEG if (filetype == JPG) error->all(FLERR,"Support for writing images in JPEG format not included"); #endif #ifndef LAMMPS_PNG if (filetype == PNG) error->all(FLERR,"Support for writing images in PNG format not included"); #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; // create Image class with single colormap for atoms // change defaults for 2d image = new Image(lmp,1); if (domain->dimension == 2) { image->theta = 0.0; image->phi = 0.0; image->up[0] = 0.0; image->up[1] = 1.0; image->up[2] = 0.0; } // set defaults for optional args atomflag = YES; lineflag = triflag = bodyflag = fixflag = NO; if (atom->nbondtypes == 0) bondflag = NO; else { bondflag = YES; bcolor = ATOM; bdiam = NUMERIC; bdiamvalue = 0.5; } char *fixID = NULL; thetastr = phistr = NULL; cflag = STATIC; cx = cy = cz = 0.5; cxstr = cystr = czstr = NULL; upxstr = upystr = upzstr = NULL; zoomstr = NULL; perspstr = NULL; boxflag = YES; boxdiam = 0.02; axesflag = NO; subboxflag = NO; // parse optional args int iarg = ioptional; while (iarg < narg) { 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],"adiam") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal dump image command"); adiam = NUMERIC; adiamvalue = force->numeric(FLERR,arg[iarg+1]); if (adiamvalue <= 0.0) 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 = force->numeric(FLERR,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],"line") == 0) { if (iarg+3 > narg) error->all(FLERR,"Illegal dump image command"); lineflag = YES; if (strcmp(arg[iarg+1],"type") == 0) lcolor = TYPE; else error->all(FLERR,"Illegal dump image command"); ldiam = NUMERIC; ldiamvalue = force->numeric(FLERR,arg[iarg+2]); iarg += 3; } else if (strcmp(arg[iarg],"tri") == 0) { if (iarg+4 > narg) error->all(FLERR,"Illegal dump image command"); triflag = YES; if (strcmp(arg[iarg+1],"type") == 0) tcolor = TYPE; else error->all(FLERR,"Illegal dump image command"); tstyle = force->inumeric(FLERR,arg[iarg+2]); tdiamvalue = force->numeric(FLERR,arg[iarg+3]); iarg += 4; } else if (strcmp(arg[iarg],"body") == 0) { if (iarg+4 > narg) error->all(FLERR,"Illegal dump image command"); bodyflag = YES; if (strcmp(arg[iarg+1],"type") == 0) bodycolor = TYPE; else error->all(FLERR,"Illegal dump image command"); bodyflag1 = force->numeric(FLERR,arg[iarg+2]); bodyflag2 = force->numeric(FLERR,arg[iarg+3]); iarg += 4; } else if (strcmp(arg[iarg],"fix") == 0) { if (iarg+5 > narg) error->all(FLERR,"Illegal dump image command"); fixflag = YES; fixID = arg[iarg+1]; if (strcmp(arg[iarg+2],"type") == 0) fixcolor = TYPE; else error->all(FLERR,"Illegal dump image command"); fixflag1 = force->numeric(FLERR,arg[iarg+3]); fixflag2 = force->numeric(FLERR,arg[iarg+4]); iarg += 5; } else if (strcmp(arg[iarg],"size") == 0) { if (iarg+3 > narg) error->all(FLERR,"Illegal dump image command"); int width = force->inumeric(FLERR,arg[iarg+1]); int height = force->inumeric(FLERR,arg[iarg+2]); if (width <= 0 || height <= 0) error->all(FLERR,"Illegal dump image command"); image->width = width; image->height = height; 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 { double theta = force->numeric(FLERR,arg[iarg+1]); if (theta < 0.0 || theta > 180.0) error->all(FLERR,"Invalid dump image theta value"); theta *= MY_PI/180.0; image->theta = theta; } 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 { double phi = force->numeric(FLERR,arg[iarg+2]); phi *= MY_PI/180.0; image->phi = phi; } 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 = force->numeric(FLERR,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 = force->numeric(FLERR,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 = force->numeric(FLERR,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 image->up[0] = force->numeric(FLERR,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 image->up[1] = force->numeric(FLERR,arg[iarg+2]); 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 image->up[2] = force->numeric(FLERR,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 { double zoom = force->numeric(FLERR,arg[iarg+1]); if (zoom <= 0.0) error->all(FLERR,"Illegal dump image command"); image->zoom = zoom; } 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 { double persp = force->numeric(FLERR,arg[iarg+1]); if (persp < 0.0) error->all(FLERR,"Illegal dump image command"); image->persp = persp; } 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 = force->numeric(FLERR,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 = force->numeric(FLERR,arg[iarg+2]); axesdiam = force->numeric(FLERR,arg[iarg+3]); if (axeslen < 0.0 || axesdiam < 0.0) error->all(FLERR,"Illegal dump image command"); iarg += 4; } else if (strcmp(arg[iarg],"subbox") == 0) { if (iarg+3 > narg) error->all(FLERR,"Illegal dump image command"); if (strcmp(arg[iarg+1],"yes") == 0) subboxflag = YES; else if (strcmp(arg[iarg+1],"no") == 0) subboxflag = NO; else error->all(FLERR,"Illegal dump image command"); subboxdiam = force->numeric(FLERR,arg[iarg+2]); if (subboxdiam < 0.0) error->all(FLERR,"Illegal dump image command"); iarg += 3; } else if (strcmp(arg[iarg],"shiny") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal dump image command"); double shiny = force->numeric(FLERR,arg[iarg+1]); if (shiny < 0.0 || shiny > 1.0) error->all(FLERR,"Illegal dump image command"); image->shiny = shiny; 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) image->ssao = YES; else if (strcmp(arg[iarg+1],"no") == 0) image->ssao = NO; else error->all(FLERR,"Illegal dump image command"); int seed = force->inumeric(FLERR,arg[iarg+2]); if (seed <= 0) error->all(FLERR,"Illegal dump image command"); image->seed = seed; double ssaoint = force->numeric(FLERR,arg[iarg+3]); if (ssaoint < 0.0 || ssaoint > 1.0) error->all(FLERR,"Illegal dump image command"); image->ssaoint = ssaoint; iarg += 4; } else error->all(FLERR,"Illegal dump image command"); } // error checks and setup for lineflag, triflag, bodyflag, fixflag if (lineflag) { avec_line = (AtomVecLine *) atom->style_match("line"); if (!avec_line) error->all(FLERR,"Dump image line requires atom style line"); } if (triflag) { avec_tri = (AtomVecTri *) atom->style_match("tri"); if (!avec_tri) error->all(FLERR,"Dump image tri requires atom style tri"); } if (bodyflag) { avec_body = (AtomVecBody *) atom->style_match("body"); if (!avec_body) error->all(FLERR,"Dump image body yes requires atom style body"); } extraflag = 0; if (lineflag || triflag || bodyflag) extraflag = 1; if (fixflag) { int ifix = modify->find_fix(fixID); if (ifix < 0) error->all(FLERR,"Fix ID for dump image does not exist"); fixptr = modify->fix[ifix]; } // allocate image buffer now that image size is known image->buffers(); // communication neede for bonds colored by atoms if (bondflag) { if (bcolor == ATOM || bdiam == ATOM) comm_forward = 3; else comm_forward = 1; } // additional defaults for dump_modify options 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] = image->color2rgb("red"); else if (i % 6 == 2) colortype[i] = image->color2rgb("green"); else if (i % 6 == 3) colortype[i] = image->color2rgb("blue"); else if (i % 6 == 4) colortype[i] = image->color2rgb("yellow"); else if (i % 6 == 5) colortype[i] = image->color2rgb("aqua"); else if (i % 6 == 0) colortype[i] = image->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] = image->color2rgb("red"); else if (i % 6 == 2) bcolortype[i] = image->color2rgb("green"); else if (i % 6 == 3) bcolortype[i] = image->color2rgb("blue"); else if (i % 6 == 4) bcolortype[i] = image->color2rgb("yellow"); else if (i % 6 == 5) bcolortype[i] = image->color2rgb("aqua"); else if (i % 6 == 0) bcolortype[i] = image->color2rgb("cyan"); } } else { bdiamtype = NULL; bcolortype = NULL; } // viewflag = DYNAMIC if any view parameter is dynamic viewflag = STATIC; if (thetastr || phistr || cflag == DYNAMIC || upxstr || upystr || upzstr || zoomstr || perspstr) viewflag = DYNAMIC; box_bounds(); if (cflag == STATIC) box_center(); if (viewflag == STATIC) view_params(); // local data maxbufcopy = 0; chooseghost = NULL; bufcopy = NULL; } /* ---------------------------------------------------------------------- */ DumpImage::~DumpImage() { delete image; delete [] diamtype; delete [] diamelement; delete [] colortype; delete [] colorelement; delete [] bdiamtype; delete [] bcolortype; memory->destroy(chooseghost); memory->destroy(bufcopy); } /* ---------------------------------------------------------------------- */ void DumpImage::init_style() { if (multifile == 0 && !multifile_override) 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] = image->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] = image->element2diam(typenames[i]); if (diamelement[i] == 0.0) error->all(FLERR,"Invalid dump image element name"); } } } /* ---------------------------------------------------------------------- */ void DumpImage::write() { // open new file openfile(); // reset box center and view parameters if dynamic box_bounds(); if (cflag == DYNAMIC) box_center(); if (viewflag == DYNAMIC) view_params(); // nme = # of atoms this proc will contribute to dump nme = count(); if (nme > maxbuf) { maxbuf = nme; memory->destroy(buf); memory->create(buf,maxbuf*size_one,"dump:buf"); } // pack buf with color & diameter pack(NULL); // set minmax color range if using dynamic atom color map if (acolor == ATTRIBUTE && image->map_dynamic(0)) { double two[2],twoall[2]; 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]); m += size_one; } two[0] = -lo; two[1] = hi; MPI_Allreduce(two,twoall,2,MPI_DOUBLE,MPI_MAX,world); int flag = image->map_minmax(0,-twoall[0],twoall[1]); if (flag) error->all(FLERR,"Invalid color map min/max values"); } // create image on each proc, then merge them image->clear(); create_image(); image->merge(); // write image file if (me == 0) { if (filetype == JPG) image->write_JPG(fp); else if (filetype == PNG) image->write_PNG(fp); else image->write_PPM(fp); if (multifile) { fclose(fp); fp = NULL; } } } /* ---------------------------------------------------------------------- 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; } } /* ---------------------------------------------------------------------- reset view parameters called once from constructor if view is STATIC called every snapshot from write() if view is DYNAMIC ------------------------------------------------------------------------- */ void DumpImage::box_center() { if (cxstr) cx = input->variable->compute_equal(cxvar); if (cystr) cy = input->variable->compute_equal(cyvar); if (czstr) cz = input->variable->compute_equal(czvar); image->xctr = boxxlo + cx*(boxxhi-boxxlo); image->yctr = boxylo + cy*(boxyhi-boxylo); image->zctr = boxzlo + cz*(boxzhi-boxzlo); } /* ---------------------------------------------------------------------- reset view parameters in Image class called once from constructor if view is STATIC called every snapshot from write() if view is DYNAMIC ------------------------------------------------------------------------- */ void DumpImage::view_params() { // view direction theta and phi if (thetastr) { double 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; image->theta = theta; } if (phistr) { double phi = input->variable->compute_equal(phivar); phi *= MY_PI/180.0; image->phi = phi; } // up vector if (upxstr) image->up[0] = input->variable->compute_equal(upxvar); if (upystr) image->up[1] = input->variable->compute_equal(upyvar); if (upzstr) image->up[2] = input->variable->compute_equal(upzvar); // zoom and perspective if (zoomstr) image->zoom = input->variable->compute_equal(zoomvar); if (image->zoom <= 0.0) error->all(FLERR,"Invalid dump image zoom value"); if (perspstr) image->persp = input->variable->compute_equal(perspvar); if (image->persp < 0.0) error->all(FLERR,"Invalid dump image persp value"); // remainder of view setup is internal to Image class image->view_params(boxxlo,boxxhi,boxylo,boxyhi,boxzlo,boxzhi); } /* ---------------------------------------------------------------------- create image for atoms on this proc every pixel has depth ------------------------------------------------------------------------- */ void DumpImage::create_image() { int i,j,k,m,n,itype,atom1,atom2,imol,iatom,btype,ibonus,drawflag; tagint tagprev; double diameter,delx,dely,delz; int *bodyvec,*fixvec; double **bodyarray,**fixarray; double *color,*color1,*color2; double *p1,*p2,*p3; double xmid[3],pt1[3],pt2[3],pt3[3]; double mat[3][3]; // render my atoms if (atomflag) { double **x = atom->x; int *line = atom->line; int *tri = atom->tri; int *body = atom->body; 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 = image->map_value2color(0,buf[m]); } else color = image->color2rgb("white"); 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]; } // do not draw if line,tri,body keywords enabled and atom is one of those drawflag = 1; if (extraflag) { if (lineflag && line[j] >= 0) drawflag = 0; if (triflag && tri[j] >= 0) drawflag = 0; if (bodyflag && body[j] >= 0) drawflag = 0; } if (drawflag) image->draw_sphere(x[j],color,diameter); m += size_one; } } // render atoms that are lines if (lineflag) { double length,theta,dx,dy; double **x = atom->x; int *line = atom->line; int *type = atom->type; for (i = 0; i < nchoose; i++) { j = clist[i]; if (line[j] < 0) continue; if (lcolor == TYPE) { color = colortype[type[j]]; } if (ldiam == NUMERIC) { diameter = ldiamvalue; } length = avec_line->bonus[line[j]].length; theta = avec_line->bonus[line[j]].theta; dx = 0.5*length*cos(theta); dy = 0.5*length*sin(theta); pt1[0] = x[j][0] + dx; pt1[1] = x[j][1] + dy; pt1[2] = 0.0; pt2[0] = x[j][0] - dx; pt2[1] = x[j][1] - dy; pt2[2] = 0.0; image->draw_cylinder(pt1,pt2,color,ldiamvalue,3); } } // render atoms that are triangles // tstyle = 1 for tri only, 2 for edges only, 3 for both if (triflag) { int tridraw = 1; if (tstyle == 2) tridraw = 0; int edgedraw = 1; if (tstyle == 1) edgedraw = 0; double **x = atom->x; int *tri = atom->tri; int *type = atom->type; for (i = 0; i < nchoose; i++) { j = clist[i]; if (tri[j] < 0) continue; if (tcolor == TYPE) { color = colortype[type[j]]; } MathExtra::quat_to_mat(avec_tri->bonus[tri[i]].quat,mat); MathExtra::matvec(mat,avec_tri->bonus[tri[i]].c1,pt1); MathExtra::matvec(mat,avec_tri->bonus[tri[i]].c2,pt2); MathExtra::matvec(mat,avec_tri->bonus[tri[i]].c3,pt3); MathExtra::add3(pt1,x[i],pt1); MathExtra::add3(pt2,x[i],pt2); MathExtra::add3(pt3,x[i],pt3); if (tridraw) image->draw_triangle(pt1,pt2,pt3,color); if (edgedraw) { image->draw_cylinder(pt1,pt2,color,tdiamvalue,3); image->draw_cylinder(pt2,pt3,color,tdiamvalue,3); image->draw_cylinder(pt3,pt1,color,tdiamvalue,3); } } } // render atoms that are bodies if (bodyflag) { Body *bptr = avec_body->bptr; int *body = atom->body; m = 0; for (i = 0; i < nchoose; i++) { j = clist[i]; if (body[j] < 0) continue; if (bodycolor == TYPE) { itype = static_cast (buf[m]); color = colortype[itype]; } ibonus = body[i]; n = bptr->image(ibonus,bodyflag1,bodyflag2,bodyvec,bodyarray); for (k = 0; k < n; k++) { if (bodyvec[k] == SPHERE) image->draw_sphere(bodyarray[k],color,bodyarray[k][3]); else if (bodyvec[k] == LINE) image->draw_cylinder(&bodyarray[k][0],&bodyarray[k][3], color,bodyarray[k][6],3); } 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; tagint *tag = atom->tag; tagint **bond_atom = atom->bond_atom; int **bond_type = atom->bond_type; int *num_bond = atom->num_bond; int *molindex = atom->molindex; int *molatom = atom->molatom; int *type = atom->type; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; int molecular = atom->molecular; Molecule **onemols = atom->avec->onemols; // 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 (atom->nmax > maxbufcopy) { maxbufcopy = atom->nmax; memory->destroy(chooseghost); memory->create(chooseghost,maxbufcopy,"dump:chooseghost"); if (comm_forward == 3) { memory->destroy(bufcopy); memory->create(bufcopy,maxbufcopy,2,"dump:bufcopy"); } } for (i = 0; i < nlocal; i++) chooseghost[i] = choose[i]; if (comm_forward == 3) { 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]; if (molecular == 1) n = num_bond[atom1]; else { if (molindex[atom1] < 0) continue; imol = molindex[atom1]; iatom = molatom[atom1]; n = onemols[imol]->num_bond[iatom]; } for (m = 0; m < n; m++) { if (molecular == 1) { btype = bond_type[atom1][m]; atom2 = atom->map(bond_atom[atom1][m]); } else { tagprev = tag[i] - iatom - 1; btype = atom->map(onemols[imol]->bond_type[iatom][m]); atom2 = atom->map(onemols[imol]->bond_atom[iatom][m]+tagprev); } if (atom2 < 0 || !chooseghost[atom2]) continue; if (newton_bond == 0 && tag[atom1] > tag[atom2]) continue; if (btype == 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 = image->map_value2color(0,bufcopy[atom1][0]); color2 = image->map_value2color(0,bufcopy[atom2][0]); } else { color1 = image->color2rgb("white"); color2 = image->color2rgb("white"); } } else if (bcolor == TYPE) { itype = btype; 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 = btype; 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) image->draw_cylinder(x[atom1],xmid,color1,diameter,3); else image->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) image->draw_cylinder(xmid,x[atom2],color2,diameter,3); else image->draw_cylinder(xmid,x[atom2],color,diameter,3); } else image->draw_cylinder(x[atom1],x[atom2],color,diameter,3); } } } // render objects provided by a fix if (fixflag) { int tridraw=0,edgedraw=0; if (domain->dimension == 3) { tridraw = 1; edgedraw = 1; if ((int) fixflag1 == 2) tridraw = 0; if ((int) fixflag1 == 1) edgedraw = 0; } n = fixptr->image(fixvec,fixarray); for (i = 0; i < n; i++) { if (fixvec[i] == SPHERE) { // no fix draws spheres yet } else if (fixvec[i] == LINE) { if (fixcolor == TYPE) { itype = static_cast (fixarray[i][0]); color = colortype[itype]; } image->draw_cylinder(&fixarray[i][1],&fixarray[i][4], color,fixflag1,3); } else if (fixvec[i] == TRI) { if (fixcolor == TYPE) { itype = static_cast (fixarray[i][0]); color = colortype[itype]; } p1 = &fixarray[i][1]; p2 = &fixarray[i][4]; p3 = &fixarray[i][7]; if (tridraw) image->draw_triangle(p1,p2,p3,color); if (edgedraw) { image->draw_cylinder(p1,p2,color,fixflag2,3); image->draw_cylinder(p2,p3,color,fixflag2,3); image->draw_cylinder(p3,p1,color,fixflag2,3); } } } } // render outline of my sub-box, orthogonal or triclinic if (subboxflag) { double diameter = MIN(boxxhi-boxxlo,boxyhi-boxylo); if (domain->dimension == 3) diameter = MIN(diameter,boxzhi-boxzlo); diameter *= subboxdiam; double *sublo = domain->sublo; double *subhi = domain->subhi; double (*boxcorners)[3]; double box[8][3]; if (domain->triclinic == 0) { box[0][0] = sublo[0]; box[0][1] = sublo[1]; box[0][2] = sublo[2]; box[1][0] = subhi[0]; box[1][1] = sublo[1]; box[1][2] = sublo[2]; box[2][0] = sublo[0]; box[2][1] = subhi[1]; box[2][2] = sublo[2]; box[3][0] = subhi[0]; box[3][1] = subhi[1]; box[3][2] = sublo[2]; box[4][0] = sublo[0]; box[4][1] = sublo[1]; box[4][2] = subhi[2]; box[5][0] = subhi[0]; box[5][1] = sublo[1]; box[5][2] = subhi[2]; box[6][0] = sublo[0]; box[6][1] = subhi[1]; box[6][2] = subhi[2]; box[7][0] = subhi[0]; box[7][1] = subhi[1]; box[7][2] = subhi[2]; boxcorners = box; } else { domain->subbox_corners(); boxcorners = domain->corners; } image->draw_box(boxcorners,diameter); } // 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 (*boxcorners)[3]; double box[8][3]; if (domain->triclinic == 0) { box[0][0] = boxxlo; box[0][1] = boxylo; box[0][2] = boxzlo; box[1][0] = boxxhi; box[1][1] = boxylo; box[1][2] = boxzlo; box[2][0] = boxxlo; box[2][1] = boxyhi; box[2][2] = boxzlo; box[3][0] = boxxhi; box[3][1] = boxyhi; box[3][2] = boxzlo; box[4][0] = boxxlo; box[4][1] = boxylo; box[4][2] = boxzhi; box[5][0] = boxxhi; box[5][1] = boxylo; box[5][2] = boxzhi; box[6][0] = boxxlo; box[6][1] = boxyhi; box[6][2] = boxzhi; box[7][0] = boxxhi; box[7][1] = boxyhi; box[7][2] = boxzhi; boxcorners = box; } else { domain->box_corners(); boxcorners = domain->corners; } image->draw_box(boxcorners,diameter); } // 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 (*boxcorners)[3]; double axes[4][3]; if (domain->triclinic == 0) { axes[0][0] = boxxlo; axes[0][1] = boxylo; axes[0][2] = boxzlo; axes[1][0] = boxxhi; axes[1][1] = boxylo; axes[1][2] = boxzlo; axes[2][0] = boxxlo; axes[2][1] = boxyhi; axes[2][2] = boxzlo; axes[3][0] = boxxlo; axes[3][1] = boxylo; axes[3][2] = boxzhi; } else { domain->box_corners(); boxcorners = domain->corners; axes[0][0] = boxcorners[0][0]; axes[0][1] = boxcorners[0][1]; axes[0][2] = boxcorners[0][2]; axes[1][0] = boxcorners[1][0]; axes[1][1] = boxcorners[1][1]; axes[1][2] = boxcorners[1][2]; axes[2][0] = boxcorners[2][0]; axes[2][1] = boxcorners[2][1]; axes[2][2] = boxcorners[2][2]; axes[3][0] = boxcorners[4][0]; axes[3][1] = boxcorners[4][1]; axes[3][2] = boxcorners[4][2]; } double offset = MAX(boxxhi-boxxlo,boxyhi-boxylo); if (domain->dimension == 3) offset = MAX(offset,boxzhi-boxzlo); offset *= 0.1; axes[0][0] -= offset; axes[0][1] -= offset; axes[0][2] -= offset; axes[1][0] -= offset; axes[1][1] -= offset; axes[1][2] -= offset; axes[2][0] -= offset; axes[2][1] -= offset; axes[2][2] -= offset; axes[3][0] -= offset; axes[3][1] -= offset; axes[3][2] -= offset; axes[1][0] = axes[0][0] + axeslen*(axes[1][0]-axes[0][0]); axes[1][1] = axes[0][1] + axeslen*(axes[1][1]-axes[0][1]); axes[1][2] = axes[0][2] + axeslen*(axes[1][2]-axes[0][2]); axes[2][0] = axes[0][0] + axeslen*(axes[2][0]-axes[0][0]); axes[2][1] = axes[0][1] + axeslen*(axes[2][1]-axes[0][1]); axes[2][2] = axes[0][2] + axeslen*(axes[2][2]-axes[0][2]); axes[3][0] = axes[0][0] + axeslen*(axes[3][0]-axes[0][0]); axes[3][1] = axes[0][1] + axeslen*(axes[3][1]-axes[0][1]); axes[3][2] = axes[0][2] + axeslen*(axes[3][2]-axes[0][2]); image->draw_axes(axes,diameter); } } /* ---------------------------------------------------------------------- */ int DumpImage::pack_forward_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++] = chooseghost[j]; } } else { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = chooseghost[j]; buf[m++] = bufcopy[j][0]; buf[m++] = bufcopy[j][1]; } } return m; } /* ---------------------------------------------------------------------- */ void DumpImage::unpack_forward_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++) chooseghost[i] = static_cast (buf[m++]); else { for (i = first; i < last; i++) { chooseghost[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); + force->bounds(FLERR,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] = image->color2rgb(ptrs[m%ncount]); if (colortype[i] == NULL) error->all(FLERR,"Invalid color in dump_modify command"); m++; } delete [] ptrs; return 3; } 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); + force->bounds(FLERR,arg[1],atom->ntypes,nlo,nhi); double diam = force->numeric(FLERR,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; } if (strcmp(arg[0],"amap") == 0) { if (narg < 6) error->all(FLERR,"Illegal dump_modify command"); if (strlen(arg[3]) != 2) error->all(FLERR,"Illegal dump_modify command"); int factor; if (arg[3][0] == 's') factor = 1; else if (arg[3][0] == 'c') factor = 2; else if (arg[3][0] == 'd') factor = 3; else error->all(FLERR,"Illegal dump_modify command"); int nentry = force->inumeric(FLERR,arg[5]); if (nentry < 1) error->all(FLERR,"Illegal dump_modify command"); int n = 6 + factor*nentry; if (narg < n) error->all(FLERR,"Illegal dump_modify command"); int flag = image->map_reset(0,n-1,&arg[1]); if (flag) error->all(FLERR,"Illegal dump_modify command"); return n; } 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); + force->bounds(FLERR,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] = image->color2rgb(ptrs[m%ncount]); if (bcolortype[i] == NULL) error->all(FLERR,"Invalid color in dump_modify command"); m++; } delete [] ptrs; return 3; } 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); + force->bounds(FLERR,arg[1],atom->ntypes,nlo,nhi); double diam = force->numeric(FLERR,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; } if (strcmp(arg[0],"backcolor") == 0) { if (narg < 2) error->all(FLERR,"Illegal dump_modify command"); double *color = image->color2rgb(arg[1]); if (color == NULL) error->all(FLERR,"Invalid color in dump_modify command"); image->background[0] = static_cast (color[0]*255.0); image->background[1] = static_cast (color[1]*255.0); image->background[2] = static_cast (color[2]*255.0); return 2; } if (strcmp(arg[0],"boxcolor") == 0) { if (narg < 2) error->all(FLERR,"Illegal dump_modify command"); image->boxcolor = image->color2rgb(arg[1]); if (image->boxcolor == NULL) error->all(FLERR,"Invalid color in dump_modify command"); return 2; } if (strcmp(arg[0],"color") == 0) { if (narg < 5) error->all(FLERR,"Illegal dump_modify command"); int flag = image->addcolor(arg[1],force->numeric(FLERR,arg[2]),force->numeric(FLERR,arg[3]),force->numeric(FLERR,arg[4])); if (flag) error->all(FLERR,"Illegal dump_modify command"); return 5; } return 0; } diff --git a/src/fix_adapt.cpp b/src/fix_adapt.cpp index 2a3f7db1f..4c7eb5f21 100644 --- a/src/fix_adapt.cpp +++ b/src/fix_adapt.cpp @@ -1,602 +1,602 @@ /* ---------------------------------------------------------------------- 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 #include #include #include "fix_adapt.h" #include "atom.h" #include "update.h" #include "group.h" #include "modify.h" #include "force.h" #include "pair.h" #include "pair_hybrid.h" #include "kspace.h" #include "fix_store.h" #include "input.h" #include "variable.h" #include "respa.h" #include "math_const.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace FixConst; using namespace MathConst; enum{PAIR,KSPACE,ATOM}; enum{DIAMETER,CHARGE}; /* ---------------------------------------------------------------------- */ FixAdapt::FixAdapt(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg), nadapt(0), id_fix_diam(NULL), id_fix_chg(NULL), adapt(NULL) { if (narg < 5) error->all(FLERR,"Illegal fix adapt command"); nevery = force->inumeric(FLERR,arg[3]); if (nevery < 0) error->all(FLERR,"Illegal fix adapt command"); dynamic_group_allow = 1; create_attribute = 1; // count # of adaptations nadapt = 0; int iarg = 4; while (iarg < narg) { if (strcmp(arg[iarg],"pair") == 0) { if (iarg+6 > narg) error->all(FLERR,"Illegal fix adapt command"); nadapt++; iarg += 6; } else if (strcmp(arg[iarg],"kspace") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal fix adapt command"); nadapt++; iarg += 2; } else if (strcmp(arg[iarg],"atom") == 0) { if (iarg+3 > narg) error->all(FLERR,"Illegal fix adapt command"); nadapt++; iarg += 3; } else break; } if (nadapt == 0) error->all(FLERR,"Illegal fix adapt command"); adapt = new Adapt[nadapt]; // parse keywords nadapt = 0; diamflag = 0; chgflag = 0; iarg = 4; while (iarg < narg) { if (strcmp(arg[iarg],"pair") == 0) { if (iarg+6 > narg) error->all(FLERR,"Illegal fix adapt command"); adapt[nadapt].which = PAIR; int n = strlen(arg[iarg+1]) + 1; adapt[nadapt].pstyle = new char[n]; strcpy(adapt[nadapt].pstyle,arg[iarg+1]); n = strlen(arg[iarg+2]) + 1; adapt[nadapt].pparam = new char[n]; adapt[nadapt].pair = NULL; strcpy(adapt[nadapt].pparam,arg[iarg+2]); - force->bounds(arg[iarg+3],atom->ntypes, + force->bounds(FLERR,arg[iarg+3],atom->ntypes, adapt[nadapt].ilo,adapt[nadapt].ihi); - force->bounds(arg[iarg+4],atom->ntypes, + force->bounds(FLERR,arg[iarg+4],atom->ntypes, adapt[nadapt].jlo,adapt[nadapt].jhi); if (strstr(arg[iarg+5],"v_") == arg[iarg+5]) { n = strlen(&arg[iarg+5][2]) + 1; adapt[nadapt].var = new char[n]; strcpy(adapt[nadapt].var,&arg[iarg+5][2]); } else error->all(FLERR,"Illegal fix adapt command"); nadapt++; iarg += 6; } else if (strcmp(arg[iarg],"kspace") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal fix adapt command"); adapt[nadapt].which = KSPACE; if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) { int n = strlen(&arg[iarg+1][2]) + 1; adapt[nadapt].var = new char[n]; strcpy(adapt[nadapt].var,&arg[iarg+1][2]); } else error->all(FLERR,"Illegal fix adapt command"); nadapt++; iarg += 2; } else if (strcmp(arg[iarg],"atom") == 0) { if (iarg+3 > narg) error->all(FLERR,"Illegal fix adapt command"); adapt[nadapt].which = ATOM; if (strcmp(arg[iarg+1],"diameter") == 0) { adapt[nadapt].aparam = DIAMETER; diamflag = 1; } else if (strcmp(arg[iarg+1],"charge") == 0) { adapt[nadapt].aparam = CHARGE; chgflag = 1; } else error->all(FLERR,"Illegal fix adapt command"); if (strstr(arg[iarg+2],"v_") == arg[iarg+2]) { int n = strlen(&arg[iarg+2][2]) + 1; adapt[nadapt].var = new char[n]; strcpy(adapt[nadapt].var,&arg[iarg+2][2]); } else error->all(FLERR,"Illegal fix adapt command"); nadapt++; iarg += 3; } else break; } // optional keywords resetflag = 0; scaleflag = 0; while (iarg < narg) { if (strcmp(arg[iarg],"reset") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal fix adapt command"); if (strcmp(arg[iarg+1],"no") == 0) resetflag = 0; else if (strcmp(arg[iarg+1],"yes") == 0) resetflag = 1; else error->all(FLERR,"Illegal fix adapt command"); iarg += 2; } else if (strcmp(arg[iarg],"scale") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal fix adapt command"); if (strcmp(arg[iarg+1],"no") == 0) scaleflag = 0; else if (strcmp(arg[iarg+1],"yes") == 0) scaleflag = 1; else error->all(FLERR,"Illegal fix adapt command"); iarg += 2; } else error->all(FLERR,"Illegal fix adapt command"); } // allocate pair style arrays int n = atom->ntypes; for (int m = 0; m < nadapt; m++) if (adapt[m].which == PAIR) memory->create(adapt[m].array_orig,n+1,n+1,"adapt:array_orig"); } /* ---------------------------------------------------------------------- */ FixAdapt::~FixAdapt() { for (int m = 0; m < nadapt; m++) { delete [] adapt[m].var; if (adapt[m].which == PAIR) { delete [] adapt[m].pstyle; delete [] adapt[m].pparam; memory->destroy(adapt[m].array_orig); } } delete [] adapt; // check nfix in case all fixes have already been deleted if (id_fix_diam && modify->nfix) modify->delete_fix(id_fix_diam); if (id_fix_chg && modify->nfix) modify->delete_fix(id_fix_chg); delete [] id_fix_diam; delete [] id_fix_chg; } /* ---------------------------------------------------------------------- */ int FixAdapt::setmask() { int mask = 0; mask |= PRE_FORCE; mask |= POST_RUN; mask |= PRE_FORCE_RESPA; return mask; } /* ---------------------------------------------------------------------- if need to restore per-atom quantities, create new fix STORE styles ------------------------------------------------------------------------- */ void FixAdapt::post_constructor() { if (!resetflag) return; if (!diamflag && !chgflag) return; // new id = fix-ID + FIX_STORE_ATTRIBUTE // new fix group = group for this fix id_fix_diam = NULL; id_fix_chg = NULL; char **newarg = new char*[6]; newarg[1] = group->names[igroup]; newarg[2] = (char *) "STORE"; newarg[3] = (char *) "peratom"; newarg[4] = (char *) "1"; newarg[5] = (char *) "1"; if (diamflag) { int n = strlen(id) + strlen("_FIX_STORE_DIAM") + 1; id_fix_diam = new char[n]; strcpy(id_fix_diam,id); strcat(id_fix_diam,"_FIX_STORE_DIAM"); newarg[0] = id_fix_diam; modify->add_fix(6,newarg); fix_diam = (FixStore *) modify->fix[modify->nfix-1]; if (fix_diam->restart_reset) fix_diam->restart_reset = 0; else { double *vec = fix_diam->vstore; double *radius = atom->radius; int *mask = atom->mask; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) vec[i] = radius[i]; else vec[i] = 0.0; } } } if (chgflag) { int n = strlen(id) + strlen("_FIX_STORE_CHG") + 1; id_fix_chg = new char[n]; strcpy(id_fix_chg,id); strcat(id_fix_chg,"_FIX_STORE_CHG"); newarg[0] = id_fix_chg; modify->add_fix(6,newarg); fix_chg = (FixStore *) modify->fix[modify->nfix-1]; if (fix_chg->restart_reset) fix_chg->restart_reset = 0; else { double *vec = fix_chg->vstore; double *q = atom->q; int *mask = atom->mask; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) vec[i] = q[i]; else vec[i] = 0.0; } } } delete [] newarg; } /* ---------------------------------------------------------------------- */ void FixAdapt::init() { int i,j; // allow a dynamic group only if ATOM attribute not used if (group->dynamic[igroup]) for (int i = 0; i < nadapt; i++) if (adapt[i].which == ATOM) error->all(FLERR,"Cannot use dynamic group with fix adapt atom"); // setup and error checks anypair = 0; for (int m = 0; m < nadapt; m++) { Adapt *ad = &adapt[m]; ad->ivar = input->variable->find(ad->var); if (ad->ivar < 0) error->all(FLERR,"Variable name for fix adapt does not exist"); if (!input->variable->equalstyle(ad->ivar)) error->all(FLERR,"Variable for fix adapt is invalid style"); if (ad->which == PAIR) { anypair = 1; ad->pair = NULL; // if ad->pstyle has trailing sub-style annotation ":N", // strip it for pstyle arg to pair_match() and set nsub = N // this should work for appended suffixes as well int n = strlen(ad->pstyle) + 1; char *pstyle = new char[n]; strcpy(pstyle,ad->pstyle); char *cptr; int nsub = 0; if ((cptr = strchr(pstyle,':'))) { *cptr = '\0'; nsub = force->inumeric(FLERR,cptr+1); } if (lmp->suffix_enable) { int len = 2 + strlen(pstyle) + strlen(lmp->suffix); char *psuffix = new char[len]; strcpy(psuffix,pstyle); strcat(psuffix,"/"); strcat(psuffix,lmp->suffix); ad->pair = force->pair_match(psuffix,1,nsub); delete[] psuffix; } if (ad->pair == NULL) ad->pair = force->pair_match(pstyle,1,nsub); if (ad->pair == NULL) error->all(FLERR,"Fix adapt pair style does not exist"); void *ptr = ad->pair->extract(ad->pparam,ad->pdim); if (ptr == NULL) error->all(FLERR,"Fix adapt pair style param not supported"); // for pair styles only parameters that are 2-d arrays in atom types or // scalars are supported if (ad->pdim != 2 && ad->pdim != 0) error->all(FLERR,"Fix adapt pair style param is not compatible"); if (ad->pdim == 2) ad->array = (double **) ptr; if (ad->pdim == 0) ad->scalar = (double *) ptr; // if pair hybrid, test that ilo,ihi,jlo,jhi are valid for sub-style if (strcmp(force->pair_style,"hybrid") == 0 || strcmp(force->pair_style,"hybrid/overlay") == 0) { PairHybrid *pair = (PairHybrid *) force->pair; for (i = ad->ilo; i <= ad->ihi; i++) for (j = MAX(ad->jlo,i); j <= ad->jhi; j++) if (!pair->check_ijtype(i,j,pstyle)) error->all(FLERR,"Fix adapt type pair range is not valid for " "pair hybrid sub-style"); } delete [] pstyle; } else if (ad->which == KSPACE) { if (force->kspace == NULL) error->all(FLERR,"Fix adapt kspace style does not exist"); kspace_scale = (double *) force->kspace->extract("scale"); } else if (ad->which == ATOM) { if (ad->aparam == DIAMETER) { if (!atom->radius_flag) error->all(FLERR,"Fix adapt requires atom attribute diameter"); } if (ad->aparam == CHARGE) { if (!atom->q_flag) error->all(FLERR,"Fix adapt requires atom attribute charge"); } } } // make copy of original pair array values for (int m = 0; m < nadapt; m++) { Adapt *ad = &adapt[m]; if (ad->which == PAIR && ad->pdim == 2) { for (i = ad->ilo; i <= ad->ihi; i++) for (j = MAX(ad->jlo,i); j <= ad->jhi; j++) ad->array_orig[i][j] = ad->array[i][j]; }else if (ad->which == PAIR && ad->pdim == 0){ ad->scalar_orig = *ad->scalar; } } // fixes that store initial per-atom values if (id_fix_diam) { int ifix = modify->find_fix(id_fix_diam); if (ifix < 0) error->all(FLERR,"Could not find fix adapt storage fix ID"); fix_diam = (FixStore *) modify->fix[ifix]; } if (id_fix_chg) { int ifix = modify->find_fix(id_fix_chg); if (ifix < 0) error->all(FLERR,"Could not find fix adapt storage fix ID"); fix_chg = (FixStore *) modify->fix[ifix]; } if (strstr(update->integrate_style,"respa")) nlevels_respa = ((Respa *) update->integrate)->nlevels; } /* ---------------------------------------------------------------------- */ void FixAdapt::setup_pre_force(int vflag) { change_settings(); } /* ---------------------------------------------------------------------- */ void FixAdapt::setup_pre_force_respa(int vflag, int ilevel) { if (ilevel < nlevels_respa-1) return; setup_pre_force(vflag); } /* ---------------------------------------------------------------------- */ void FixAdapt::pre_force(int vflag) { if (nevery == 0) return; if (update->ntimestep % nevery) return; change_settings(); } /* ---------------------------------------------------------------------- */ void FixAdapt::pre_force_respa(int vflag, int ilevel, int) { if (ilevel < nlevels_respa-1) return; pre_force(vflag); } /* ---------------------------------------------------------------------- */ void FixAdapt::post_run() { if (resetflag) restore_settings(); } /* ---------------------------------------------------------------------- change pair,kspace,atom parameters based on variable evaluation ------------------------------------------------------------------------- */ void FixAdapt::change_settings() { int i,j; // variable evaluation may invoke computes so wrap with clear/add modify->clearstep_compute(); for (int m = 0; m < nadapt; m++) { Adapt *ad = &adapt[m]; double value = input->variable->compute_equal(ad->ivar); // set global scalar or type pair array values if (ad->which == PAIR) { if (ad->pdim == 0) { if (scaleflag) *ad->scalar = value * ad->scalar_orig; else *ad->scalar = value; } else if (ad->pdim == 2) { if (scaleflag) for (i = ad->ilo; i <= ad->ihi; i++) for (j = MAX(ad->jlo,i); j <= ad->jhi; j++) ad->array[i][j] = value*ad->array_orig[i][j]; else for (i = ad->ilo; i <= ad->ihi; i++) for (j = MAX(ad->jlo,i); j <= ad->jhi; j++) ad->array[i][j] = value; } // set kspace scale factor } else if (ad->which == KSPACE) { *kspace_scale = value; // set per atom values, also make changes for ghost atoms } else if (ad->which == ATOM) { // reset radius from diameter // also scale rmass to new value if (ad->aparam == DIAMETER) { int mflag = 0; if (atom->rmass_flag) mflag = 1; double density; double *radius = atom->radius; double *rmass = atom->rmass; int *mask = atom->mask; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; if (mflag == 0) { for (i = 0; i < nall; i++) if (mask[i] & groupbit) radius[i] = 0.5*value; } else { for (i = 0; i < nall; i++) if (mask[i] & groupbit) { density = rmass[i] / (4.0*MY_PI/3.0 * radius[i]*radius[i]*radius[i]); radius[i] = 0.5*value; rmass[i] = 4.0*MY_PI/3.0 * radius[i]*radius[i]*radius[i] * density; } } } else if (ad->aparam == CHARGE) { double *q = atom->q; int *mask = atom->mask; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; for (i = 0; i < nall; i++) if (mask[i] & groupbit) q[i] = value; } } } modify->addstep_compute(update->ntimestep + nevery); // re-initialize pair styles if any PAIR settings were changed // this resets other coeffs that may depend on changed values, // and also offset and tail corrections if (anypair) { for (int m = 0; m < nadapt; m++) { Adapt *ad = &adapt[m]; if (ad->which == PAIR) { ad->pair->reinit(); } } } // reset KSpace charges if charges have changed if (chgflag && force->kspace) force->kspace->qsum_qsq(); } /* ---------------------------------------------------------------------- restore pair,kspace,atom parameters to original values ------------------------------------------------------------------------- */ void FixAdapt::restore_settings() { for (int m = 0; m < nadapt; m++) { Adapt *ad = &adapt[m]; if (ad->which == PAIR) { if (ad->pdim == 0) *ad->scalar = ad->scalar_orig; else if (ad->pdim == 2) { for (int i = ad->ilo; i <= ad->ihi; i++) for (int j = MAX(ad->jlo,i); j <= ad->jhi; j++) ad->array[i][j] = ad->array_orig[i][j]; } } else if (ad->which == KSPACE) { *kspace_scale = 1.0; } else if (ad->which == ATOM) { if (diamflag) { double density; double *vec = fix_diam->vstore; double *radius = atom->radius; double *rmass = atom->rmass; int *mask = atom->mask; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { density = rmass[i] / (4.0*MY_PI/3.0 * radius[i]*radius[i]*radius[i]); radius[i] = vec[i]; rmass[i] = 4.0*MY_PI/3.0 * radius[i]*radius[i]*radius[i] * density; } } if (chgflag) { double *vec = fix_chg->vstore; double *q = atom->q; int *mask = atom->mask; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) q[i] = vec[i]; } } } if (anypair) force->pair->reinit(); if (chgflag && force->kspace) force->kspace->qsum_qsq(); } /* ---------------------------------------------------------------------- initialize one atom's storage values, called when atom is created ------------------------------------------------------------------------- */ void FixAdapt::set_arrays(int i) { if (fix_diam) fix_diam->vstore[i] = atom->radius[i]; if (fix_chg) fix_chg->vstore[i] = atom->q[i]; } diff --git a/src/force.cpp b/src/force.cpp index dbc71b49a..3154139d5 100644 --- a/src/force.cpp +++ b/src/force.cpp @@ -1,1119 +1,1120 @@ /* ---------------------------------------------------------------------- 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 #include #include #include "force.h" #include "style_bond.h" #include "style_angle.h" #include "style_dihedral.h" #include "style_improper.h" #include "style_pair.h" #include "style_kspace.h" #include "atom.h" #include "comm.h" #include "pair.h" #include "pair_hybrid.h" #include "pair_hybrid_overlay.h" #include "bond.h" #include "bond_hybrid.h" #include "angle.h" #include "dihedral.h" #include "improper.h" #include "kspace.h" #include "group.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define MAXLINE 1024 /* ---------------------------------------------------------------------- */ Force::Force(LAMMPS *lmp) : Pointers(lmp) { newton = newton_pair = newton_bond = 1; special_lj[0] = special_coul[0] = 1.0; special_lj[1] = special_lj[2] = special_lj[3] = 0.0; special_coul[1] = special_coul[2] = special_coul[3] = 0.0; special_angle = special_dihedral = 0; special_extra = 0; dielectric = 1.0; pair = NULL; bond = NULL; angle = NULL; dihedral = NULL; improper = NULL; kspace = NULL; char *str = (char *) "none"; int n = strlen(str) + 1; pair_style = new char[n]; strcpy(pair_style,str); bond_style = new char[n]; strcpy(bond_style,str); angle_style = new char[n]; strcpy(angle_style,str); dihedral_style = new char[n]; strcpy(dihedral_style,str); improper_style = new char[n]; strcpy(improper_style,str); kspace_style = new char[n]; strcpy(kspace_style,str); // fill pair map with pair styles listed in style_pair.h pair_map = new PairCreatorMap(); #define PAIR_CLASS #define PairStyle(key,Class) \ (*pair_map)[#key] = &pair_creator; #include "style_pair.h" #undef PairStyle #undef PAIR_CLASS bond_map = new BondCreatorMap(); #define BOND_CLASS #define BondStyle(key,Class) \ (*bond_map)[#key] = &bond_creator; #include "style_bond.h" #undef BondStyle #undef BOND_CLASS angle_map = new AngleCreatorMap(); #define ANGLE_CLASS #define AngleStyle(key,Class) \ (*angle_map)[#key] = &angle_creator; #include "style_angle.h" #undef AngleStyle #undef ANGLE_CLASS dihedral_map = new DihedralCreatorMap(); #define DIHEDRAL_CLASS #define DihedralStyle(key,Class) \ (*dihedral_map)[#key] = &dihedral_creator; #include "style_dihedral.h" #undef DihedralStyle #undef DIHEDRAL_CLASS improper_map = new ImproperCreatorMap(); #define IMPROPER_CLASS #define ImproperStyle(key,Class) \ (*improper_map)[#key] = &improper_creator; #include "style_improper.h" #undef ImproperStyle #undef IMPROPER_CLASS kspace_map = new KSpaceCreatorMap(); #define KSPACE_CLASS #define KSpaceStyle(key,Class) \ (*kspace_map)[#key] = &kspace_creator; #include "style_kspace.h" #undef KSpaceStyle #undef KSPACE_CLASS } /* ---------------------------------------------------------------------- */ Force::~Force() { delete [] pair_style; delete [] bond_style; delete [] angle_style; delete [] dihedral_style; delete [] improper_style; delete [] kspace_style; if (pair) delete pair; if (bond) delete bond; if (angle) delete angle; if (dihedral) delete dihedral; if (improper) delete improper; if (kspace) delete kspace; pair = NULL; bond = NULL; angle = NULL; dihedral = NULL; improper = NULL; kspace = NULL; delete pair_map; delete bond_map; delete angle_map; delete dihedral_map; delete improper_map; delete kspace_map; } /* ---------------------------------------------------------------------- */ void Force::init() { qqrd2e = qqr2e/dielectric; if (kspace) kspace->init(); // kspace must come before pair if (pair) pair->init(); // so g_ewald is defined if (bond) bond->init(); if (angle) angle->init(); if (dihedral) dihedral->init(); if (improper) improper->init(); } /* ---------------------------------------------------------------------- */ void Force::setup() { if (pair) pair->setup(); } /* ---------------------------------------------------------------------- create a pair style, called from input script or restart file ------------------------------------------------------------------------- */ void Force::create_pair(const char *style, int trysuffix) { delete [] pair_style; if (pair) delete pair; int sflag; pair = new_pair(style,trysuffix,sflag); store_style(pair_style,style,sflag); } /* ---------------------------------------------------------------------- generate a pair class if trysuffix = 1, try first with suffix1/2 appended return sflag = 0 for no suffix added, 1 or 2 for suffix1/2 added ------------------------------------------------------------------------- */ Pair *Force::new_pair(const char *style, int trysuffix, int &sflag) { if (trysuffix && lmp->suffix_enable) { if (lmp->suffix) { sflag = 1; char estyle[256]; sprintf(estyle,"%s/%s",style,lmp->suffix); if (pair_map->find(estyle) != pair_map->end()) { PairCreator pair_creator = (*pair_map)[estyle]; return pair_creator(lmp); } } if (lmp->suffix2) { sflag = 2; char estyle[256]; sprintf(estyle,"%s/%s",style,lmp->suffix2); if (pair_map->find(estyle) != pair_map->end()) { PairCreator pair_creator = (*pair_map)[estyle]; return pair_creator(lmp); } } } sflag = 0; if (strcmp(style,"none") == 0) return NULL; if (pair_map->find(style) != pair_map->end()) { PairCreator pair_creator = (*pair_map)[style]; return pair_creator(lmp); } error->all(FLERR,"Unknown pair style"); return NULL; } /* ---------------------------------------------------------------------- one instance per pair style in style_pair.h ------------------------------------------------------------------------- */ template Pair *Force::pair_creator(LAMMPS *lmp) { return new T(lmp); } /* ---------------------------------------------------------------------- return ptr to Pair class if matches word or matches hybrid sub-style if exact, then style name must be exact match to word if not exact, style name must contain word if nsub > 0, match Nth hybrid sub-style return NULL if no match or if nsub=0 and multiple sub-styles match ------------------------------------------------------------------------- */ Pair *Force::pair_match(const char *word, int exact, int nsub) { int iwhich,count; if (exact && strcmp(pair_style,word) == 0) return pair; else if (!exact && strstr(pair_style,word)) return pair; else if (strstr(pair_style,"hybrid/overlay")) { PairHybridOverlay *hybrid = (PairHybridOverlay *) pair; count = 0; for (int i = 0; i < hybrid->nstyles; i++) if ((exact && strcmp(hybrid->keywords[i],word) == 0) || (!exact && strstr(hybrid->keywords[i],word))) { iwhich = i; count++; if (nsub == count) return hybrid->styles[iwhich]; } if (count == 1) return hybrid->styles[iwhich]; } else if (strstr(pair_style,"hybrid")) { PairHybrid *hybrid = (PairHybrid *) pair; count = 0; for (int i = 0; i < hybrid->nstyles; i++) if ((exact && strcmp(hybrid->keywords[i],word) == 0) || (!exact && strstr(hybrid->keywords[i],word))) { iwhich = i; count++; if (nsub == count) return hybrid->styles[iwhich]; } if (count == 1) return hybrid->styles[iwhich]; } return NULL; } /* ---------------------------------------------------------------------- return style name of Pair class that matches Pair ptr called by Neighbor::print_neigh_info() return NULL if no match ------------------------------------------------------------------------- */ char *Force::pair_match_ptr(Pair *ptr) { if (ptr == pair) return pair_style; if (strstr(pair_style,"hybrid")) { PairHybrid *hybrid = (PairHybrid *) pair; for (int i = 0; i < hybrid->nstyles; i++) if (ptr == hybrid->styles[i]) return hybrid->keywords[i]; } return NULL; } /* ---------------------------------------------------------------------- create a bond style, called from input script or restart file ------------------------------------------------------------------------- */ void Force::create_bond(const char *style, int trysuffix) { delete [] bond_style; if (bond) delete bond; int sflag; bond = new_bond(style,trysuffix,sflag); store_style(bond_style,style,sflag); } /* ---------------------------------------------------------------------- generate a bond class, fist with suffix appended ------------------------------------------------------------------------- */ Bond *Force::new_bond(const char *style, int trysuffix, int &sflag) { if (trysuffix && lmp->suffix_enable) { if (lmp->suffix) { sflag = 1; char estyle[256]; sprintf(estyle,"%s/%s",style,lmp->suffix); if (bond_map->find(estyle) != bond_map->end()) { BondCreator bond_creator = (*bond_map)[estyle]; return bond_creator(lmp); } } if (lmp->suffix2) { sflag = 2; char estyle[256]; sprintf(estyle,"%s/%s",style,lmp->suffix2); if (bond_map->find(estyle) != bond_map->end()) { BondCreator bond_creator = (*bond_map)[estyle]; return bond_creator(lmp); } } } sflag = 0; if (strcmp(style,"none") == 0) return NULL; if (bond_map->find(style) != bond_map->end()) { BondCreator bond_creator = (*bond_map)[style]; return bond_creator(lmp); } error->all(FLERR,"Unknown bond style"); return NULL; } /* ---------------------------------------------------------------------- one instance per bond style in style_bond.h ------------------------------------------------------------------------- */ template Bond *Force::bond_creator(LAMMPS *lmp) { return new T(lmp); } /* ---------------------------------------------------------------------- return ptr to current bond class or hybrid sub-class if matches style ------------------------------------------------------------------------- */ Bond *Force::bond_match(const char *style) { if (strcmp(bond_style,style) == 0) return bond; else if (strcmp(bond_style,"hybrid") == 0) { BondHybrid *hybrid = (BondHybrid *) bond; for (int i = 0; i < hybrid->nstyles; i++) if (strcmp(hybrid->keywords[i],style) == 0) return hybrid->styles[i]; } return NULL; } /* ---------------------------------------------------------------------- create an angle style, called from input script or restart file ------------------------------------------------------------------------- */ void Force::create_angle(const char *style, int trysuffix) { delete [] angle_style; if (angle) delete angle; int sflag; angle = new_angle(style,trysuffix,sflag); store_style(angle_style,style,sflag); } /* ---------------------------------------------------------------------- generate an angle class ------------------------------------------------------------------------- */ Angle *Force::new_angle(const char *style, int trysuffix, int &sflag) { if (trysuffix && lmp->suffix_enable) { if (lmp->suffix) { sflag = 1; char estyle[256]; sprintf(estyle,"%s/%s",style,lmp->suffix); if (angle_map->find(estyle) != angle_map->end()) { AngleCreator angle_creator = (*angle_map)[estyle]; return angle_creator(lmp); } } if (lmp->suffix2) { sflag = 2; char estyle[256]; sprintf(estyle,"%s/%s",style,lmp->suffix); if (angle_map->find(estyle) != angle_map->end()) { AngleCreator angle_creator = (*angle_map)[estyle]; return angle_creator(lmp); } } } sflag = 0; if (strcmp(style,"none") == 0) return NULL; if (angle_map->find(style) != angle_map->end()) { AngleCreator angle_creator = (*angle_map)[style]; return angle_creator(lmp); } error->all(FLERR,"Unknown angle style"); return NULL; } /* ---------------------------------------------------------------------- one instance per angle style in style_angle.h ------------------------------------------------------------------------- */ template Angle *Force::angle_creator(LAMMPS *lmp) { return new T(lmp); } /* ---------------------------------------------------------------------- return ptr to current angle class or hybrid sub-class if matches style ------------------------------------------------------------------------- */ Angle *Force::angle_match(const char *style) { if (strcmp(angle_style,style) == 0) return angle; else if (strcmp(angle_style,"hybrid") == 0) { AngleHybrid *hybrid = (AngleHybrid *) angle; for (int i = 0; i < hybrid->nstyles; i++) if (strcmp(hybrid->keywords[i],style) == 0) return hybrid->styles[i]; } return NULL; } /* ---------------------------------------------------------------------- create a dihedral style, called from input script or restart file ------------------------------------------------------------------------- */ void Force::create_dihedral(const char *style, int trysuffix) { delete [] dihedral_style; if (dihedral) delete dihedral; int sflag; dihedral = new_dihedral(style,trysuffix,sflag); store_style(dihedral_style,style,sflag); } /* ---------------------------------------------------------------------- generate a dihedral class ------------------------------------------------------------------------- */ Dihedral *Force::new_dihedral(const char *style, int trysuffix, int &sflag) { if (trysuffix && lmp->suffix_enable) { if (lmp->suffix) { sflag = 1; char estyle[256]; sprintf(estyle,"%s/%s",style,lmp->suffix); if (dihedral_map->find(estyle) != dihedral_map->end()) { DihedralCreator dihedral_creator = (*dihedral_map)[estyle]; return dihedral_creator(lmp); } } if (lmp->suffix2) { sflag = 2; char estyle[256]; sprintf(estyle,"%s/%s",style,lmp->suffix2); if (dihedral_map->find(estyle) != dihedral_map->end()) { DihedralCreator dihedral_creator = (*dihedral_map)[estyle]; return dihedral_creator(lmp); } } } sflag = 0; if (strcmp(style,"none") == 0) return NULL; if (dihedral_map->find(style) != dihedral_map->end()) { DihedralCreator dihedral_creator = (*dihedral_map)[style]; return dihedral_creator(lmp); } error->all(FLERR,"Unknown dihedral style"); return NULL; } /* ---------------------------------------------------------------------- one instance per dihedral style in style_dihedral.h ------------------------------------------------------------------------- */ template Dihedral *Force::dihedral_creator(LAMMPS *lmp) { return new T(lmp); } /* ---------------------------------------------------------------------- return ptr to current angle class or hybrid sub-class if matches style ------------------------------------------------------------------------- */ Dihedral *Force::dihedral_match(const char *style) { if (strcmp(dihedral_style,style) == 0) return dihedral; else if (strcmp(dihedral_style,"hybrid") == 0) { DihedralHybrid *hybrid = (DihedralHybrid *) dihedral; for (int i = 0; i < hybrid->nstyles; i++) if (strcmp(hybrid->keywords[i],style) == 0) return hybrid->styles[i]; } return NULL; } /* ---------------------------------------------------------------------- create an improper style, called from input script or restart file ------------------------------------------------------------------------- */ void Force::create_improper(const char *style, int trysuffix) { delete [] improper_style; if (improper) delete improper; int sflag; improper = new_improper(style,trysuffix,sflag); store_style(improper_style,style,sflag); } /* ---------------------------------------------------------------------- generate a improper class ------------------------------------------------------------------------- */ Improper *Force::new_improper(const char *style, int trysuffix, int &sflag) { if (trysuffix && lmp->suffix_enable) { if (lmp->suffix) { sflag = 1; char estyle[256]; sprintf(estyle,"%s/%s",style,lmp->suffix); if (improper_map->find(estyle) != improper_map->end()) { ImproperCreator improper_creator = (*improper_map)[estyle]; return improper_creator(lmp); } } if (lmp->suffix2) { sflag = 2; char estyle[256]; sprintf(estyle,"%s/%s",style,lmp->suffix2); if (improper_map->find(estyle) != improper_map->end()) { ImproperCreator improper_creator = (*improper_map)[estyle]; return improper_creator(lmp); } } } sflag = 0; if (strcmp(style,"none") == 0) return NULL; if (improper_map->find(style) != improper_map->end()) { ImproperCreator improper_creator = (*improper_map)[style]; return improper_creator(lmp); } error->all(FLERR,"Unknown improper style"); return NULL; } /* ---------------------------------------------------------------------- one instance per improper style in style_improper.h ------------------------------------------------------------------------- */ template Improper *Force::improper_creator(LAMMPS *lmp) { return new T(lmp); } /* ---------------------------------------------------------------------- return ptr to current improper class or hybrid sub-class if matches style ------------------------------------------------------------------------- */ Improper *Force::improper_match(const char *style) { if (strcmp(improper_style,style) == 0) return improper; else if (strcmp(improper_style,"hybrid") == 0) { ImproperHybrid *hybrid = (ImproperHybrid *) improper; for (int i = 0; i < hybrid->nstyles; i++) if (strcmp(hybrid->keywords[i],style) == 0) return hybrid->styles[i]; } return NULL; } /* ---------------------------------------------------------------------- new kspace style ------------------------------------------------------------------------- */ void Force::create_kspace(int narg, char **arg, int trysuffix) { delete [] kspace_style; if (kspace) delete kspace; int sflag; kspace = new_kspace(narg,arg,trysuffix,sflag); store_style(kspace_style,arg[0],sflag); if (comm->style == 1 && !kspace_match("ewald",0)) error->all(FLERR, "Cannot yet use KSpace solver with grid with comm style tiled"); } /* ---------------------------------------------------------------------- generate a kspace class ------------------------------------------------------------------------- */ KSpace *Force::new_kspace(int narg, char **arg, int trysuffix, int &sflag) { if (trysuffix && lmp->suffix_enable) { if (lmp->suffix) { sflag = 1; char estyle[256]; sprintf(estyle,"%s/%s",arg[0],lmp->suffix); if (kspace_map->find(estyle) != kspace_map->end()) { KSpaceCreator kspace_creator = (*kspace_map)[estyle]; return kspace_creator(lmp, narg-1, &arg[1]); } } if (lmp->suffix2) { sflag = 1; char estyle[256]; sprintf(estyle,"%s/%s",arg[0],lmp->suffix2); if (kspace_map->find(estyle) != kspace_map->end()) { KSpaceCreator kspace_creator = (*kspace_map)[estyle]; return kspace_creator(lmp, narg-1, &arg[1]); } } } sflag = 0; if (strcmp(arg[0],"none") == 0) return NULL; if (kspace_map->find(arg[0]) != kspace_map->end()) { KSpaceCreator kspace_creator = (*kspace_map)[arg[0]]; return kspace_creator(lmp, narg-1, &arg[1]); } error->all(FLERR,"Unknown kspace style"); return NULL; } /* ---------------------------------------------------------------------- one instance per kspace style in style_kspace.h ------------------------------------------------------------------------- */ template KSpace *Force::kspace_creator(LAMMPS *lmp, int narg, char ** arg) { return new T(lmp, narg, arg); } /* ---------------------------------------------------------------------- return ptr to Kspace class if matches word if exact, then style name must be exact match to word if not exact, style name must contain word return NULL if no match ------------------------------------------------------------------------- */ KSpace *Force::kspace_match(const char *word, int exact) { if (exact && strcmp(kspace_style,word) == 0) return kspace; else if (!exact && strstr(kspace_style,word)) return kspace; return NULL; } /* ---------------------------------------------------------------------- store style name in str allocated here if sflag = 0, no suffix if sflag = 1/2, append suffix or suffix2 to style ------------------------------------------------------------------------- */ void Force::store_style(char *&str, const char *style, int sflag) { if (sflag) { char estyle[256]; if (sflag == 1) sprintf(estyle,"%s/%s",style,lmp->suffix); else sprintf(estyle,"%s/%s",style,lmp->suffix2); int n = strlen(estyle) + 1; str = new char[n]; strcpy(str,estyle); } else { int n = strlen(style) + 1; str = new char[n]; strcpy(str,style); } } /* ---------------------------------------------------------------------- set special bond values ------------------------------------------------------------------------- */ void Force::set_special(int narg, char **arg) { if (narg == 0) error->all(FLERR,"Illegal special_bonds command"); // defaults, but do not reset special_extra special_lj[1] = special_lj[2] = special_lj[3] = 0.0; special_coul[1] = special_coul[2] = special_coul[3] = 0.0; special_angle = special_dihedral = 0; int iarg = 0; while (iarg < narg) { if (strcmp(arg[iarg],"amber") == 0) { if (iarg+1 > narg) error->all(FLERR,"Illegal special_bonds command"); special_lj[1] = 0.0; special_lj[2] = 0.0; special_lj[3] = 0.5; special_coul[1] = 0.0; special_coul[2] = 0.0; special_coul[3] = 5.0/6.0; iarg += 1; } else if (strcmp(arg[iarg],"charmm") == 0) { if (iarg+1 > narg) error->all(FLERR,"Illegal special_bonds command"); special_lj[1] = 0.0; special_lj[2] = 0.0; special_lj[3] = 0.0; special_coul[1] = 0.0; special_coul[2] = 0.0; special_coul[3] = 0.0; iarg += 1; } else if (strcmp(arg[iarg],"dreiding") == 0) { if (iarg+1 > narg) error->all(FLERR,"Illegal special_bonds command"); special_lj[1] = 0.0; special_lj[2] = 0.0; special_lj[3] = 1.0; special_coul[1] = 0.0; special_coul[2] = 0.0; special_coul[3] = 1.0; iarg += 1; } else if (strcmp(arg[iarg],"fene") == 0) { if (iarg+1 > narg) error->all(FLERR,"Illegal special_bonds command"); special_lj[1] = 0.0; special_lj[2] = 1.0; special_lj[3] = 1.0; special_coul[1] = 0.0; special_coul[2] = 1.0; special_coul[3] = 1.0; iarg += 1; } else if (strcmp(arg[iarg],"lj/coul") == 0) { if (iarg+4 > narg) error->all(FLERR,"Illegal special_bonds command"); special_lj[1] = special_coul[1] = numeric(FLERR,arg[iarg+1]); special_lj[2] = special_coul[2] = numeric(FLERR,arg[iarg+2]); special_lj[3] = special_coul[3] = numeric(FLERR,arg[iarg+3]); iarg += 4; } else if (strcmp(arg[iarg],"lj") == 0) { if (iarg+4 > narg) error->all(FLERR,"Illegal special_bonds command"); special_lj[1] = numeric(FLERR,arg[iarg+1]); special_lj[2] = numeric(FLERR,arg[iarg+2]); special_lj[3] = numeric(FLERR,arg[iarg+3]); iarg += 4; } else if (strcmp(arg[iarg],"coul") == 0) { if (iarg+4 > narg) error->all(FLERR,"Illegal special_bonds command"); special_coul[1] = numeric(FLERR,arg[iarg+1]); special_coul[2] = numeric(FLERR,arg[iarg+2]); special_coul[3] = numeric(FLERR,arg[iarg+3]); iarg += 4; } else if (strcmp(arg[iarg],"angle") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal special_bonds command"); if (strcmp(arg[iarg+1],"no") == 0) special_angle = 0; else if (strcmp(arg[iarg+1],"yes") == 0) special_angle = 1; else error->all(FLERR,"Illegal special_bonds command"); iarg += 2; } else if (strcmp(arg[iarg],"dihedral") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal special_bonds command"); if (strcmp(arg[iarg+1],"no") == 0) special_dihedral = 0; else if (strcmp(arg[iarg+1],"yes") == 0) special_dihedral = 1; else error->all(FLERR,"Illegal special_bonds command"); iarg += 2; } else if (strcmp(arg[iarg],"extra") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal special_bonds command"); special_extra = atoi(arg[iarg+1]); iarg += 2; } else error->all(FLERR,"Illegal special_bonds command"); } for (int i = 1; i <= 3; i++) if (special_lj[i] < 0.0 || special_lj[i] > 1.0 || special_coul[i] < 0.0 || special_coul[i] > 1.0) error->all(FLERR,"Illegal special_bonds command"); if (special_extra < 0) error->all(FLERR,"Illegal special_bonds command"); } /* ---------------------------------------------------------------------- compute bounds implied by numeric str with a possible wildcard asterik 1 = lower bound, nmax = upper bound 5 possibilities: (1) i = i to i, (2) * = nmin to nmax, (3) i* = i to nmax, (4) *j = nmin to j, (5) i*j = i to j return nlo,nhi ------------------------------------------------------------------------- */ -void Force::bounds(char *str, int nmax, int &nlo, int &nhi, int nmin) +void Force::bounds(const char *file, int line, char *str, + int nmax, int &nlo, int &nhi, int nmin) { char *ptr = strchr(str,'*'); if (ptr == NULL) { nlo = nhi = atoi(str); } else if (strlen(str) == 1) { nlo = nmin; nhi = nmax; } else if (ptr == str) { nlo = nmin; nhi = atoi(ptr+1); } else if (strlen(ptr+1) == 0) { nlo = atoi(str); nhi = nmax; } else { nlo = atoi(str); nhi = atoi(ptr+1); } if (nlo < nmin || nhi > nmax || nlo > nhi) - error->all(FLERR,"Numeric index is out of bounds"); + error->all(file,line,"Numeric index is out of bounds"); } /* ---------------------------------------------------------------------- compute bounds implied by numeric str with a possible wildcard asterik 1 = lower bound, nmax = upper bound 5 possibilities: (1) i = i to i, (2) * = nmin to nmax, (3) i* = i to nmax, (4) *j = nmin to j, (5) i*j = i to j return nlo,nhi ------------------------------------------------------------------------- */ -void Force::boundsbig(char *str, bigint nmax, bigint &nlo, bigint &nhi, - bigint nmin) +void Force::boundsbig(const char *file, int line, char *str, + bigint nmax, bigint &nlo, bigint &nhi, bigint nmin) { char *ptr = strchr(str,'*'); if (ptr == NULL) { nlo = nhi = ATOBIGINT(str); } else if (strlen(str) == 1) { nlo = nmin; nhi = nmax; } else if (ptr == str) { nlo = nmin; nhi = ATOBIGINT(ptr+1); } else if (strlen(ptr+1) == 0) { nlo = ATOBIGINT(str); nhi = nmax; } else { nlo = ATOBIGINT(str); nhi = ATOBIGINT(ptr+1); } if (nlo < nmin || nhi > nmax || nlo > nhi) - error->all(FLERR,"Numeric index is out of bounds"); + error->all(file,line,"Numeric index is out of bounds"); } /* ---------------------------------------------------------------------- read a floating point value from a string generate an error if not a legitimate floating point value called by various commands to check validity of their arguments ------------------------------------------------------------------------- */ double Force::numeric(const char *file, int line, char *str) { if (!str) error->all(file,line,"Expected floating point parameter " "in input script or data file"); int n = strlen(str); if (n == 0) error->all(file,line,"Expected floating point parameter " "in input script or data file"); for (int i = 0; i < n; i++) { if (isdigit(str[i])) continue; if (str[i] == '-' || str[i] == '+' || str[i] == '.') continue; if (str[i] == 'e' || str[i] == 'E') continue; error->all(file,line,"Expected floating point parameter " "in input script or data file"); } return atof(str); } /* ---------------------------------------------------------------------- read an integer value from a string generate an error if not a legitimate integer value called by various commands to check validity of their arguments ------------------------------------------------------------------------- */ int Force::inumeric(const char *file, int line, char *str) { if (!str) error->all(file,line, "Expected integer parameter in input script or data file"); int n = strlen(str); if (n == 0) error->all(file,line, "Expected integer parameter in input script or data file"); for (int i = 0; i < n; i++) { if (isdigit(str[i]) || str[i] == '-' || str[i] == '+') continue; error->all(file,line, "Expected integer parameter in input script or data file"); } return atoi(str); } /* ---------------------------------------------------------------------- read a big integer value from a string generate an error if not a legitimate integer value called by various commands to check validity of their arguments ------------------------------------------------------------------------- */ bigint Force::bnumeric(const char *file, int line, char *str) { if (!str) error->all(file,line, "Expected integer parameter in input script or data file"); int n = strlen(str); if (n == 0) error->all(file,line, "Expected integer parameter in input script or data file"); for (int i = 0; i < n; i++) { if (isdigit(str[i]) || str[i] == '-' || str[i] == '+') continue; error->all(file,line, "Expected integer parameter in input script or data file"); } return ATOBIGINT(str); } /* ---------------------------------------------------------------------- read a tag integer value from a string generate an error if not a legitimate integer value called by various commands to check validity of their arguments ------------------------------------------------------------------------- */ tagint Force::tnumeric(const char *file, int line, char *str) { if (!str) error->all(file,line, "Expected integer parameter in input script or data file"); int n = strlen(str); if (n == 0) error->all(file,line, "Expected integer parameter in input script or data file"); for (int i = 0; i < n; i++) { if (isdigit(str[i]) || str[i] == '-' || str[i] == '+') continue; error->all(file,line, "Expected integer parameter in input script or data file"); } return ATOTAGINT(str); } /* ---------------------------------------------------------------------- open a potential file as specified by name if fails, search in dir specified by env variable LAMMPS_POTENTIALS ------------------------------------------------------------------------- */ FILE *Force::open_potential(const char *name) { FILE *fp; if (name == NULL) return NULL; // attempt to open file directly // if successful, return ptr fp = fopen(name,"r"); if (fp) { if (comm->me == 0) potential_date(fp,name); rewind(fp); return fp; } // try the environment variable directory const char *path = getenv("LAMMPS_POTENTIALS"); if (path == NULL) return NULL; const char *pot = potential_name(name); if (pot == NULL) return NULL; size_t len1 = strlen(path); size_t len2 = strlen(pot); char *newpath = new char[len1+len2+2]; strcpy(newpath,path); #if defined(_WIN32) newpath[len1] = '\\'; newpath[len1+1] = 0; #else newpath[len1] = '/'; newpath[len1+1] = 0; #endif strcat(newpath,pot); fp = fopen(newpath,"r"); if (fp) { if (comm->me == 0) potential_date(fp,name); rewind(fp); } delete [] newpath; return fp; } /* ---------------------------------------------------------------------- strip off leading part of path, return just the filename ------------------------------------------------------------------------- */ const char *Force::potential_name(const char *path) { const char *pot; if (path == NULL) return NULL; #if defined(_WIN32) // skip over the disk drive part of windows pathnames if (isalpha(path[0]) && path[1] == ':') path += 2; #endif for (pot = path; *path != '\0'; ++path) { #if defined(_WIN32) if ((*path == '\\') || (*path == '/')) pot = path + 1; #else if (*path == '/') pot = path + 1; #endif } return pot; } /* ---------------------------------------------------------------------- read first line of potential file if has DATE field, print following word ------------------------------------------------------------------------- */ void Force::potential_date(FILE *fp, const char *name) { char line[MAXLINE]; char *ptr = fgets(line,MAXLINE,fp); if (ptr == NULL) return; char *word; word = strtok(line," \t\n\r\f"); while (word) { if (strcmp(word,"DATE:") == 0) { word = strtok(NULL," \t\n\r\f"); if (word == NULL) return; if (screen) fprintf(screen,"Reading potential file %s with DATE: %s\n",name,word); if (logfile) fprintf(logfile,"Reading potential file %s with DATE: %s\n",name,word); return; } word = strtok(NULL," \t\n\r\f"); } } /* ---------------------------------------------------------------------- memory usage of force classes ------------------------------------------------------------------------- */ bigint Force::memory_usage() { bigint bytes = 0; if (pair) bytes += static_cast (pair->memory_usage()); if (bond) bytes += static_cast (bond->memory_usage()); if (angle) bytes += static_cast (angle->memory_usage()); if (dihedral) bytes += static_cast (dihedral->memory_usage()); if (improper) bytes += static_cast (improper->memory_usage()); if (kspace) bytes += static_cast (kspace->memory_usage()); return bytes; } diff --git a/src/force.h b/src/force.h index 78788826a..f2d9abc7d 100644 --- a/src/force.h +++ b/src/force.h @@ -1,196 +1,196 @@ /* -*- c++ -*- ---------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #ifndef LMP_FORCE_H #define LMP_FORCE_H #include "pointers.h" #include #include #include namespace LAMMPS_NS { class Force : protected Pointers { public: double boltz; // Boltzmann constant (eng/degree-K) double hplanck; // Planck's constant (energy-time) double mvv2e; // conversion of mv^2 to energy double ftm2v; // conversion of ft/m to velocity double mv2d; // conversion of mass/volume to density double nktv2p; // conversion of NkT/V to pressure double qqr2e; // conversion of q^2/r to energy double qe2f; // conversion of qE to force double vxmu2f; // conversion of vx dynamic-visc to force double xxt2kmu; // conversion of xx/t to kinematic-visc double dielectric; // dielectric constant double qqrd2e; // q^2/r to energy w/ dielectric constant double e_mass; // electron mass double hhmrr2e; // conversion of (hbar)^2/(mr^2) to energy double mvh2r; // conversion of mv/hbar to distance // hbar = h/(2*pi) double angstrom; // 1 angstrom in native units double femtosecond; // 1 femtosecond in native units double qelectron; // 1 electron charge abs() in native units int newton,newton_pair,newton_bond; // Newton's 3rd law settings class Pair *pair; char *pair_style; class Bond *bond; char *bond_style; class Angle *angle; char *angle_style; class Dihedral *dihedral; char *dihedral_style; class Improper *improper; char *improper_style; class KSpace *kspace; char *kspace_style; typedef Pair *(*PairCreator)(LAMMPS *); typedef Bond *(*BondCreator)(LAMMPS *); typedef Angle *(*AngleCreator)(LAMMPS *); typedef Dihedral *(*DihedralCreator)(LAMMPS *); typedef Improper *(*ImproperCreator)(LAMMPS *); typedef KSpace *(*KSpaceCreator)(LAMMPS *,int,char**); typedef std::map PairCreatorMap; typedef std::map BondCreatorMap; typedef std::map AngleCreatorMap; typedef std::map DihedralCreatorMap; typedef std::map ImproperCreatorMap; typedef std::map KSpaceCreatorMap; PairCreatorMap *pair_map; BondCreatorMap *bond_map; AngleCreatorMap *angle_map; DihedralCreatorMap *dihedral_map; ImproperCreatorMap *improper_map; KSpaceCreatorMap *kspace_map; // index [0] is not used in these arrays double special_lj[4]; // 1-2, 1-3, 1-4 prefactors for LJ double special_coul[4]; // 1-2, 1-3, 1-4 prefactors for Coulombics int special_angle; // 0 if defined angles are ignored // 1 if only weight 1,3 atoms if in an angle int special_dihedral; // 0 if defined dihedrals are ignored // 1 if only weight 1,4 atoms if in a dihedral int special_extra; // extra space for added bonds Force(class LAMMPS *); ~Force(); void init(); void setup(); void create_pair(const char *, int); class Pair *new_pair(const char *, int, int &); class Pair *pair_match(const char *, int, int nsub=0); char *pair_match_ptr(Pair *); void create_bond(const char *, int); class Bond *new_bond(const char *, int, int &); class Bond *bond_match(const char *); void create_angle(const char *, int); class Angle *new_angle(const char *, int, int &); class Angle *angle_match(const char *); void create_dihedral(const char *, int); class Dihedral *new_dihedral(const char *, int, int &); class Dihedral *dihedral_match(const char *); void create_improper(const char *, int); class Improper *new_improper(const char *, int, int &); class Improper *improper_match(const char *); void create_kspace(int, char **, int); class KSpace *new_kspace(int, char **, int, int &); class KSpace *kspace_match(const char *, int); void store_style(char *&, const char *, int); void set_special(int, char **); - void bounds(char *, int, int &, int &, int nmin=1); - void boundsbig(char *, bigint, bigint &, bigint &, bigint nmin=1); + void bounds(const char *, int, char *, int, int &, int &, int nmin=1); + void boundsbig(const char *, int, char *, bigint, bigint &, bigint &, bigint nmin=1); double numeric(const char *, int, char *); int inumeric(const char *, int, char *); bigint bnumeric(const char *, int, char *); tagint tnumeric(const char *, int, char *); FILE *open_potential(const char *); const char *potential_name(const char *); void potential_date(FILE *, const char *); bigint memory_usage(); private: template static Pair *pair_creator(LAMMPS *); template static Bond *bond_creator(LAMMPS *); template static Angle *angle_creator(LAMMPS *); template static Dihedral *dihedral_creator(LAMMPS *); template static Improper *improper_creator(LAMMPS *); template static KSpace *kspace_creator(LAMMPS *, int, char **); }; } #endif /* ERROR/WARNING messages: E: Unknown pair style The choice of pair style is unknown. E: Unknown bond style The choice of bond style is unknown. E: Unknown angle style The choice of angle style is unknown. E: Unknown dihedral style The choice of dihedral style is unknown. E: Unknown improper style The choice of improper style is unknown. E: Cannot yet use KSpace solver with grid with comm style tiled This is current restriction in LAMMPS. E: Unknown kspace style The choice of kspace style is unknown. 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: Numeric index is out of bounds A command with an argument that specifies an integer or range of integers is using a value that is less than 1 or greater than the maximum allowed limit. */ diff --git a/src/improper_hybrid.cpp b/src/improper_hybrid.cpp index d819365b7..78ee69569 100644 --- a/src/improper_hybrid.cpp +++ b/src/improper_hybrid.cpp @@ -1,350 +1,350 @@ /* ---------------------------------------------------------------------- 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 #include #include #include "improper_hybrid.h" #include "atom.h" #include "neighbor.h" #include "domain.h" #include "comm.h" #include "force.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define EXTRA 1000 /* ---------------------------------------------------------------------- */ ImproperHybrid::ImproperHybrid(LAMMPS *lmp) : Improper(lmp) { nstyles = 0; } /* ---------------------------------------------------------------------- */ ImproperHybrid::~ImproperHybrid() { if (nstyles) { for (int i = 0; i < nstyles; i++) delete styles[i]; delete [] styles; for (int i = 0; i < nstyles; i++) delete [] keywords[i]; delete [] keywords; } if (allocated) { memory->destroy(setflag); memory->destroy(map); delete [] nimproperlist; delete [] maximproper; for (int i = 0; i < nstyles; i++) memory->destroy(improperlist[i]); delete [] improperlist; } } /* ---------------------------------------------------------------------- */ void ImproperHybrid::compute(int eflag, int vflag) { int i,j,m,n; // save ptrs to original improperlist int nimproperlist_orig = neighbor->nimproperlist; int **improperlist_orig = neighbor->improperlist; // if this is re-neighbor step, create sub-style improperlists // nimproperlist[] = length of each sub-style list // realloc sub-style improperlist if necessary // load sub-style improperlist with 5 values from original improperlist if (neighbor->ago == 0) { for (m = 0; m < nstyles; m++) nimproperlist[m] = 0; for (i = 0; i < nimproperlist_orig; i++) { m = map[improperlist_orig[i][4]]; if (m >= 0) nimproperlist[m]++; } for (m = 0; m < nstyles; m++) { if (nimproperlist[m] > maximproper[m]) { memory->destroy(improperlist[m]); maximproper[m] = nimproperlist[m] + EXTRA; memory->create(improperlist[m],maximproper[m],5, "improper_hybrid:improperlist"); } nimproperlist[m] = 0; } for (i = 0; i < nimproperlist_orig; i++) { m = map[improperlist_orig[i][4]]; if (m < 0) continue; n = nimproperlist[m]; improperlist[m][n][0] = improperlist_orig[i][0]; improperlist[m][n][1] = improperlist_orig[i][1]; improperlist[m][n][2] = improperlist_orig[i][2]; improperlist[m][n][3] = improperlist_orig[i][3]; improperlist[m][n][4] = improperlist_orig[i][4]; nimproperlist[m]++; } } // call each sub-style's compute function // set neighbor->improperlist to sub-style improperlist before call // accumulate sub-style global/peratom energy/virial in hybrid if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; for (m = 0; m < nstyles; m++) { neighbor->nimproperlist = nimproperlist[m]; neighbor->improperlist = improperlist[m]; styles[m]->compute(eflag,vflag); if (eflag_global) energy += styles[m]->energy; if (vflag_global) for (n = 0; n < 6; n++) virial[n] += styles[m]->virial[n]; if (eflag_atom) { n = atom->nlocal; if (force->newton_bond) 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_bond) 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]; } } // restore ptrs to original improperlist neighbor->nimproperlist = nimproperlist_orig; neighbor->improperlist = improperlist_orig; } /* ---------------------------------------------------------------------- */ void ImproperHybrid::allocate() { allocated = 1; int n = atom->nimpropertypes; memory->create(map,n+1,"improper:map"); memory->create(setflag,n+1,"improper:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; nimproperlist = new int[nstyles]; maximproper = new int[nstyles]; improperlist = new int**[nstyles]; for (int m = 0; m < nstyles; m++) maximproper[m] = 0; for (int m = 0; m < nstyles; m++) improperlist[m] = NULL; } /* ---------------------------------------------------------------------- */ void ImproperHybrid::init_style() { for (int i = 0; i < nstyles; i++) styles[i]->init_style(); } /* ---------------------------------------------------------------------- create one improper style for each arg in list ------------------------------------------------------------------------- */ void ImproperHybrid::settings(int narg, char **arg) { int i,m,istyle; if (narg < 1) error->all(FLERR,"Illegal improper_style command"); // delete old lists, since cannot just change settings if (nstyles) { for (int i = 0; i < nstyles; i++) delete styles[i]; delete [] styles; for (int i = 0; i < nstyles; i++) delete [] keywords[i]; delete [] keywords; } if (allocated) { memory->destroy(setflag); memory->destroy(map); delete [] nimproperlist; delete [] maximproper; for (int i = 0; i < nstyles; i++) memory->destroy(improperlist[i]); delete [] improperlist; } allocated = 0; // count sub-styles by skipping numeric args // one exception is 1st arg of style "table", which is non-numeric word // need a better way to skip these exceptions nstyles = 0; i = 0; while (i < narg) { if (strcmp(arg[i],"table") == 0) i++; i++; while (i < narg && !isalpha(arg[i][0])) i++; nstyles++; } // allocate list of sub-styles styles = new Improper*[nstyles]; keywords = new char*[nstyles]; // allocate each sub-style and call its settings() with subset of args // allocate uses suffix, but don't store suffix version in keywords, // else syntax in coeff() will not match // define subset of args for a sub-style by skipping numeric args // one exception is 1st arg of style "table", which is non-numeric // 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,"Improper style hybrid cannot use " "same improper style twice"); if (strcmp(arg[i],"hybrid") == 0) error->all(FLERR, "Improper style hybrid cannot have hybrid as an argument"); if (strcmp(arg[i],"none") == 0) error->all(FLERR,"Improper style hybrid cannot have none as an argument"); styles[nstyles] = force->new_improper(arg[i],1,dummy); force->store_style(keywords[nstyles],arg[i],0); istyle = i; if (strcmp(arg[i],"table") == 0) i++; i++; while (i < narg && !isalpha(arg[i][0])) i++; styles[nstyles]->settings(i-istyle-1,&arg[istyle+1]); nstyles++; } } /* ---------------------------------------------------------------------- set coeffs for one type ---------------------------------------------------------------------- */ void ImproperHybrid::coeff(int narg, char **arg) { if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->nimpropertypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->nimpropertypes,ilo,ihi); // 2nd arg = improper sub-style name // allow for "none" as valid sub-style name int m; for (m = 0; m < nstyles; m++) if (strcmp(arg[1],keywords[m]) == 0) break; int none = 0; if (m == nstyles) { if (strcmp(arg[1],"none") == 0) none = 1; else error->all(FLERR,"Improper coeff for hybrid has invalid style"); } // move 1st arg to 2nd arg // just copy ptrs, since arg[] points into original input line arg[1] = arg[0]; // invoke sub-style coeff() starting with 1st arg if (!none) styles[m]->coeff(narg-1,&arg[1]); // set setflag and which type maps to which sub-style // if sub-style is none: set hybrid setflag, wipe out map for (int i = ilo; i <= ihi; i++) { if (none) { setflag[i] = 1; map[i] = -1; } else { setflag[i] = styles[m]->setflag[i]; map[i] = m; } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void ImproperHybrid::write_restart(FILE *fp) { fwrite(&nstyles,sizeof(int),1,fp); 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); } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void ImproperHybrid::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 Improper*[nstyles]; keywords = new char*[nstyles]; allocate(); 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_improper(keywords[m],0,dummy); } } /* ---------------------------------------------------------------------- memory usage ------------------------------------------------------------------------- */ double ImproperHybrid::memory_usage() { double bytes = maxeatom * sizeof(double); bytes += maxvatom*6 * sizeof(double); for (int m = 0; m < nstyles; m++) bytes += maximproper[m]*5 * sizeof(int); for (int m = 0; m < nstyles; m++) if (styles[m]) bytes += styles[m]->memory_usage(); return bytes; } diff --git a/src/improper_zero.cpp b/src/improper_zero.cpp index 958f66216..556e427ff 100644 --- a/src/improper_zero.cpp +++ b/src/improper_zero.cpp @@ -1,122 +1,122 @@ /* ---------------------------------------------------------------------- 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: Carsten Svaneborg (SDU) ------------------------------------------------------------------------- */ #include #include #include #include "improper_zero.h" #include "atom.h" #include "force.h" #include "comm.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ ImproperZero::ImproperZero(LAMMPS *lmp) : Improper(lmp), coeffflag(1) {} /* ---------------------------------------------------------------------- */ ImproperZero::~ImproperZero() { if (allocated && !copymode) { memory->destroy(setflag); } } /* ---------------------------------------------------------------------- */ void ImproperZero::compute(int eflag, int vflag) { if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; } /* ---------------------------------------------------------------------- */ void ImproperZero::settings(int narg, char **arg) { if ((narg != 0) && (narg != 1)) error->all(FLERR,"Illegal improper_style command"); if (narg == 1) { if (strcmp("nocoeff",arg[0]) == 0) coeffflag=0; else error->all(FLERR,"Illegal improper_style command"); } } /* ---------------------------------------------------------------------- */ void ImproperZero::allocate() { allocated = 1; int n = atom->nimpropertypes; memory->create(setflag,n+1,"improper:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one or more types ------------------------------------------------------------------------- */ void ImproperZero::coeff(int narg, char **arg) { if ((narg < 1) || (coeffflag && narg > 1)) error->all(FLERR,"Incorrect args for improper coefficients"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->nimpropertypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->nimpropertypes,ilo,ihi); int count = 0; for (int i = ilo; i <= ihi; i++) { setflag[i] = 1; count++; } if (count == 0) error->all(FLERR,"Incorrect args for improper coefficients"); } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void ImproperZero::write_restart(FILE *fp) {} /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void ImproperZero::read_restart(FILE *fp) { allocate(); for (int i = 1; i <= atom->nimpropertypes; i++) setflag[i] = 1; } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void ImproperZero::write_data(FILE *fp) { for (int i = 1; i <= atom->nimpropertypes; i++) fprintf(fp,"%d\n",i); } diff --git a/src/input.cpp b/src/input.cpp index 905e7f059..d1343ee38 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -1,1982 +1,1982 @@ /* ---------------------------------------------------------------------- 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 #include #include #include #include #include #include #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 "comm_brick.h" #include "comm_tiled.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 "fix.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 "timer.h" #include "variable.h" #include "accelerator_kokkos.h" #include "error.h" #include "memory.h" #ifdef _OPENMP #include #endif #ifdef _WIN32 #include #endif using namespace LAMMPS_NS; #define DELTALINE 256 #define DELTA 4 /* ---------------------------------------------------------------------- */ Input::Input(LAMMPS *lmp, int argc, char **argv) : Pointers(lmp) { MPI_Comm_rank(world,&me); maxline = maxcopy = maxwork = 0; line = copy = work = NULL; narg = maxarg = 0; arg = NULL; echo_screen = 0; echo_log = 1; label_active = 0; labelstr = NULL; jump_skip = 0; ifthenelse_flag = 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); // fill map with commands listed in style_command.h command_map = new CommandCreatorMap(); #define COMMAND_CLASS #define CommandStyle(key,Class) \ (*command_map)[#key] = &command_creator; #include "style_command.h" #undef CommandStyle #undef COMMAND_CLASS // process command-line args // check for args "-var" and "-echo" // caller has already checked that sufficient arguments exist int iarg = 1; 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 memory->sfree(line); memory->sfree(copy); memory->sfree(work); if (labelstr) delete [] labelstr; memory->sfree(arg); memory->sfree(infiles); delete variable; delete command_map; } /* ---------------------------------------------------------------------- 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 // n = length of line including str terminator, 0 if end of file // if line ends in continuation char '&', concatenate next line if (me == 0) { m = 0; while (1) { if (maxline-m < 2) reallocate(line,maxline,0); // end of file reached, so break // n == 0 if nothing read, else n = line with str terminator if (fgets(&line[m],maxline-m,infile) == NULL) { if (m) n = strlen(line) + 1; else n = 0; break; } // continue if last char read was not a newline // could happen if line is very long m = strlen(line); if (line[m-1] != '\n') continue; // continue reading if final printable char is & char // or if odd number of triple quotes // else break with n = line with str terminator m--; while (m >= 0 && isspace(line[m])) m--; if (m < 0 || line[m] != '&') { if (numtriple(line) % 2) { m += 2; continue; } line[m+1] = '\0'; n = m+2; 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); infile = NULL; } nfile--; } MPI_Bcast(&nfile,1,MPI_INT,0,world); if (nfile == 0) break; if (me == 0) infile = infiles[nfile-1]; continue; } if (n > maxline) reallocate(line,maxline,n); MPI_Bcast(line,n,MPI_CHAR,0,world); // 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, 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 = new char[maxline+32]; sprintf(str,"Unknown command: %s",line); error->all(FLERR,str); } } } /* ---------------------------------------------------------------------- process all input from filename called from library interface ------------------------------------------------------------------------- */ void Input::file(const char *filename) { // error if another nested file still open, should not be possible // open new filename and set infile, infiles[0], nfile // call to file() will close filename and decrement nfile if (me == 0) { if (nfile > 1) error->one(FLERR,"Invalid use of library file() function"); if (infile && 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; nfile = 1; } file(); } /* ---------------------------------------------------------------------- copy command in single to line, parse and execute it return command name to caller ------------------------------------------------------------------------- */ char *Input::one(const char *single) { int n = strlen(single) + 1; if (n > maxline) reallocate(line,maxline,n); 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 = new char[maxline+32]; sprintf(str,"Unknown command: %s",line); error->all(FLERR,str); } return command; } /* ---------------------------------------------------------------------- parse copy of command line by inserting string terminators strip comment = all chars from # on replace all $ via variable substitution except within quotes command = first word narg = # of args arg[] = individual args treat text between single/double/triple quotes as one arg via nextword() ------------------------------------------------------------------------- */ void Input::parse() { // duplicate line into copy string to break into words int n = strlen(line) + 1; if (n > maxcopy) reallocate(copy,maxcopy,n); strcpy(copy,line); // strip any # comment by replacing it with 0 // do not strip from a # inside single/double/triple quotes // quoteflag = 1,2,3 when encounter first single/double,triple quote // quoteflag = 0 when encounter matching single/double,triple quote int quoteflag = 0; char *ptr = copy; while (*ptr) { if (*ptr == '#' && !quoteflag) { *ptr = '\0'; break; } if (quoteflag == 0) { if (strstr(ptr,"\"\"\"") == ptr) { quoteflag = 3; ptr += 2; } else if (*ptr == '"') quoteflag = 2; else if (*ptr == '\'') quoteflag = 1; } else { if (quoteflag == 3 && strstr(ptr,"\"\"\"") == ptr) { quoteflag = 0; ptr += 2; } else if (quoteflag == 2 && *ptr == '"') quoteflag = 0; else if (quoteflag == 1 && *ptr == '\'') quoteflag = 0; } ptr++; } // perform $ variable substitution (print changes) // except if searching for a label since earlier variable may not be defined if (!label_active) substitute(copy,work,maxcopy,maxwork,1); // command = 1st arg in copy string char *next; command = nextword(copy,&next); if (command == NULL) return; // point arg[] at each subsequent arg in copy string // nextword() inserts string terminators into copy string to delimit args // nextword() treats text between single/double/triple quotes as one arg narg = 0; ptr = next; while (ptr) { if (narg == maxarg) { maxarg += DELTA; arg = (char **) memory->srealloc(arg,maxarg*sizeof(char *),"input:arg"); } arg[narg] = nextword(ptr,&next); if (!arg[narg]) break; narg++; ptr = next; } } /* ---------------------------------------------------------------------- find next word in str insert 0 at end of word ignore leading whitespace treat text between single/double/triple quotes as one arg matching quote must be followed by whitespace char if not end of string strip quotes from returned word return ptr to start of word or NULL if no word in string also return next = ptr after word ------------------------------------------------------------------------- */ char *Input::nextword(char *str, char **next) { char *start,*stop; // start = first non-whitespace char start = &str[strspn(str," \t\n\v\f\r")]; if (*start == '\0') return NULL; // if start is single/double/triple quote: // start = first char beyond quote // stop = first char of matching quote // next = first char beyond matching quote // next must be NULL or whitespace // if start is not single/double/triple quote: // stop = first whitespace char after start // next = char after stop, or stop itself if stop is NULL if (strstr(start,"\"\"\"") == start) { stop = strstr(&start[3],"\"\"\""); if (!stop) error->all(FLERR,"Unbalanced quotes in input line"); start += 3; *next = stop+3; if (**next && !isspace(**next)) error->all(FLERR,"Input line quote not followed by whitespace"); } else if (*start == '"' || *start == '\'') { stop = strchr(&start[1],*start); if (!stop) error->all(FLERR,"Unbalanced quotes in input line"); start++; *next = stop+1; if (**next && !isspace(**next)) error->all(FLERR,"Input line quote not followed by whitespace"); } else { stop = &start[strcspn(start," \t\n\v\f\r")]; if (*stop == '\0') *next = stop; else *next = stop+1; } // set stop to NULL to terminate word *stop = '\0'; return start; } /* ---------------------------------------------------------------------- substitute for $ variables in str using work str2 and return it reallocate str/str2 to hold expanded version if necessary & reset max/max2 print updated string if flag is set and not searching for label label_active will be 0 if called from external class ------------------------------------------------------------------------- */ void Input::substitute(char *&str, char *&str2, int &max, int &max2, int flag) { // use str2 as scratch space to expand str, then copy back to str // reallocate str and str2 as necessary // do not replace $ inside single/double/triple quotes // var = pts at variable name, ended by NULL // if $ is followed by '{', trailing '}' becomes NULL // else $x becomes x followed by NULL // beyond = points to text following variable int i,n,paren_count; char immediate[256]; char *var,*value,*beyond; int quoteflag = 0; char *ptr = str; n = strlen(str) + 1; if (n > max2) reallocate(str2,max2,n); *str2 = '\0'; char *ptr2 = str2; while (*ptr) { // variable substitution if (*ptr == '$' && !quoteflag) { // value = ptr to expanded variable // variable name between curly braces, e.g. ${a} if (*(ptr+1) == '{') { var = ptr+2; 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; value = variable->retrieve(var); // immediate variable between parenthesis, e.g. $(1/2) } else if (*(ptr+1) == '(') { var = ptr+2; paren_count = 0; i = 0; while (var[i] != '\0' && !(var[i] == ')' && paren_count == 0)) { switch (var[i]) { case '(': paren_count++; break; case ')': paren_count--; break; default: ; } i++; } if (var[i] == '\0') error->one(FLERR,"Invalid immediate variable"); var[i] = '\0'; beyond = ptr + strlen(var) + 3; sprintf(immediate,"%.20g",variable->compute_equal(var)); value = immediate; // single character variable name, e.g. $a } else { var = ptr; var[0] = var[1]; var[1] = '\0'; beyond = ptr + 2; value = variable->retrieve(var); } if (value == NULL) error->one(FLERR,"Substitution for illegal variable"); // check if storage in str2 needs to be expanded // re-initialize ptr and ptr2 to the point beyond the variable. n = strlen(str2) + strlen(value) + strlen(beyond) + 1; if (n > max2) reallocate(str2,max2,n); strcat(str2,value); ptr2 = str2 + strlen(str2); ptr = beyond; // output substitution progress if requested if (flag && me == 0 && label_active == 0) { if (echo_screen && screen) fprintf(screen,"%s%s\n",str2,beyond); if (echo_log && logfile) fprintf(logfile,"%s%s\n",str2,beyond); } continue; } // quoteflag = 1,2,3 when encounter first single/double,triple quote // quoteflag = 0 when encounter matching single/double,triple quote // copy 2 extra triple quote chars into str2 if (quoteflag == 0) { if (strstr(ptr,"\"\"\"") == ptr) { quoteflag = 3; *ptr2++ = *ptr++; *ptr2++ = *ptr++; } else if (*ptr == '"') quoteflag = 2; else if (*ptr == '\'') quoteflag = 1; } else { if (quoteflag == 3 && strstr(ptr,"\"\"\"") == ptr) { quoteflag = 0; *ptr2++ = *ptr++; *ptr2++ = *ptr++; } else if (quoteflag == 2 && *ptr == '"') quoteflag = 0; else if (quoteflag == 1 && *ptr == '\'') quoteflag = 0; } // copy current character into str2 *ptr2++ = *ptr++; *ptr2 = '\0'; } // set length of input str to length of work str2 // copy work string back to input str if (max2 > max) reallocate(str,max,max2); strcpy(str,str2); } /* ---------------------------------------------------------------------- expand arg to earg, for arguments with syntax c_ID[*] or f_ID[*] fields to consider in input arg range from iarg to narg return new expanded # of values, and copy them w/out "*" into earg if any expansion occurs, earg is new allocation, must be freed by caller if no expansion occurs, earg just points to arg, caller need not free ------------------------------------------------------------------------- */ int Input::expand_args(int narg, char **arg, int mode, char **&earg) { int n,iarg,index,nlo,nhi,nmax,expandflag,icompute,ifix; char *ptr1,*ptr2,*str; ptr1 = NULL; for (iarg = 0; iarg < narg; iarg++) { ptr1 = strchr(arg[iarg],'*'); if (ptr1) break; } if (!ptr1) { earg = arg; return narg; } // maxarg should always end up equal to newarg, so caller can free earg int maxarg = narg-iarg; earg = (char **) memory->smalloc(maxarg*sizeof(char *),"input:earg"); int newarg = 0; for (iarg = 0; iarg < narg; iarg++) { expandflag = 0; if (strncmp(arg[iarg],"c_",2) == 0 || strncmp(arg[iarg],"f_",2) == 0) { ptr1 = strchr(&arg[iarg][2],'['); if (ptr1) { ptr2 = strchr(ptr1,']'); if (ptr2) { *ptr2 = '\0'; if (strchr(ptr1,'*')) { if (arg[iarg][0] == 'c') { *ptr1 = '\0'; icompute = modify->find_compute(&arg[iarg][2]); *ptr1 = '['; // check for global vector/array, peratom array, local array if (icompute >= 0) { if (mode == 0 && modify->compute[icompute]->vector_flag) { nmax = modify->compute[icompute]->size_vector; expandflag = 1; } else if (mode == 1 && modify->compute[icompute]->array_flag) { nmax = modify->compute[icompute]->size_array_cols; expandflag = 1; } else if (modify->compute[icompute]->peratom_flag && modify->compute[icompute]->size_peratom_cols) { nmax = modify->compute[icompute]->size_peratom_cols; expandflag = 1; } else if (modify->compute[icompute]->local_flag && modify->compute[icompute]->size_local_cols) { nmax = modify->compute[icompute]->size_local_cols; expandflag = 1; } } } else if (arg[iarg][0] == 'f') { *ptr1 = '\0'; ifix = modify->find_fix(&arg[iarg][2]); *ptr1 = '['; // check for global vector/array, peratom array, local array if (ifix >= 0) { if (mode == 0 && modify->fix[ifix]->vector_flag) { nmax = modify->fix[ifix]->size_vector; expandflag = 1; } else if (mode == 1 && modify->fix[ifix]->array_flag) { nmax = modify->fix[ifix]->size_array_cols; expandflag = 1; } else if (modify->fix[ifix]->peratom_flag && modify->fix[ifix]->size_peratom_cols) { nmax = modify->fix[ifix]->size_peratom_cols; expandflag = 1; } else if (modify->fix[ifix]->local_flag && modify->fix[ifix]->size_local_cols) { nmax = modify->fix[ifix]->size_local_cols; expandflag = 1; } } } } *ptr2 = ']'; } } } if (expandflag) { *ptr2 = '\0'; - force->bounds(ptr1+1,nmax,nlo,nhi); + force->bounds(FLERR,ptr1+1,nmax,nlo,nhi); *ptr2 = ']'; if (newarg+nhi-nlo+1 > maxarg) { maxarg += nhi-nlo+1; earg = (char **) memory->srealloc(earg,maxarg*sizeof(char *),"input:earg"); } for (index = nlo; index <= nhi; index++) { n = strlen(arg[iarg]) + 16; // 16 = space for large inserted integer str = earg[newarg] = new char[n]; strncpy(str,arg[iarg],ptr1+1-arg[iarg]); sprintf(&str[ptr1+1-arg[iarg]],"%d",index); strcat(str,ptr2); newarg++; } } else { if (newarg == maxarg) { maxarg++; earg = (char **) memory->srealloc(earg,maxarg*sizeof(char *),"input:earg"); } n = strlen(arg[iarg]) + 1; earg[newarg] = new char[n]; strcpy(earg[newarg],arg[iarg]); newarg++; } } //printf("NEWARG %d\n",newarg); //for (int i = 0; i < newarg; i++) // printf(" arg %d: %s\n",i,earg[i]); return newarg; } /* ---------------------------------------------------------------------- return number of triple quotes in line ------------------------------------------------------------------------- */ int Input::numtriple(char *line) { int count = 0; char *ptr = line; while ((ptr = strstr(ptr,"\"\"\""))) { ptr += 3; count++; } return count; } /* ---------------------------------------------------------------------- rellocate a string if n > 0: set max >= n in increments of DELTALINE if n = 0: just increment max by DELTALINE ------------------------------------------------------------------------- */ void Input::reallocate(char *&str, int &max, int n) { if (n) { while (n > max) max += DELTALINE; } else max += DELTALINE; str = (char *) memory->srealloc(str,max*sizeof(char),"input:str"); } /* ---------------------------------------------------------------------- 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,"python")) python(); else if (!strcmp(command,"quit")) quit(); 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,"bond_write")) bond_write(); else if (!strcmp(command,"boundary")) boundary(); else if (!strcmp(command,"box")) box(); else if (!strcmp(command,"comm_modify")) comm_modify(); else if (!strcmp(command,"comm_style")) comm_style(); 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,"molecule")) molecule(); 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,"timer")) timer_command(); 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; // invoke commands added via style_command.h if (command_map->find(command) != command_map->end()) { CommandCreator command_creator = (*command_map)[command]; command_creator(lmp,narg,arg); return 0; } // unrecognized command return -1; } /* ---------------------------------------------------------------------- one instance per command in style_command.h ------------------------------------------------------------------------- */ template void Input::command_creator(LAMMPS *lmp, int narg, char **arg) { T cmd(lmp); cmd.command(narg,arg); } /* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */ 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 int n = strlen(arg[0]) + 1; if (n > maxline) reallocate(line,maxline,n); strcpy(line,arg[0]); substitute(line,work,maxline,maxwork,0); // evaluate Boolean expression for "if" double btest = variable->evaluate_boolean(line); // 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++; } ifthenelse_flag = 1; for (int i = 0; i < ncommands; i++) one(commands[i]); ifthenelse_flag = 0; for (int i = 0; i < ncommands; i++) delete [] commands[i]; delete [] commands; return; } // done if no "elif" or "else" if (iarg == narg) 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 (iarg != narg) { if (iarg+2 > narg) error->all(FLERR,"Illegal if command"); if (strcmp(arg[iarg],"elif") == 0) { n = strlen(arg[iarg+1]) + 1; if (n > maxline) reallocate(line,maxline,n); strcpy(line,arg[iarg+1]); substitute(line,work,maxline,maxwork,0); btest = variable->evaluate_boolean(line); 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 ifthenelse_flag = 1; for (int i = 0; i < ncommands; i++) one(commands[i]); ifthenelse_flag = 0; // clean up for (int i = 0; i < ncommands; i++) delete [] commands[i]; delete [] commands; return; } } /* ---------------------------------------------------------------------- */ void Input::include() { if (narg != 1) error->all(FLERR,"Illegal include command"); // do not allow include inside an if command // NOTE: this check will fail if a 2nd if command was inside the if command // and came before the include if (ifthenelse_flag) error->all(FLERR,"Cannot use include command within an if 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 && 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 > 2) error->all(FLERR,"Illegal log command"); int appendflag = 0; if (narg == 2) { if (strcmp(arg[1],"append") == 0) appendflag = 1; else error->all(FLERR,"Illegal log command"); } if (me == 0) { if (logfile) fclose(logfile); if (strcmp(arg[0],"none") == 0) logfile = NULL; else { if (appendflag) logfile = fopen(arg[0],"a"); 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); + force->bounds(FLERR,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); 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"); // copy 1st arg back into line (copy is being used) // check maxline since arg[0] could have been exanded by variables // substitute for $ variables (no printing) and print arg int n = strlen(arg[0]) + 1; if (n > maxline) reallocate(line,maxline,n); strcpy(line,arg[0]); substitute(line,work,maxline,maxwork,0); // parse optional args FILE *fp = NULL; int screenflag = 1; int iarg = 1; while (iarg < narg) { if (strcmp(arg[iarg],"file") == 0 || strcmp(arg[iarg],"append") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal print command"); if (me == 0) { if (fp != NULL) fclose(fp); if (strcmp(arg[iarg],"file") == 0) fp = fopen(arg[iarg+1],"w"); else fp = fopen(arg[iarg+1],"a"); if (fp == NULL) { char str[128]; sprintf(str,"Cannot open print file %s",arg[iarg+1]); error->one(FLERR,str); } } iarg += 2; } else if (strcmp(arg[iarg],"screen") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal print command"); if (strcmp(arg[iarg+1],"yes") == 0) screenflag = 1; else if (strcmp(arg[iarg+1],"no") == 0) screenflag = 0; else error->all(FLERR,"Illegal print command"); iarg += 2; } else error->all(FLERR,"Illegal print command"); } if (me == 0) { if (screenflag && screen) fprintf(screen,"%s\n",line); if (screenflag && logfile) fprintf(logfile,"%s\n",line); if (fp) { fprintf(fp,"%s\n",line); fclose(fp); } } } /* ---------------------------------------------------------------------- */ void Input::python() { variable->python_command(narg,arg); } /* ---------------------------------------------------------------------- */ void Input::quit() { if (narg == 0) error->done(0); // 1 would be fully backwards compatible if (narg == 1) error->done(force->inumeric(FLERR,arg[0])); error->all(FLERR,"Illegal quit command"); } /* ---------------------------------------------------------------------- */ char *shell_failed_message(const char* cmd, int errnum) { const char *errmsg = strerror(errnum); int len = strlen(cmd)+strlen(errmsg)+64; char *msg = new char[len]; sprintf(msg,"Shell command '%s' failed with error '%s'", cmd, errmsg); return msg; } void Input::shell() { int rv,err; if (narg < 1) error->all(FLERR,"Illegal shell command"); if (strcmp(arg[0],"cd") == 0) { if (narg != 2) error->all(FLERR,"Illegal shell cd command"); rv = (chdir(arg[1]) < 0) ? errno : 0; MPI_Reduce(&rv,&err,1,MPI_INT,MPI_MAX,0,world); if (me == 0 && err != 0) { char *message = shell_failed_message("cd",err); error->warning(FLERR,message); delete [] message; } } else if (strcmp(arg[0],"mkdir") == 0) { if (narg < 2) error->all(FLERR,"Illegal shell mkdir command"); if (me == 0) for (int i = 1; i < narg; i++) { #if defined(_WIN32) rv = _mkdir(arg[i]); #else rv = mkdir(arg[i], S_IRWXU | S_IRGRP | S_IXGRP); #endif if (rv < 0) { char *message = shell_failed_message("mkdir",errno); error->warning(FLERR,message); delete [] message; } } } else if (strcmp(arg[0],"mv") == 0) { if (narg != 3) error->all(FLERR,"Illegal shell mv command"); rv = (rename(arg[1],arg[2]) < 0) ? errno : 0; MPI_Reduce(&rv,&err,1,MPI_INT,MPI_MAX,0,world); if (me == 0 && err != 0) { char *message = shell_failed_message("mv",err); error->warning(FLERR,message); delete [] message; } } else if (strcmp(arg[0],"rm") == 0) { if (narg < 2) error->all(FLERR,"Illegal shell rm command"); if (me == 0) for (int i = 1; i < narg; i++) { if (unlink(arg[i]) < 0) { char *message = shell_failed_message("rm",errno); error->warning(FLERR,message); delete [] message; } } } else if (strcmp(arg[0],"rmdir") == 0) { if (narg < 2) error->all(FLERR,"Illegal shell rmdir command"); if (me == 0) for (int i = 1; i < narg; i++) { if (rmdir(arg[i]) < 0) { char *message = shell_failed_message("rmdir",errno); error->warning(FLERR,message); delete [] message; } } } else if (strcmp(arg[0],"putenv") == 0) { if (narg < 2) error->all(FLERR,"Illegal shell putenv command"); for (int i = 1; i < narg; i++) { char *ptr = strdup(arg[i]); rv = 0; #ifdef _WIN32 if (ptr != NULL) rv = _putenv(ptr); #else if (ptr != NULL) rv = putenv(ptr); #endif rv = (rv < 0) ? errno : 0; MPI_Reduce(&rv,&err,1,MPI_INT,MPI_MAX,0,world); if (me == 0 && err != 0) { char *message = shell_failed_message("putenv",err); error->warning(FLERR,message); delete [] message; } } // use work string to concat args back into one string separated by spaces // invoke string in shell via system() } else { int n = 0; for (int i = 0; i < narg; i++) n += strlen(arg[i]) + 1; if (n > maxwork) reallocate(work,maxwork,n); strcpy(work,arg[0]); for (int i = 1; i < narg; i++) { strcat(work," "); strcat(work,arg[i]); } if (me == 0) if (system(work) != 0) error->warning(FLERR,"Shell command returned with non-zero status"); } } /* ---------------------------------------------------------------------- */ 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],1); 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],1); } /* ---------------------------------------------------------------------- */ 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],1); if (force->bond) force->bond->settings(narg-1,&arg[1]); } /* ---------------------------------------------------------------------- */ void Input::bond_write() { if (atom->avec->bonds_allow == 0) error->all(FLERR,"Bond_write command when no bonds allowed"); if (force->bond == NULL) error->all(FLERR,"Bond_write command before bond_style is defined"); else force->bond->write_file(narg,arg); } /* ---------------------------------------------------------------------- */ void Input::boundary() { if (domain->box_exist) error->all(FLERR,"Boundary command after simulation box is defined"); domain->set_boundary(narg,arg,0); } /* ---------------------------------------------------------------------- */ void Input::box() { if (domain->box_exist) error->all(FLERR,"Box command after simulation box is defined"); domain->set_box(narg,arg); } /* ---------------------------------------------------------------------- */ void Input::comm_modify() { comm->modify_params(narg,arg); } /* ---------------------------------------------------------------------- */ void Input::comm_style() { if (narg < 1) error->all(FLERR,"Illegal comm_style command"); if (strcmp(arg[0],"brick") == 0) { if (comm->style == 0) return; Comm *oldcomm = comm; comm = new CommBrick(lmp,oldcomm); delete oldcomm; } else if (strcmp(arg[0],"tiled") == 0) { if (comm->style == 1) return; Comm *oldcomm = comm; comm = new CommTiled(lmp,oldcomm); delete oldcomm; } else error->all(FLERR,"Illegal comm_style command"); } /* ---------------------------------------------------------------------- */ void Input::compute() { modify->add_compute(narg,arg,1); } /* ---------------------------------------------------------------------- */ void Input::compute_modify() { modify->modify_compute(narg,arg); } /* ---------------------------------------------------------------------- */ void Input::dielectric() { if (narg != 1) error->all(FLERR,"Illegal dielectric command"); force->dielectric = force->numeric(FLERR,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],1); 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 = force->inumeric(FLERR,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,1); } /* ---------------------------------------------------------------------- */ 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],1); 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,1); } /* ---------------------------------------------------------------------- */ 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::molecule() { atom->add_molecule(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=1,newton_bond=1; 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 (domain->box_exist && (newton_bond != force->newton_bond)) error->all(FLERR,"Newton bond change after simulation box is defined"); force->newton_bond = newton_bond; 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"); // same checks for packages existing as in LAMMPS::post_create() // since can be invoked here by package command in input script if (strcmp(arg[0],"gpu") == 0) { if (!modify->check_package("GPU")) error->all(FLERR,"Package gpu command without GPU package installed"); char **fixarg = new char*[2+narg]; 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->add_fix(2+narg,fixarg); delete [] fixarg; } else if (strcmp(arg[0],"kokkos") == 0) { if (lmp->kokkos == NULL || lmp->kokkos->kokkos_exists == 0) error->all(FLERR, "Package kokkos command without KOKKOS package enabled"); lmp->kokkos->accelerator(narg-1,&arg[1]); } else if (strcmp(arg[0],"omp") == 0) { if (!modify->check_package("OMP")) error->all(FLERR, "Package omp command without USER-OMP package installed"); char **fixarg = new char*[2+narg]; 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->add_fix(2+narg,fixarg); delete [] fixarg; } else if (strcmp(arg[0],"intel") == 0) { if (!modify->check_package("INTEL")) error->all(FLERR, "Package intel command without USER-INTEL package installed"); char **fixarg = new char*[2+narg]; fixarg[0] = (char *) "package_intel"; fixarg[1] = (char *) "all"; fixarg[2] = (char *) "INTEL"; for (int i = 1; i < narg; i++) fixarg[i+2] = arg[i]; modify->add_fix(2+narg,fixarg); 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) { int match = 0; if (strcmp(arg[0],force->pair_style) == 0) match = 1; if (!match && lmp->suffix_enable) { char estyle[256]; if (lmp->suffix) { sprintf(estyle,"%s/%s",arg[0],lmp->suffix); if (strcmp(estyle,force->pair_style) == 0) match = 1; } if (lmp->suffix2) { sprintf(estyle,"%s/%s",arg[0],lmp->suffix2); if (strcmp(estyle,force->pair_style) == 0) match = 1; } } if (match) { force->pair->settings(narg-1,&arg[1]); return; } } force->create_pair(arg[0],1); 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,1); } /* ---------------------------------------------------------------------- */ 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 == 1) { 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 { lmp->suffix_enable = 1; delete [] lmp->suffix; delete [] lmp->suffix2; if (strcmp(arg[0],"hybrid") == 0) { if (narg != 3) error->all(FLERR,"Illegal suffix command"); int n = strlen(arg[1]) + 1; lmp->suffix = new char[n]; strcpy(lmp->suffix,arg[1]); n = strlen(arg[2]) + 1; lmp->suffix2 = new char[n]; strcpy(lmp->suffix2,arg[2]); } else { if (narg != 1) error->all(FLERR,"Illegal suffix command"); int n = strlen(arg[0]) + 1; lmp->suffix = new char[n]; strcpy(lmp->suffix,arg[0]); } } } /* ---------------------------------------------------------------------- */ void Input::thermo() { output->set_thermo(narg,arg); } /* ---------------------------------------------------------------------- */ void Input::thermo_modify() { output->thermo->modify_params(narg,arg); } /* ---------------------------------------------------------------------- */ void Input::thermo_style() { output->create_thermo(narg,arg); } /* ---------------------------------------------------------------------- */ void Input::timer_command() { timer->modify_params(narg,arg); } /* ---------------------------------------------------------------------- */ void Input::timestep() { if (narg != 1) error->all(FLERR,"Illegal timestep command"); update->dt = force->numeric(FLERR,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/pair_beck.cpp b/src/pair_beck.cpp index 0e05afb43..e3e8b0c5c 100644 --- a/src/pair_beck.cpp +++ b/src/pair_beck.cpp @@ -1,363 +1,363 @@ /* ---------------------------------------------------------------------- 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: Jonathan Zimmerman (Sandia) ------------------------------------------------------------------------- */ #include #include #include #include "pair_beck.h" #include "atom.h" #include "comm.h" #include "force.h" #include "neigh_list.h" #include "memory.h" #include "error.h" #include "math_special.h" using namespace LAMMPS_NS; using namespace MathSpecial; /* ---------------------------------------------------------------------- */ PairBeck::PairBeck(LAMMPS *lmp) : Pair(lmp) {} /* ---------------------------------------------------------------------- */ PairBeck::~PairBeck() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut); memory->destroy(AA); memory->destroy(BB); memory->destroy(aa); memory->destroy(alpha); memory->destroy(beta); } } /* ---------------------------------------------------------------------- */ void PairBeck::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,r5,force_beck,factor_lj; double r,rinv; double aaij,alphaij,betaij; double term1,term1inv,term2,term3,term4,term5,term6; 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); r5 = rsq*rsq*r; aaij = aa[itype][jtype]; alphaij = alpha[itype][jtype]; betaij = beta[itype][jtype]; term1 = aaij*aaij + rsq; term2 = powint(term1,-5); term3 = 21.672 + 30.0*aaij*aaij + 6.0*rsq; term4 = alphaij + r5*betaij; term5 = alphaij + 6.0*r5*betaij; rinv = 1.0/r; force_beck = AA[itype][jtype]*exp(-1.0*r*term4)*term5; force_beck -= BB[itype][jtype]*r*term2*term3; fpair = factor_lj*force_beck*rinv; 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) { term6 = powint(term1,-3); term1inv = 1.0/term1; evdwl = AA[itype][jtype]*exp(-1.0*r*term4); evdwl -= BB[itype][jtype]*term6*(1.0+(2.709+3.0*aaij*aaij)*term1inv); } 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 PairBeck::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(AA,n+1,n+1,"pair:AA"); memory->create(BB,n+1,n+1,"pair:BB"); memory->create(aa,n+1,n+1,"pair:aa"); memory->create(alpha,n+1,n+1,"pair:alpha"); memory->create(beta,n+1,n+1,"pair:beta"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairBeck::settings(int narg, char **arg) { if (narg != 1) error->all(FLERR,"Illegal pair_style command"); cut_global = force->numeric(FLERR,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 PairBeck::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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double AA_one = force->numeric(FLERR,arg[2]); double BB_one = force->numeric(FLERR,arg[3]); double aa_one = force->numeric(FLERR,arg[4]); double alpha_one = force->numeric(FLERR,arg[5]); double beta_one = force->numeric(FLERR,arg[6]); double cut_one = cut_global; if (narg == 8) cut_one = force->numeric(FLERR,arg[7]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { AA[i][j] = AA_one; BB[i][j] = BB_one; aa[i][j] = aa_one; alpha[i][j] = alpha_one; beta[i][j] = beta_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 PairBeck::init_one(int i, int j) { if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set"); AA[j][i] = AA[i][j]; BB[j][i] = BB[i][j]; aa[j][i] = aa[i][j]; alpha[j][i] = alpha[i][j]; beta[j][i] = beta[i][j]; return cut[i][j]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairBeck::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(&AA[i][j],sizeof(double),1,fp); fwrite(&BB[i][j],sizeof(double),1,fp); fwrite(&aa[i][j],sizeof(double),1,fp); fwrite(&alpha[i][j],sizeof(double),1,fp); fwrite(&beta[i][j],sizeof(double),1,fp); fwrite(&cut[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairBeck::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(&AA[i][j],sizeof(double),1,fp); fread(&BB[i][j],sizeof(double),1,fp); fread(&aa[i][j],sizeof(double),1,fp); fread(&alpha[i][j],sizeof(double),1,fp); fread(&beta[i][j],sizeof(double),1,fp); fread(&cut[i][j],sizeof(double),1,fp); } MPI_Bcast(&AA[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&BB[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&aa[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&alpha[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&beta[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairBeck::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 PairBeck::read_restart_settings(FILE *fp) { int me = comm->me; if (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 PairBeck::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double phi_beck,r,rinv; double r5,force_beck; double aaij,alphaij,betaij; double term1,term1inv,term2,term3,term4,term5,term6; r = sqrt(rsq); r5 = rsq*rsq*r; aaij = aa[itype][jtype]; alphaij = alpha[itype][jtype]; betaij = beta[itype][jtype]; term1 = aaij*aaij + rsq; term2 = powint(term1,-5); term3 = 21.672 + 30.0*aaij*aaij + 6.0*rsq; term4 = alphaij + r5*betaij; term5 = alphaij + 6.0*r5*betaij; rinv = 1.0/r; force_beck = AA[itype][jtype]*exp(-1.0*r*term4)*term5; force_beck -= BB[itype][jtype]*r*term2*term3; fforce = factor_lj*force_beck*rinv; term6 = powint(term1,-3); term1inv = 1.0/term1; phi_beck = AA[itype][jtype]*exp(-1.0*r*term4); phi_beck -= BB[itype][jtype]*term6*(1.0+(2.709+3.0*aaij*aaij)*term1inv); return factor_lj*phi_beck; } diff --git a/src/pair_born.cpp b/src/pair_born.cpp index d925af103..5fc26e252 100644 --- a/src/pair_born.cpp +++ b/src/pair_born.cpp @@ -1,438 +1,438 @@ /* ---------------------------------------------------------------------- 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 #include #include #include #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) { writedata = 1; } /* ---------------------------------------------------------------------- */ 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 = force->numeric(FLERR,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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double a_one = force->numeric(FLERR,arg[2]); double rho_one = force->numeric(FLERR,arg[3]); double sigma_one = force->numeric(FLERR,arg[4]); if (rho_one <= 0) error->all(FLERR,"Incorrect args for pair coefficients"); double c_one = force->numeric(FLERR,arg[5]); double d_one = force->numeric(FLERR,arg[6]); double cut_one = cut_global; if (narg == 8) cut_one = force->numeric(FLERR,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); fwrite(&tail_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); fread(&tail_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); MPI_Bcast(&tail_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void PairBorn::write_data(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) fprintf(fp,"%d %g %g %g %g %g\n",i, a[i][i],rho[i][i],sigma[i][i],c[i][i],d[i][i]); } /* ---------------------------------------------------------------------- proc 0 writes all pairs to data file ------------------------------------------------------------------------- */ void PairBorn::write_data_all(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) fprintf(fp,"%d %d %g %g %g %g %g %g\n",i,j, a[i][j],rho[i][j],sigma[i][j],c[i][j],d[i][j],cut[i][j]); } /* ---------------------------------------------------------------------- */ 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(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_coul_wolf.cpp b/src/pair_born_coul_wolf.cpp index 48066fc43..31c0cc715 100644 --- a/src/pair_born_coul_wolf.cpp +++ b/src/pair_born_coul_wolf.cpp @@ -1,492 +1,492 @@ /* ---------------------------------------------------------------------- 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: Yongfeng Zhang (INL), yongfeng.zhang@inl.gov ------------------------------------------------------------------------- */ #include #include #include #include #include "pair_born_coul_wolf.h" #include "atom.h" #include "comm.h" #include "force.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; /* ---------------------------------------------------------------------- */ PairBornCoulWolf::PairBornCoulWolf(LAMMPS *lmp) : Pair(lmp) { writedata = 1; single_enable = 0; } /* ---------------------------------------------------------------------- */ PairBornCoulWolf::~PairBornCoulWolf() { 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 PairBornCoulWolf::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 prefactor; double r,rexp; int *ilist,*jlist,*numneigh,**firstneigh; double erfcc,erfcd,v_sh,dvdrr,e_self,e_shift,f_shift,qisq; 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; // self and shifted coulombic energy e_self = v_sh = 0.0; e_shift = erfc(alf*cut_coul)/cut_coul; f_shift = -(e_shift+ 2.0*alf/MY_PIS * exp(-alf*alf*cut_coul*cut_coul)) / cut_coul; 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]; qisq = qtmp*qtmp; e_self = -(e_shift/2.0 + alf/MY_PIS) * qisq*qqrd2e; if (eflag) ev_tally(i,i,nlocal,0,0.0,e_self,0.0,0.0,0.0,0.0); 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); prefactor = qqrd2e*qtmp*q[j]/r; erfcc = erfc(alf*r); erfcd = exp(-alf*alf*r*r); v_sh = (erfcc - e_shift*r) * prefactor; dvdrr = (erfcc/rsq + 2.0*alf/MY_PIS * erfcd/r) + f_shift; forcecoul = dvdrr*rsq*prefactor; 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; 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 = v_sh; 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 PairBornCoulWolf::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 PairBornCoulWolf::settings(int narg, char **arg) { if (narg < 2 || narg > 3) error->all(FLERR,"Illegal pair_style command"); alf = force->numeric(FLERR,arg[0]); cut_lj_global = force->numeric(FLERR,arg[1]); if (narg == 2) cut_coul = cut_lj_global; else cut_coul = force->numeric(FLERR,arg[2]); 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 PairBornCoulWolf::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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double a_one = force->numeric(FLERR,arg[2]); double rho_one = force->numeric(FLERR,arg[3]); double sigma_one = force->numeric(FLERR,arg[4]); if (rho_one <= 0) error->all(FLERR,"Incorrect args for pair coefficients"); double c_one = force->numeric(FLERR,arg[5]); double d_one = force->numeric(FLERR,arg[6]); double cut_lj_one = cut_lj_global; if (narg == 8) cut_lj_one = force->numeric(FLERR,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 specific to this pair style ------------------------------------------------------------------------- */ void PairBornCoulWolf::init_style() { if (!atom->q_flag) error->all(FLERR,"Pair style born/coul/wolf requires atom attribute q"); neighbor->request(this,instance_me); cut_coulsq = cut_coul * cut_coul; } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairBornCoulWolf::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((sigma[i][j]-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]; return cut; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairBornCoulWolf::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 PairBornCoulWolf::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 PairBornCoulWolf::write_restart_settings(FILE *fp) { fwrite(&alf,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 PairBornCoulWolf::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&alf,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(&alf,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); } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void PairBornCoulWolf::write_data(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) fprintf(fp,"%d %g %g %g %g %g\n",i, a[i][i],rho[i][i],sigma[i][i],c[i][i],d[i][i]); } /* ---------------------------------------------------------------------- proc 0 writes all pairs to data file ------------------------------------------------------------------------- */ void PairBornCoulWolf::write_data_all(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) fprintf(fp,"%d %d %g %g %g %g %g %g\n",i,j, a[i][j],rho[i][j],sigma[i][j],c[i][j],d[i][j],cut_lj[i][j]); } /* ---------------------------------------------------------------------- only the pair part is calculated here ------------------------------------------------------------------------- */ double PairBornCoulWolf::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r2inv,r6inv,r,prefactor,rexp; double forcecoul,forceborn,phicoul,phiborn; double e_shift,f_shift,dvdrr,erfcc,erfcd; r2inv = 1.0/rsq; e_shift = erfc(alf*cut_coul) / cut_coul; f_shift = -(e_shift+2*alf/MY_PIS * exp(-alf*alf*cut_coul*cut_coul)) / cut_coul; if (rsq < cut_coulsq) { r = sqrt(rsq); prefactor = force->qqrd2e * atom->q[i]*atom->q[j]/r; erfcc = erfc(alf*r); erfcd = exp(-alf*alf*r*r); dvdrr = (erfcc/rsq + 2.0*alf/MY_PIS * erfcd/r) + f_shift; forcecoul = dvdrr*rsq*prefactor; 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]); 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 * (erfcc-e_shift*r); 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; } diff --git a/src/pair_buck.cpp b/src/pair_buck.cpp index baaea7ccd..78a5321cf 100644 --- a/src/pair_buck.cpp +++ b/src/pair_buck.cpp @@ -1,408 +1,408 @@ /* ---------------------------------------------------------------------- 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 #include #include #include #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) { writedata = 1; } /* ---------------------------------------------------------------------- */ PairBuck::~PairBuck() { if (copymode) return; 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(FLERR,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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double a_one = force->numeric(FLERR,arg[2]); double rho_one = force->numeric(FLERR,arg[3]); if (rho_one <= 0) error->all(FLERR,"Incorrect args for pair coefficients"); double c_one = force->numeric(FLERR,arg[4]); double cut_one = cut_global; if (narg == 6) cut_one = force->numeric(FLERR,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); fwrite(&tail_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); fread(&tail_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); MPI_Bcast(&tail_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void PairBuck::write_data(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) fprintf(fp,"%d %g %g %g\n",i,a[i][i],rho[i][i],c[i][i]); } /* ---------------------------------------------------------------------- proc 0 writes all pairs to data file ------------------------------------------------------------------------- */ void PairBuck::write_data_all(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) fprintf(fp,"%d %d %g %g %g %g\n",i,j, a[i][j],rho[i][j],c[i][j],cut[i][j]); } /* ---------------------------------------------------------------------- */ 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(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_coul_cut.cpp b/src/pair_buck_coul_cut.cpp index 06aeea308..7c948f58a 100644 --- a/src/pair_buck_coul_cut.cpp +++ b/src/pair_buck_coul_cut.cpp @@ -1,472 +1,472 @@ /* ---------------------------------------------------------------------- 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: Eduardo Bringa (LLNL) ------------------------------------------------------------------------- */ #include #include #include #include "pair_buck_coul_cut.h" #include "atom.h" #include "comm.h" #include "force.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; /* ---------------------------------------------------------------------- */ PairBuckCoulCut::PairBuckCoulCut(LAMMPS *lmp) : Pair(lmp) { writedata = 1; } /* ---------------------------------------------------------------------- */ PairBuckCoulCut::~PairBuckCoulCut() { if (!copymode) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut_lj); memory->destroy(cut_ljsq); memory->destroy(cut_coul); memory->destroy(cut_coulsq); memory->destroy(a); memory->destroy(rho); memory->destroy(c); memory->destroy(rhoinv); memory->destroy(buck1); memory->destroy(buck2); memory->destroy(offset); } } /* ---------------------------------------------------------------------- */ void PairBuckCoulCut::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 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[itype][jtype]) forcecoul = qqrd2e * qtmp*q[j]/r; 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 = (factor_coul*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[itype][jtype]) ecoul = factor_coul * qqrd2e * qtmp*q[j]/r; 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 PairBuckCoulCut::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(cut_coul,n+1,n+1,"pair:cut_coul"); memory->create(cut_coulsq,n+1,n+1,"pair:cut_coulsq"); 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 PairBuckCoulCut::settings(int narg, char **arg) { if (narg < 1 || narg > 2) error->all(FLERR,"Illegal pair_style command"); cut_lj_global = force->numeric(FLERR,arg[0]); if (narg == 1) cut_coul_global = cut_lj_global; else cut_coul_global = force->numeric(FLERR,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; cut_coul[i][j] = cut_coul_global; } } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairBuckCoulCut::coeff(int narg, char **arg) { if (narg < 5 || narg > 7) 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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double a_one = force->numeric(FLERR,arg[2]); double rho_one = force->numeric(FLERR,arg[3]); if (rho_one <= 0) error->all(FLERR,"Incorrect args for pair coefficients"); double c_one = force->numeric(FLERR,arg[4]); double cut_lj_one = cut_lj_global; double cut_coul_one = cut_coul_global; if (narg >= 6) cut_coul_one = cut_lj_one = force->numeric(FLERR,arg[5]); if (narg == 7) cut_coul_one = force->numeric(FLERR,arg[6]); 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; cut_coul[i][j] = cut_coul_one; setflag[i][j] = 1; count++; } } if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairBuckCoulCut::init_style() { if (!atom->q_flag) error->all(FLERR,"Pair style buck/coul/cut requires atom attribute q"); neighbor->request(this,instance_me); } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairBuckCoulCut::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[i][j]); cut_ljsq[i][j] = cut_lj[i][j] * cut_lj[i][j]; cut_coulsq[i][j] = cut_coul[i][j] * cut_coul[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]; cut_coulsq[j][i] = cut_coulsq[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; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairBuckCoulCut::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); fwrite(&cut_coul[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairBuckCoulCut::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); fread(&cut_coul[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); MPI_Bcast(&cut_coul[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairBuckCoulCut::write_restart_settings(FILE *fp) { fwrite(&cut_lj_global,sizeof(double),1,fp); fwrite(&cut_coul_global,sizeof(double),1,fp); fwrite(&offset_flag,sizeof(int),1,fp); fwrite(&mix_flag,sizeof(int),1,fp); fwrite(&tail_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairBuckCoulCut::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&cut_lj_global,sizeof(double),1,fp); fread(&cut_coul_global,sizeof(double),1,fp); fread(&offset_flag,sizeof(int),1,fp); fread(&mix_flag,sizeof(int),1,fp); fread(&tail_flag,sizeof(int),1,fp); } MPI_Bcast(&cut_lj_global,1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_coul_global,1,MPI_DOUBLE,0,world); MPI_Bcast(&offset_flag,1,MPI_INT,0,world); MPI_Bcast(&mix_flag,1,MPI_INT,0,world); MPI_Bcast(&tail_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void PairBuckCoulCut::write_data(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) fprintf(fp,"%d %g %g %g\n",i,a[i][i],rho[i][i],c[i][i]); } /* ---------------------------------------------------------------------- proc 0 writes all pairs to data file ------------------------------------------------------------------------- */ void PairBuckCoulCut::write_data_all(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) fprintf(fp,"%d %d %g %g %g %g %g\n",i,j, a[i][j],rho[i][j],c[i][j],cut_lj[i][j],cut_coul[i][j]); } /* ---------------------------------------------------------------------- */ double PairBuckCoulCut::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r2inv,r6inv,r,rexp,forcecoul,forcebuck,phicoul,phibuck; r2inv = 1.0/rsq; if (rsq < cut_coulsq[itype][jtype]) forcecoul = force->qqrd2e * atom->q[i]*atom->q[j]*sqrt(r2inv); 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 = (factor_coul*forcecoul + factor_lj*forcebuck) * r2inv; double eng = 0.0; if (rsq < cut_coulsq[itype][jtype]) { phicoul = force->qqrd2e * atom->q[i]*atom->q[j]*sqrt(r2inv); eng += factor_coul*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; } diff --git a/src/pair_coul_cut.cpp b/src/pair_coul_cut.cpp index 4f21ba5ac..fec592bb1 100644 --- a/src/pair_coul_cut.cpp +++ b/src/pair_coul_cut.cpp @@ -1,309 +1,309 @@ /* ---------------------------------------------------------------------- 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 #include #include #include #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(FLERR,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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double cut_one = cut_global; if (narg == 3) cut_one = force->numeric(FLERR,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,instance_me); } /* ---------------------------------------------------------------------- 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(const char *str, int &dim) { dim = 2; if (strcmp(str,"scale") == 0) return (void *) scale; return NULL; } diff --git a/src/pair_coul_dsf.cpp b/src/pair_coul_dsf.cpp index a72b8d72d..3595f9cbe 100644 --- a/src/pair_coul_dsf.cpp +++ b/src/pair_coul_dsf.cpp @@ -1,332 +1,332 @@ /* ---------------------------------------------------------------------- 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: Trung Dac Nguyen (ORNL) References: Fennell and Gezelter, JCP 124, 234104 (2006) ------------------------------------------------------------------------- */ #include #include #include #include #include "pair_coul_dsf.h" #include "atom.h" #include "comm.h" #include "force.h" #include "neighbor.h" #include "neigh_list.h" #include "memory.h" #include "math_const.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 /* ---------------------------------------------------------------------- */ PairCoulDSF::PairCoulDSF(LAMMPS *lmp) : Pair(lmp) {} /* ---------------------------------------------------------------------- */ PairCoulDSF::~PairCoulDSF() { if (copymode) return; if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); } } /* ---------------------------------------------------------------------- */ void PairCoulDSF::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum; double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,ecoul,fpair; double r,rsq,r2inv,forcecoul,factor_coul; double prefactor,erfcc,erfcd,t; 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 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]; jlist = firstneigh[i]; jnum = numneigh[i]; if (eflag) { double e_self = -(e_shift/2.0 + alpha/MY_PIS) * qtmp*qtmp*qqrd2e; ev_tally(i,i,nlocal,0,0.0,e_self,0.0,0.0,0.0,0.0); } 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; if (rsq < cut_coulsq) { r2inv = 1.0/rsq; r = sqrt(rsq); prefactor = qqrd2e*qtmp*q[j]/r; erfcd = exp(-alpha*alpha*rsq); t = 1.0 / (1.0 + EWALD_P*alpha*r); erfcc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * erfcd; forcecoul = prefactor * (erfcc/r + 2.0*alpha/MY_PIS * erfcd + r*f_shift) * r; if (factor_coul < 1.0) 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) { ecoul = prefactor * (erfcc - r*e_shift - rsq*f_shift); if (factor_coul < 1.0) ecoul -= (1.0-factor_coul)*prefactor; } else ecoul = 0.0; 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 PairCoulDSF::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"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairCoulDSF::settings(int narg, char **arg) { if (narg != 2) error->all(FLERR,"Illegal pair_style command"); alpha = force->numeric(FLERR,arg[0]); cut_coul = force->numeric(FLERR,arg[1]); } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairCoulDSF::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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,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++) { setflag[i][j] = 1; count++; } } if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairCoulDSF::init_style() { if (!atom->q_flag) error->all(FLERR,"Pair style coul/dsf requires atom attribute q"); neighbor->request(this,instance_me); cut_coulsq = cut_coul * cut_coul; double erfcc = erfc(alpha*cut_coul); double erfcd = exp(-alpha*alpha*cut_coul*cut_coul); f_shift = -(erfcc/cut_coulsq + 2.0/MY_PIS*alpha*erfcd/cut_coul); e_shift = erfcc/cut_coul - f_shift*cut_coul; } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairCoulDSF::init_one(int i, int j) { return cut_coul; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairCoulDSF::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); } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairCoulDSF::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); } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairCoulDSF::write_restart_settings(FILE *fp) { fwrite(&alpha,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 PairCoulDSF::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&alpha,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(&alpha,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 PairCoulDSF::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r2inv,r,erfcc,erfcd,prefactor,t; double forcecoul,phicoul; r2inv = 1.0/rsq; double eng = 0.0; if (rsq < cut_coulsq) { r = sqrt(rsq); prefactor = factor_coul * force->qqrd2e * atom->q[i]*atom->q[j]/r; erfcd = exp(-alpha*alpha*rsq); t = 1.0 / (1.0 + EWALD_P*alpha*r); erfcc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * erfcd; forcecoul = prefactor * (erfcc/r + 2.0*alpha/MY_PIS*erfcd + r*f_shift) * r; phicoul = prefactor * (erfcc - r*e_shift - rsq*f_shift); eng += phicoul; } else forcecoul = 0.0; fforce = forcecoul * r2inv; return eng; } /* ---------------------------------------------------------------------- */ void *PairCoulDSF::extract(const char *str, int &dim) { if (strcmp(str,"cut_coul") == 0) { dim = 0; return (void *) &cut_coul; } return NULL; } diff --git a/src/pair_coul_wolf.cpp b/src/pair_coul_wolf.cpp index 320eed3e9..1a7f47726 100644 --- a/src/pair_coul_wolf.cpp +++ b/src/pair_coul_wolf.cpp @@ -1,323 +1,323 @@ /* ---------------------------------------------------------------------- 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: Yongfeng Zhang (INL), yongfeng.zhang@inl.gov ------------------------------------------------------------------------- */ #include #include #include #include #include "pair_coul_wolf.h" #include "atom.h" #include "comm.h" #include "force.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; /* ---------------------------------------------------------------------- */ PairCoulWolf::PairCoulWolf(LAMMPS *lmp) : Pair(lmp) { single_enable = 0; // NOTE: single() method below is not yet correct } /* ---------------------------------------------------------------------- */ PairCoulWolf::~PairCoulWolf() { if (copymode) return; if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); } } /* ---------------------------------------------------------------------- */ void PairCoulWolf::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum; double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,ecoul,fpair; double rsq,forcecoul,factor_coul; double prefactor; double r; int *ilist,*jlist,*numneigh,**firstneigh; double erfcc,erfcd,v_sh,dvdrr,e_self,e_shift,f_shift,qisq; 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 nlocal = atom->nlocal; double *special_coul = force->special_coul; int newton_pair = force->newton_pair; double qqrd2e = force->qqrd2e; // self and shifted coulombic energy e_self = v_sh = 0.0; e_shift = erfc(alf*cut_coul)/cut_coul; f_shift = -(e_shift+ 2.0*alf/MY_PIS * exp(-alf*alf*cut_coul*cut_coul)) / cut_coul; 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]; jlist = firstneigh[i]; jnum = numneigh[i]; qisq = qtmp*qtmp; e_self = -(e_shift/2.0 + alf/MY_PIS) * qisq*qqrd2e; if (evflag) ev_tally(i,i,nlocal,0,0.0,e_self,0.0,0.0,0.0,0.0); 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; if (rsq < cut_coulsq) { r = sqrt(rsq); prefactor = qqrd2e*qtmp*q[j]/r; erfcc = erfc(alf*r); erfcd = exp(-alf*alf*r*r); v_sh = (erfcc - e_shift*r) * prefactor; dvdrr = (erfcc/rsq + 2.0*alf/MY_PIS * erfcd/r) + f_shift; forcecoul = dvdrr*rsq*prefactor; if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor; fpair = forcecoul / rsq; 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 = v_sh; if (factor_coul < 1.0) ecoul -= (1.0-factor_coul)*prefactor; } else ecoul = 0.0; 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 PairCoulWolf::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"); } /* ---------------------------------------------------------------------- global settings unlike other pair styles, there are no individual pair settings that these override ------------------------------------------------------------------------- */ void PairCoulWolf::settings(int narg, char **arg) { if (narg != 2) error->all(FLERR,"Illegal pair_style command"); alf = force->numeric(FLERR,arg[0]); cut_coul = force->numeric(FLERR,arg[1]); } /* ---------------------------------------------------------------------- set cutoffs for one or more type pairs, optional ------------------------------------------------------------------------- */ void PairCoulWolf::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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,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++) { setflag[i][j] = 1; count++; } } if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairCoulWolf::init_style() { if (!atom->q_flag) error->all(FLERR,"Pair coul/wolf requires atom attribute q"); neighbor->request(this,instance_me); cut_coulsq = cut_coul*cut_coul; } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairCoulWolf::init_one(int i, int j) { return cut_coul; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairCoulWolf::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); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairCoulWolf::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); } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairCoulWolf::write_restart_settings(FILE *fp) { fwrite(&alf,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 PairCoulWolf::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&alf,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(&alf,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); } /* ---------------------------------------------------------------------- only the pair part is calculated here ------------------------------------------------------------------------- */ double PairCoulWolf::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r,prefactor; double forcecoul,phicoul; double e_shift,f_shift,dvdrr,erfcc,erfcd; e_shift = erfc(alf*cut_coul) / cut_coul; f_shift = -(e_shift+ 2.0*alf/MY_PIS * exp(-alf*alf*cut_coul*cut_coul)) / cut_coul; if (rsq < cut_coulsq) { r = sqrt(rsq); prefactor = force->qqrd2e * atom->q[i]*atom->q[j]/r; erfcc = erfc(alf*r); erfcd = exp(-alf*alf*r*r); dvdrr = (erfcc/rsq + 2.0*alf/MY_PIS * erfcd/r) + f_shift; forcecoul = dvdrr*rsq*prefactor; if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor; } else forcecoul = 0.0; fforce = forcecoul / rsq; double eng = 0.0; if (rsq < cut_coulsq) { phicoul = prefactor * (erfcc-e_shift*r); if (factor_coul < 1.0) phicoul -= (1.0-factor_coul)*prefactor; eng += phicoul; } return eng; } diff --git a/src/pair_dpd.cpp b/src/pair_dpd.cpp index 99166918c..b5b959f85 100644 --- a/src/pair_dpd.cpp +++ b/src/pair_dpd.cpp @@ -1,410 +1,410 @@ /* ---------------------------------------------------------------------- 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: Kurt Smith (U Pittsburgh) ------------------------------------------------------------------------- */ #include #include #include #include "pair_dpd.h" #include "atom.h" #include "atom_vec.h" #include "comm.h" #include "update.h" #include "force.h" #include "neighbor.h" #include "neigh_list.h" #include "random_mars.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define EPSILON 1.0e-10 /* ---------------------------------------------------------------------- */ PairDPD::PairDPD(LAMMPS *lmp) : Pair(lmp) { writedata = 1; random = NULL; } /* ---------------------------------------------------------------------- */ PairDPD::~PairDPD() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut); memory->destroy(a0); memory->destroy(gamma); memory->destroy(sigma); } if (random) delete random; } /* ---------------------------------------------------------------------- */ void PairDPD::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair; double vxtmp,vytmp,vztmp,delvx,delvy,delvz; double rsq,r,rinv,dot,wd,randnum,factor_dpd; 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 **v = atom->v; double **f = atom->f; int *type = atom->type; int nlocal = atom->nlocal; double *special_lj = force->special_lj; int newton_pair = force->newton_pair; double dtinvsqrt = 1.0/sqrt(update->dt); 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]; vxtmp = v[i][0]; vytmp = v[i][1]; vztmp = v[i][2]; itype = type[i]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; factor_dpd = 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); if (r < EPSILON) continue; // r can be 0.0 in DPD systems rinv = 1.0/r; delvx = vxtmp - v[j][0]; delvy = vytmp - v[j][1]; delvz = vztmp - v[j][2]; dot = delx*delvx + dely*delvy + delz*delvz; wd = 1.0 - r/cut[itype][jtype]; randnum = random->gaussian(); // conservative force = a0 * wd // drag force = -gamma * wd^2 * (delx dot delv) / r // random force = sigma * wd * rnd * dtinvsqrt; fpair = a0[itype][jtype]*wd; fpair -= gamma[itype][jtype]*wd*wd*dot*rinv; fpair += sigma[itype][jtype]*wd*randnum*dtinvsqrt; fpair *= factor_dpd*rinv; 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) { // unshifted eng of conservative term: // evdwl = -a0[itype][jtype]*r * (1.0-0.5*r/cut[itype][jtype]); // eng shifted to 0.0 at cutoff evdwl = 0.5*a0[itype][jtype]*cut[itype][jtype] * wd*wd; evdwl *= factor_dpd; } 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 PairDPD::allocate() { int i,j; allocated = 1; int n = atom->ntypes; memory->create(setflag,n+1,n+1,"pair:setflag"); for (i = 1; i <= n; i++) for (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(a0,n+1,n+1,"pair:a0"); memory->create(gamma,n+1,n+1,"pair:gamma"); memory->create(sigma,n+1,n+1,"pair:sigma"); for (i = 0; i <= atom->ntypes; i++) for (j = 0; j <= atom->ntypes; j++) sigma[i][j] = gamma[i][j] = 0.0; } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairDPD::settings(int narg, char **arg) { if (narg != 3) error->all(FLERR,"Illegal pair_style command"); temperature = force->numeric(FLERR,arg[0]); cut_global = force->numeric(FLERR,arg[1]); seed = force->inumeric(FLERR,arg[2]); // initialize Marsaglia RNG with processor-unique seed if (seed <= 0) error->all(FLERR,"Illegal pair_style command"); delete random; random = new RanMars(lmp,seed + comm->me); // 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 PairDPD::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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double a0_one = force->numeric(FLERR,arg[2]); double gamma_one = force->numeric(FLERR,arg[3]); double cut_one = cut_global; if (narg == 5) cut_one = force->numeric(FLERR,arg[4]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { a0[i][j] = a0_one; gamma[i][j] = gamma_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 PairDPD::init_style() { if (comm->ghost_velocity == 0) error->all(FLERR,"Pair dpd requires ghost atoms store velocity"); // if newton off, forces between atoms ij will be double computed // using different random numbers if (force->newton_pair == 0 && comm->me == 0) error->warning(FLERR, "Pair dpd needs newton pair on for momentum conservation"); neighbor->request(this,instance_me); } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairDPD::init_one(int i, int j) { if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set"); sigma[i][j] = sqrt(2.0*force->boltz*temperature*gamma[i][j]); cut[j][i] = cut[i][j]; a0[j][i] = a0[i][j]; gamma[j][i] = gamma[i][j]; sigma[j][i] = sigma[i][j]; return cut[i][j]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairDPD::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(&a0[i][j],sizeof(double),1,fp); fwrite(&gamma[i][j],sizeof(double),1,fp); fwrite(&cut[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairDPD::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(&a0[i][j],sizeof(double),1,fp); fread(&gamma[i][j],sizeof(double),1,fp); fread(&cut[i][j],sizeof(double),1,fp); } MPI_Bcast(&a0[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&gamma[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairDPD::write_restart_settings(FILE *fp) { fwrite(&temperature,sizeof(double),1,fp); fwrite(&cut_global,sizeof(double),1,fp); fwrite(&seed,sizeof(int),1,fp); fwrite(&mix_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairDPD::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&temperature,sizeof(double),1,fp); fread(&cut_global,sizeof(double),1,fp); fread(&seed,sizeof(int),1,fp); fread(&mix_flag,sizeof(int),1,fp); } MPI_Bcast(&temperature,1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world); MPI_Bcast(&seed,1,MPI_INT,0,world); MPI_Bcast(&mix_flag,1,MPI_INT,0,world); // initialize Marsaglia RNG with processor-unique seed // same seed that pair_style command initially specified if (random) delete random; random = new RanMars(lmp,seed + comm->me); } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void PairDPD::write_data(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) fprintf(fp,"%d %g %g\n",i,a0[i][i],gamma[i][i]); } /* ---------------------------------------------------------------------- proc 0 writes all pairs to data file ------------------------------------------------------------------------- */ void PairDPD::write_data_all(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) fprintf(fp,"%d %d %g %g %g\n",i,j,a0[i][j],gamma[i][j],cut[i][j]); } /* ---------------------------------------------------------------------- */ double PairDPD::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_dpd, double &fforce) { double r,rinv,wd,phi; r = sqrt(rsq); if (r < EPSILON) { fforce = 0.0; return 0.0; } rinv = 1.0/r; wd = 1.0 - r/cut[itype][jtype]; fforce = a0[itype][jtype]*wd * factor_dpd*rinv; phi = 0.5*a0[itype][jtype]*cut[itype][jtype] * wd*wd; return factor_dpd*phi; } diff --git a/src/pair_dpd_tstat.cpp b/src/pair_dpd_tstat.cpp index 2c51bb8d8..6d8f75d95 100644 --- a/src/pair_dpd_tstat.cpp +++ b/src/pair_dpd_tstat.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 #include "pair_dpd_tstat.h" #include "atom.h" #include "update.h" #include "force.h" #include "neigh_list.h" #include "comm.h" #include "random_mars.h" #include "error.h" using namespace LAMMPS_NS; #define EPSILON 1.0e-10 /* ---------------------------------------------------------------------- */ PairDPDTstat::PairDPDTstat(LAMMPS *lmp) : PairDPD(lmp) { single_enable = 0; writedata = 1; } /* ---------------------------------------------------------------------- */ void PairDPDTstat::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,fpair; double vxtmp,vytmp,vztmp,delvx,delvy,delvz; double rsq,r,rinv,dot,wd,randnum,factor_dpd; int *ilist,*jlist,*numneigh,**firstneigh; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; // adjust sigma if target T is changing if (t_start != t_stop) { double delta = update->ntimestep - update->beginstep; if (delta != 0.0) delta /= update->endstep - update->beginstep; temperature = t_start + delta * (t_stop-t_start); double boltz = force->boltz; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) sigma[i][j] = sigma[j][i] = sqrt(2.0*boltz*temperature*gamma[i][j]); } double **x = atom->x; double **v = atom->v; double **f = atom->f; int *type = atom->type; int nlocal = atom->nlocal; double *special_lj = force->special_lj; int newton_pair = force->newton_pair; double dtinvsqrt = 1.0/sqrt(update->dt); 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]; vxtmp = v[i][0]; vytmp = v[i][1]; vztmp = v[i][2]; itype = type[i]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; factor_dpd = 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); if (r < EPSILON) continue; // r can be 0.0 in DPD systems rinv = 1.0/r; delvx = vxtmp - v[j][0]; delvy = vytmp - v[j][1]; delvz = vztmp - v[j][2]; dot = delx*delvx + dely*delvy + delz*delvz; wd = 1.0 - r/cut[itype][jtype]; randnum = random->gaussian(); // drag force = -gamma * wd^2 * (delx dot delv) / r // random force = sigma * wd * rnd * dtinvsqrt; fpair = -gamma[itype][jtype]*wd*wd*dot*rinv; fpair += sigma[itype][jtype]*wd*randnum*dtinvsqrt; fpair *= factor_dpd*rinv; 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 (evflag) ev_tally(i,j,nlocal,newton_pair, 0.0,0.0,fpair,delx,dely,delz); } } } if (vflag_fdotr) virial_fdotr_compute(); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairDPDTstat::settings(int narg, char **arg) { if (narg != 4) error->all(FLERR,"Illegal pair_style command"); t_start = force->numeric(FLERR,arg[0]); t_stop = force->numeric(FLERR,arg[1]); cut_global = force->numeric(FLERR,arg[2]); seed = force->inumeric(FLERR,arg[3]); temperature = t_start; // initialize Marsaglia RNG with processor-unique seed if (seed <= 0) error->all(FLERR,"Illegal pair_style command"); delete random; random = new RanMars(lmp,seed + comm->me); // 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 PairDPDTstat::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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double a0_one = 0.0; double gamma_one = force->numeric(FLERR,arg[2]); double cut_one = cut_global; if (narg == 4) cut_one = force->numeric(FLERR,arg[3]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { a0[i][j] = a0_one; gamma[i][j] = gamma_one; cut[i][j] = cut_one; setflag[i][j] = 1; count++; } } if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairDPDTstat::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(&gamma[i][j],sizeof(double),1,fp); fwrite(&cut[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairDPDTstat::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(&gamma[i][j],sizeof(double),1,fp); fread(&cut[i][j],sizeof(double),1,fp); } MPI_Bcast(&gamma[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairDPDTstat::write_restart_settings(FILE *fp) { fwrite(&t_start,sizeof(double),1,fp); fwrite(&t_stop,sizeof(double),1,fp); fwrite(&cut_global,sizeof(double),1,fp); fwrite(&seed,sizeof(int),1,fp); fwrite(&mix_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairDPDTstat::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&t_start,sizeof(double),1,fp); fread(&t_stop,sizeof(double),1,fp); fread(&cut_global,sizeof(double),1,fp); fread(&seed,sizeof(int),1,fp); fread(&mix_flag,sizeof(int),1,fp); } MPI_Bcast(&t_start,1,MPI_DOUBLE,0,world); MPI_Bcast(&t_stop,1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world); MPI_Bcast(&seed,1,MPI_INT,0,world); MPI_Bcast(&mix_flag,1,MPI_INT,0,world); temperature = t_start; // initialize Marsaglia RNG with processor-unique seed // same seed that pair_style command initially specified if (random) delete random; random = new RanMars(lmp,seed + comm->me); } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void PairDPDTstat::write_data(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) fprintf(fp,"%d %g\n",i,gamma[i][i]); } /* ---------------------------------------------------------------------- proc 0 writes all pairs to data file ------------------------------------------------------------------------- */ void PairDPDTstat::write_data_all(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) fprintf(fp,"%d %d %g %g\n",i,j,gamma[i][j],cut[i][j]); } diff --git a/src/pair_gauss.cpp b/src/pair_gauss.cpp index 1b922a215..c7b77c327 100644 --- a/src/pair_gauss.cpp +++ b/src/pair_gauss.cpp @@ -1,367 +1,367 @@ /* ---------------------------------------------------------------------- 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 #include #include #include #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]; writedata = 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 rsq; 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]) { fpair = -2.0*a[itype][jtype]*b[itype][jtype] * exp(-b[itype][jtype]*rsq); 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 = force->numeric(FLERR,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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double a_one = force->numeric(FLERR,arg[2]); double b_one = force->numeric(FLERR,arg[3]); double cut_one = cut_global; if (narg == 5) cut_one = force->numeric(FLERR,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) { double sign_bi = (b[i][i] >= 0.0) ? 1.0 : -1.0; double sign_bj = (b[j][j] >= 0.0) ? 1.0 : -1.0; double si = sqrt(0.5/fabs(b[i][i])); double sj = sqrt(0.5/fabs(b[j][j])); double sij = mix_distance(si, sj); b[i][j] = 0.5 / (sij*sij); b[i][j] *= MAX(sign_bi, sign_bj); // Negative "a" values are useful for simulating repulsive particles. // If either of the particles is repulsive (a<0), then the // interaction between both is repulsive. double sign_ai = (a[i][i] >= 0.0) ? 1.0 : -1.0; double sign_aj = (a[j][j] >= 0.0) ? 1.0 : -1.0; a[i][j] = mix_energy(fabs(a[i][i]), fabs(a[j][j]), si, sj); a[i][j] *= MIN(sign_ai, sign_aj); cut[i][j] = mix_distance(cut[i][i],cut[j][j]); } // cutoff correction to energy 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); } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void PairGauss::write_data(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) fprintf(fp,"%d %g %g\n",i,a[i][i],b[i][i]); } /* ---------------------------------------------------------------------- proc 0 writes all pairs to data file ------------------------------------------------------------------------- */ void PairGauss::write_data_all(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) fprintf(fp,"%d %d %g %g %g\n",i,j,a[i][j],b[i][j],cut[i][j]); } /* ---------------------------------------------------------------------- */ double PairGauss::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double philj = -(a[itype][jtype]*exp(-b[itype][jtype]*rsq) - offset[itype][jtype]); fforce = -2.0*a[itype][jtype]*b[itype][jtype] * exp(-b[itype][jtype]*rsq); return philj; } /* ---------------------------------------------------------------------- */ 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_hybrid.cpp b/src/pair_hybrid.cpp index 90b847339..3f4392d02 100644 --- a/src/pair_hybrid.cpp +++ b/src/pair_hybrid.cpp @@ -1,1044 +1,1044 @@ /* ---------------------------------------------------------------------- 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 #include #include #include #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" #include "respa.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ PairHybrid::PairHybrid(LAMMPS *lmp) : Pair(lmp) { nstyles = 0; styles = NULL; keywords = NULL; multiple = NULL; special_lj = NULL; special_coul = NULL; outerflag = 0; respaflag = 0; if (lmp->kokkos) error->all(FLERR,"Cannot yet use pair hybrid with Kokkos"); } /* ---------------------------------------------------------------------- */ PairHybrid::~PairHybrid() { if (nstyles) { for (int m = 0; m < nstyles; m++) { delete styles[m]; delete [] keywords[m]; if (special_lj[m]) delete [] special_lj[m]; if (special_coul[m]) delete [] special_coul[m]; } } delete [] styles; delete [] keywords; delete [] multiple; delete [] special_lj; delete [] special_coul; 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() or compute_outer() 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; double *saved_special = save_special(); // check if we are running with r-RESPA using the hybrid keyword Respa *respa = NULL; respaflag = 0; if (strstr(update->integrate_style,"respa")) { respa = (Respa *) update->integrate; if (respa->nhybrid_styles > 0) respaflag = 1; } for (m = 0; m < nstyles; m++) { set_special(m); if (!respaflag || (respaflag && respa->hybrid_compute[m])) { // invoke compute() unless compute flag is turned off or // outerflag is set and sub-style has a compute_outer() method if (styles[m]->compute_flag == 0) continue; if (outerflag && styles[m]->respa_enable) styles[m]->compute_outer(eflag,vflag_substyle); else styles[m]->compute(eflag,vflag_substyle); } restore_special(saved_special); // jump to next sub-style if r-RESPA does not want global accumulated data if (respaflag && !respa->tally_global) continue; 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]; } } delete [] saved_special; 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) { outerflag = 1; compute(eflag,vflag); outerflag = 0; } /* ---------------------------------------------------------------------- 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) { if (narg < 1) error->all(FLERR,"Illegal pair_style command"); // delete old lists, since cannot just change settings 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; } if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cutghost); memory->destroy(nmap); memory->destroy(map); } allocated = 0; // allocate list of sub-styles as big as possibly needed if no extra args styles = new Pair*[narg]; keywords = new char*[narg]; multiple = new int[narg]; special_lj = new double*[narg]; special_coul = new double*[narg]; // allocate each sub-style // allocate uses suffix, but don't store suffix version in keywords, // else syntax in coeff() will not match // call settings() with set of args that are not pair style names // use force->pair_map to determine which args these are int iarg,jarg,dummy; iarg = 0; nstyles = 0; while (iarg < narg) { if (strcmp(arg[iarg],"hybrid") == 0) error->all(FLERR,"Pair style hybrid cannot have hybrid as an argument"); if (strcmp(arg[iarg],"none") == 0) error->all(FLERR,"Pair style hybrid cannot have none as an argument"); styles[nstyles] = force->new_pair(arg[iarg],1,dummy); force->store_style(keywords[nstyles],arg[iarg],0); special_lj[nstyles] = special_coul[nstyles] = NULL; jarg = iarg + 1; while (jarg < narg && !force->pair_map->count(arg[jarg])) jarg++; styles[nstyles]->settings(jarg-iarg-1,&arg[iarg+1]); iarg = jarg; nstyles++; } // multiple[i] = 1 to M if sub-style used multiple times, else 0 for (int i = 0; i < nstyles; i++) { int count = 0; for (int j = 0; j < nstyles; j++) { if (strcmp(keywords[j],keywords[i]) == 0) count++; if (j == i) multiple[i] = count; } if (count == 1) multiple[i] = 0; } // set pair flags from sub-style flags flags(); } /* ---------------------------------------------------------------------- set top-level pair flags from sub-style flags ------------------------------------------------------------------------- */ void PairHybrid::flags() { int m; // set comm_forward, comm_reverse, comm_reverse_off 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); if (styles[m]) comm_reverse_off = MAX(comm_reverse_off, styles[m]->comm_reverse_off); } // single_enable = 1 if any sub-style is set // respa_enable = 1 if any sub-style is set // manybody_flag = 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 // ewaldflag, pppmflag, msmflag, dipoleflag, dispersionflag, tip4pflag = 1 // if any sub-style is set // compute_flag = 1 if any sub-style is set single_enable = 0; compute_flag = 0; for (m = 0; m < nstyles; m++) { if (styles[m]->single_enable) single_enable = 1; if (styles[m]->respa_enable) respa_enable = 1; if (styles[m]->manybody_flag) manybody_flag = 1; if (styles[m]->no_virial_fdotr_compute) no_virial_fdotr_compute = 1; if (styles[m]->ghostneigh) ghostneigh = 1; if (styles[m]->ewaldflag) ewaldflag = 1; if (styles[m]->pppmflag) pppmflag = 1; if (styles[m]->msmflag) msmflag = 1; if (styles[m]->dipoleflag) dipoleflag = 1; if (styles[m]->dispersionflag) dispersionflag = 1; if (styles[m]->tip4pflag) tip4pflag = 1; if (styles[m]->compute_flag) compute_flag = 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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); // 3rd arg = pair sub-style name // 4th arg = pair sub-style index if name used multiple times // allow for "none" as valid sub-style name int multflag; int m; for (m = 0; m < nstyles; m++) { multflag = 0; if (strcmp(arg[2],keywords[m]) == 0) { if (multiple[m]) { multflag = 1; if (narg < 4) error->all(FLERR,"Incorrect args for pair coefficients"); if (!isdigit(arg[3][0])) error->all(FLERR,"Incorrect args for pair coefficients"); int index = force->inumeric(FLERR,arg[3]); if (index == multiple[m]) break; else continue; } else 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 // if multflag: move 1st/2nd args to 3rd/4th args // just copy ptrs, since arg[] points into original input line arg[2+multflag] = arg[1]; arg[1+multflag] = arg[0]; // invoke sub-style coeff() starting with 1st remaining arg if (!none) styles[m]->coeff(narg-1-multflag,&arg[1+multflag]); // 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"); } // check if special_lj/special_coul overrides are compatible for (istyle = 0; istyle < nstyles; istyle++) { if (special_lj[istyle]) { for (i = 1; i < 4; ++i) { if (((force->special_lj[i] == 0.0) || (force->special_lj[i] == 1.0)) && (force->special_lj[i] != special_lj[istyle][i])) error->all(FLERR,"Pair_modify special setting for pair hybrid " "incompatible with global special_bonds setting"); } } if (special_coul[istyle]) { for (i = 1; i < 4; ++i) { if (((force->special_coul[i] == 0.0) || (force->special_coul[i] == 1.0)) && (force->special_coul[i] != special_coul[istyle][i])) error->all(FLERR,"Pair_modify special setting for pair hybrid " "incompatible with global special_bonds setting"); } } } // each sub-style makes its neighbor list request(s) for (istyle = 0; istyle < nstyles; istyle++) styles[istyle]->init_style(); // create skip lists inside 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 that request 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 // no skipping if pair style assigned to all type pairs 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; } /* ---------------------------------------------------------------------- invoke setup for each sub-style ------------------------------------------------------------------------- */ void PairHybrid::setup() { for (int m = 0; m < nstyles; m++) styles[m]->setup(); } /* ---------------------------------------------------------------------- examine sub-style neigh list requests create new parent requests if needed, to derive sub-style requests from ------------------------------------------------------------------------- */ void PairHybrid::modify_requests() { int i,j; NeighRequest *irq,*jrq; // loop over pair requests only, including those added during looping int nrequest_original = neighbor->nrequest; for (i = 0; i < neighbor->nrequest; i++) { if (!neighbor->requests[i]->pair) continue; // nothing more to do if this request: // is not a skip list // is a copy or half_from_full or granhistory list // copy list setup is from pair style = hybrid/overlay // which invokes this method at end of its modify_requests() // if granhistory, turn off skip, since each gran sub-style // its own history list, parent gran list does not have history // if half_from_full, turn off skip, since it will derive // from its full parent and its skip status irq = neighbor->requests[i]; if (irq->skip == 0) continue; if (irq->copy) continue; if (irq->granhistory || irq->half_from_full) { irq->skip = 0; continue; } // look for another list that matches via same_kind() and is not a skip list // if one exists, point at that one via otherlist // else make new parent request via copy_request() and point at that one // new parent list is not a skip list // parent does not need its ID set, since pair hybrid does not use it 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,instance_me); neighbor->requests[newrequest]->copy_request(irq); irq->otherlist = newrequest; } // for rRESPA inner/middle lists, // which just created or set otherlist to parent: // unset skip flag and otherlist // this prevents neighbor from treating them as skip lists if (irq->respainner || irq->respamiddle) { irq->skip = 0; irq->otherlist = -1; } } // adjustments to newly added granular parent requests (gran = 1) // set parent newton = 2 if has children with granonesided = 0 and 1 // else newton = 0 = setting of children // if 2, also set child off2on for both granonesided kinds of children // set parent gran onesided = 0 if has children with granonesided = 0 and 1 // else onesided = setting of children for (i = nrequest_original; i < neighbor->nrequest; i++) { if (!neighbor->requests[i]->pair) continue; if (!neighbor->requests[i]->gran) continue; irq = neighbor->requests[i]; int onesided = -1; for (j = 0; j < nrequest_original; j++) { if (!neighbor->requests[j]->pair) continue; if (!neighbor->requests[j]->gran) continue; if (neighbor->requests[j]->otherlist != i) continue; jrq = neighbor->requests[j]; if (onesided < 0) onesided = jrq->granonesided; else if (onesided != jrq->granonesided) onesided = 2; if (onesided == 2) break; } if (onesided == 2) { irq->newton = 2; irq->granonesided = 0; for (j = 0; j < nrequest_original; j++) { if (!neighbor->requests[j]->pair) continue; if (!neighbor->requests[j]->gran) continue; if (neighbor->requests[j]->otherlist != i) continue; jrq = neighbor->requests[j]; jrq->off2on = 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); // write out per style special settings, if present n = (special_lj[m] == NULL) ? 0 : 1; fwrite(&n,sizeof(int),1,fp); if (n) fwrite(special_lj[m],sizeof(double),4,fp); n = (special_coul[m] == NULL) ? 0 : 1; fwrite(&n,sizeof(int),1,fp); if (n) fwrite(special_coul[m],sizeof(double),4,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); // allocate list of sub-styles styles = new Pair*[nstyles]; keywords = new char*[nstyles]; multiple = new int[nstyles]; special_lj = new double*[nstyles]; special_coul = new double*[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],0,dummy); styles[m]->read_restart_settings(fp); // read back per style special settings, if present special_lj[m] = special_coul[m] = NULL; if (me == 0) fread(&n,sizeof(int),1,fp); MPI_Bcast(&n,1,MPI_INT,0,world); if (n > 0 ) { special_lj[m] = new double[4]; if (me == 0) fread(special_lj[m],sizeof(double),4,fp); MPI_Bcast(special_lj[m],4,MPI_DOUBLE,0,world); } if (me == 0) fread(&n,sizeof(int),1,fp); MPI_Bcast(&n,1,MPI_INT,0,world); if (n > 0 ) { special_coul[m] = new double[4]; if (me == 0) fread(special_coul[m],sizeof(double),4,fp); MPI_Bcast(special_coul[m],4,MPI_DOUBLE,0,world); } } // multiple[i] = 1 to M if sub-style used multiple times, else 0 for (int i = 0; i < nstyles; i++) { int count = 0; for (int j = 0; j < nstyles; j++) { if (strcmp(keywords[j],keywords[i]) == 0) count++; if (j == i) multiple[i] = count; } if (count == 1) multiple[i] = 0; } // set pair flags from sub-style flags flags(); } /* ---------------------------------------------------------------------- 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"); if ((special_lj[map[itype][jtype][m]] != NULL) || (special_coul[map[itype][jtype][m]] != NULL)) error->one(FLERR,"Pair hybrid single calls do not support" " per sub-style special bond values"); 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 and its sub-styles ------------------------------------------------------------------------- */ void PairHybrid::modify_params(int narg, char **arg) { if (narg == 0) error->all(FLERR,"Illegal pair_modify command"); // if 1st keyword is pair, apply other keywords to one sub-style if (strcmp(arg[0],"pair") == 0) { if (narg < 2) error->all(FLERR,"Illegal pair_modify command"); int m; for (m = 0; m < nstyles; m++) if (strcmp(arg[1],keywords[m]) == 0) break; if (m == nstyles) error->all(FLERR,"Unknown pair_modify hybrid sub-style"); int iarg = 2; if (multiple[m]) { if (narg < 3) error->all(FLERR,"Illegal pair_modify command"); int multiflag = force->inumeric(FLERR,arg[2]); for (m = 0; m < nstyles; m++) if (strcmp(arg[1],keywords[m]) == 0 && multiflag == multiple[m]) break; if (m == nstyles) error->all(FLERR,"Unknown pair_modify hybrid sub-style"); iarg = 3; } // if 2nd keyword (after pair) is special: // invoke modify_special() for the sub-style if (iarg < narg && strcmp(arg[iarg],"special") == 0) { if (narg < iarg+5) error->all(FLERR,"Illegal pair_modify special command"); modify_special(m,narg-iarg,&arg[iarg+1]); iarg += 5; } // apply the remaining keywords to the base pair style itself and the // sub-style except for "pair" and "special". // the former is important for some keywords like "tail" or "compute" if (narg-iarg > 0) { Pair::modify_params(narg-iarg,&arg[iarg]); styles[m]->modify_params(narg-iarg,&arg[iarg]); } // apply all keywords to pair hybrid itself and every sub-style } else { Pair::modify_params(narg,arg); for (int m = 0; m < nstyles; m++) styles[m]->modify_params(narg,arg); } } /* ---------------------------------------------------------------------- store a local per pair style override for special_lj and special_coul ------------------------------------------------------------------------- */ void PairHybrid::modify_special(int m, int narg, char **arg) { double special[4]; int i; special[0] = 1.0; special[1] = force->numeric(FLERR,arg[1]); special[2] = force->numeric(FLERR,arg[2]); special[3] = force->numeric(FLERR,arg[3]); if (strcmp(arg[0],"lj/coul") == 0) { if (!special_lj[m]) special_lj[m] = new double[4]; if (!special_coul[m]) special_coul[m] = new double[4]; for (i = 0; i < 4; ++i) special_lj[m][i] = special_coul[m][i] = special[i]; } else if (strcmp(arg[0],"lj") == 0) { if (!special_lj[m]) special_lj[m] = new double[4]; for (i = 0; i < 4; ++i) special_lj[m][i] = special[i]; } else if (strcmp(arg[0],"coul") == 0) { if (!special_coul[m]) special_coul[m] = new double[4]; for (i = 0; i < 4; ++i) special_coul[m][i] = special[i]; } else error->all(FLERR,"Illegal pair_modify special command"); } /* ---------------------------------------------------------------------- override global special bonds settings with per substyle values ------------------------------------------------------------------------- */ void PairHybrid::set_special(int m) { int i; if (special_lj[m]) for (i = 0; i < 4; ++i) force->special_lj[i] = special_lj[m][i]; if (special_coul[m]) for (i = 0; i < 4; ++i) force->special_coul[i] = special_coul[m][i]; } /* ---------------------------------------------------------------------- store global special settings ------------------------------------------------------------------------- */ double * PairHybrid::save_special() { double *saved = new double[8]; for (int i = 0; i < 4; ++i) { saved[i] = force->special_lj[i]; saved[i+4] = force->special_coul[i]; } return saved; } /* ---------------------------------------------------------------------- restore global special settings from saved data ------------------------------------------------------------------------- */ void PairHybrid::restore_special(double *saved) { for (int i = 0; i < 4; ++i) { force->special_lj[i] = saved[i]; force->special_coul[i] = saved[i+4]; } } /* ---------------------------------------------------------------------- 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(const char *str, int &dim) { void *cutptr = NULL; void *ptr; double cutvalue = 0.0; 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; } /* ---------------------------------------------------------------------- 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; } diff --git a/src/pair_hybrid_overlay.cpp b/src/pair_hybrid_overlay.cpp index 30c1d7d54..6ffd6a19d 100644 --- a/src/pair_hybrid_overlay.cpp +++ b/src/pair_hybrid_overlay.cpp @@ -1,142 +1,142 @@ /* ---------------------------------------------------------------------- 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 #include #include #include "pair_hybrid_overlay.h" #include "atom.h" #include "force.h" #include "neighbor.h" #include "neigh_request.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ PairHybridOverlay::PairHybridOverlay(LAMMPS *lmp) : PairHybrid(lmp) {} /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairHybridOverlay::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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); // 3rd arg = pair sub-style name // 4th arg = pair sub-style index if name used multiple times // allow for "none" as valid sub-style name int multflag; int m; for (m = 0; m < nstyles; m++) { multflag = 0; if (strcmp(arg[2],keywords[m]) == 0) { if (multiple[m]) { multflag = 1; if (narg < 4) error->all(FLERR,"Incorrect args for pair coefficients"); if (!isdigit(arg[3][0])) error->all(FLERR,"Incorrect args for pair coefficients"); int index = force->inumeric(FLERR,arg[3]); if (index == multiple[m]) break; else continue; } else 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 // if multflag: move 1st/2nd args to 3rd/4th args // just copy ptrs, since arg[] points into original input line arg[2+multflag] = arg[1]; arg[1+multflag] = arg[0]; // invoke sub-style coeff() starting with 1st remaining arg if (!none) styles[m]->coeff(narg-1-multflag,&arg[1+multflag]); // set setflag and which type pairs map to which sub-style // if sub-style is none: set hybrid subflag, wipe out map // else: set hybrid setflag & map only if substyle setflag is set // if sub-style is new for type pair, add as multiple mapping // if sub-style exists for type pair, don't add, just update coeffs 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]) { int k; for (k = 0; k < nmap[i][j]; k++) if (map[i][j][k] == m) break; if (k == nmap[i][j]) map[i][j][nmap[i][j]++] = m; setflag[i][j] = 1; count++; } } } if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- combine sub-style neigh list requests and create new ones if needed ------------------------------------------------------------------------- */ void PairHybridOverlay::modify_requests() { int i,j; NeighRequest *irq,*jrq; // loop over pair requests only // if a previous list is same kind with same skip attributes // then make this one a copy list of that one // works whether both lists are no-skip or yes-skip // will not point a list at a copy list, but at copy list's parent for (i = 0; i < neighbor->nrequest; i++) { if (!neighbor->requests[i]->pair) continue; irq = neighbor->requests[i]; for (j = 0; j < i; j++) { if (!neighbor->requests[j]->pair) continue; jrq = neighbor->requests[j]; if (irq->same_kind(jrq) && irq->same_skip(jrq)) { irq->copy = 1; irq->otherlist = j; break; } } } // perform same operations on skip lists as pair style = hybrid PairHybrid::modify_requests(); } diff --git a/src/pair_lj96_cut.cpp b/src/pair_lj96_cut.cpp index cba6fdbdb..1579a9fbf 100644 --- a/src/pair_lj96_cut.cpp +++ b/src/pair_lj96_cut.cpp @@ -1,727 +1,727 @@ /* ---------------------------------------------------------------------- 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: Chuanfu Luo (luochuanfu@gmail.com) ------------------------------------------------------------------------- */ #include #include #include #include #include "pair_lj96_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; /* ---------------------------------------------------------------------- */ PairLJ96Cut::PairLJ96Cut(LAMMPS *lmp) : Pair(lmp) { respa_enable = 1; writedata = 1; } /* ---------------------------------------------------------------------- */ PairLJ96Cut::~PairLJ96Cut() { 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 PairLJ96Cut::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,r3inv,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; r3inv = sqrt(r6inv); forcelj = r6inv * (lj1[itype][jtype]*r3inv - 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]*r3inv-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 PairLJ96Cut::compute_inner() { int i,j,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,fpair; double rsq,r2inv,r3inv,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; r3inv = sqrt(r6inv); jtype = type[j]; forcelj = r6inv * (lj1[itype][jtype]*r3inv - 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 PairLJ96Cut::compute_middle() { int i,j,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,fpair; double rsq,r2inv,r3inv,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; r3inv = sqrt(r6inv); jtype = type[j]; forcelj = r6inv * (lj1[itype][jtype]*r3inv - 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 PairLJ96Cut::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,r3inv,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; r3inv = sqrt(r6inv); forcelj = r6inv * (lj1[itype][jtype]*r3inv - 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; r3inv = sqrt(r6inv); evdwl = r6inv*(lj3[itype][jtype]*r3inv-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; r3inv = sqrt(r6inv); forcelj = r6inv * (lj1[itype][jtype]*r3inv - 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 PairLJ96Cut::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 PairLJ96Cut::settings(int narg, char **arg) { if (narg != 1) error->all(FLERR,"Illegal pair_style command"); cut_global = force->numeric(FLERR,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 PairLJ96Cut::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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(FLERR,arg[2]); double sigma_one = force->numeric(FLERR,arg[3]); double cut_one = cut_global; if (narg == 5) cut_one = force->numeric(FLERR,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 PairLJ96Cut::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,instance_me); else if (respa == 1) { irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respainner = 1; irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 3; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respaouter = 1; } else { irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respainner = 1; irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 2; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respamiddle = 1; irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 3; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respaouter = 1; } } else irequest = neighbor->request(this,instance_me); // 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 PairLJ96Cut::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 PairLJ96Cut::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] = 36.0 * epsilon[i][j] * pow(sigma[i][j],9.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],9.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,9.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 sig3 = sigma[i][j]*sigma[i][j]*sigma[i][j]; double sig6 = sig3*sig3; double rc3 = cut[i][j]*cut[i][j]*cut[i][j]; double rc6 = rc3*rc3; etail_ij = 8.0*MY_PI*all[0]*all[1]*epsilon[i][j] * sig6 * (sig3 - 2.0*rc3) / (6.0*rc6); ptail_ij = 8.0*MY_PI*all[0]*all[1]*epsilon[i][j] * sig6 * (3.0*sig3 - 4.0*rc3) / (6.0*rc6); } return cut[i][j]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJ96Cut::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 PairLJ96Cut::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 PairLJ96Cut::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); fwrite(&tail_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJ96Cut::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); fread(&tail_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); MPI_Bcast(&tail_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void PairLJ96Cut::write_data(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) fprintf(fp,"%d %g %g\n",i,epsilon[i][i],sigma[i][i]); } /* ---------------------------------------------------------------------- proc 0 writes all pairs to data file ------------------------------------------------------------------------- */ void PairLJ96Cut::write_data_all(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) fprintf(fp,"%d %d %g %g %g\n",i,j,epsilon[i][j],sigma[i][j],cut[i][j]); } /* ---------------------------------------------------------------------- */ double PairLJ96Cut::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r2inv,r3inv,r6inv,forcelj,philj; r2inv = 1.0/rsq; r6inv = r2inv*r2inv*r2inv; r3inv = sqrt(r6inv); forcelj = r6inv * (lj1[itype][jtype]*r3inv - lj2[itype][jtype]); fforce = factor_lj*forcelj*r2inv; philj = r6inv*(lj3[itype][jtype]*r3inv-lj4[itype][jtype]) - offset[itype][jtype]; return factor_lj*philj; } diff --git a/src/pair_lj_cubic.cpp b/src/pair_lj_cubic.cpp index 68b664fe2..633c12019 100644 --- a/src/pair_lj_cubic.cpp +++ b/src/pair_lj_cubic.cpp @@ -1,358 +1,358 @@ /* ---------------------------------------------------------------------- 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 #include #include #include #include "pair_lj_cubic.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; using namespace PairLJCubicConstants; /* ---------------------------------------------------------------------- */ PairLJCubic::PairLJCubic(LAMMPS *lmp) : Pair(lmp) {} /* ---------------------------------------------------------------------- */ PairLJCubic::~PairLJCubic() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut); memory->destroy(cut_inner); memory->destroy(cut_inner_sq); memory->destroy(epsilon); memory->destroy(sigma); memory->destroy(lj1); memory->destroy(lj2); memory->destroy(lj3); memory->destroy(lj4); } } /* ---------------------------------------------------------------------- */ void PairLJCubic::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; double r,t,rmin; 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; if (rsq <= cut_inner_sq[itype][jtype]) { r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); } else { r = sqrt(rsq); rmin = sigma[itype][jtype]*RT6TWO; t = (r - cut_inner[itype][jtype])/rmin; forcelj = epsilon[itype][jtype]*(-DPHIDS + A3*t*t/2.0)*r/rmin; } 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) { if (rsq <= cut_inner_sq[itype][jtype]) evdwl = r6inv * (lj3[itype][jtype]*r6inv - lj4[itype][jtype]); else evdwl = epsilon[itype][jtype]* (PHIS + DPHIDS*t - A3*t*t*t/6.0); 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 PairLJCubic::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(cut_inner,n+1,n+1,"pair:cut_inner"); memory->create(cut_inner_sq,n+1,n+1,"pair:cut_inner_sq"); 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"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairLJCubic::settings(int narg, char **arg) { if (narg != 0) error->all(FLERR,"Illegal pair_style command"); // 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] = 0.0; } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairLJCubic::coeff(int narg, char **arg) { if (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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(FLERR,arg[2]); double sigma_one = force->numeric(FLERR,arg[3]); double rmin = sigma_one*RT6TWO; 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_inner[i][j] = rmin*SS; cut[i][j] = rmin*SM; 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 PairLJCubic::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_inner[i][j] = mix_distance(cut_inner[i][i],cut_inner[j][j]); cut[i][j] = mix_distance(cut[i][i],cut[j][j]); } cut_inner_sq[i][j] = cut_inner[i][j]*cut_inner[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); cut_inner[j][i] = cut_inner[i][j]; cut_inner_sq[j][i] = cut_inner_sq[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]; return cut[i][j]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJCubic::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_inner[i][j],sizeof(double),1,fp); fwrite(&cut[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJCubic::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_inner[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_inner[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJCubic::write_restart_settings(FILE *fp) { fwrite(&mix_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJCubic::read_restart_settings(FILE *fp) { int me = comm->me; if (me == 0) { fread(&mix_flag,sizeof(int),1,fp); } MPI_Bcast(&mix_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- */ double PairLJCubic::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r2inv,r6inv,forcelj,philj; double r,t; double rmin; r2inv = 1.0/rsq; if (rsq <= cut_inner_sq[itype][jtype]) { r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); } else { r = sqrt(rsq); rmin = sigma[itype][jtype]*RT6TWO; t = (r - cut_inner[itype][jtype])/rmin; forcelj = epsilon[itype][jtype]*(-DPHIDS + A3*t*t/2.0)*r/rmin; } fforce = factor_lj*forcelj*r2inv; if (rsq <= cut_inner_sq[itype][jtype]) philj = r6inv * (lj3[itype][jtype]*r6inv - lj4[itype][jtype]); else philj = epsilon[itype][jtype]* (PHIS + DPHIDS*t - A3*t*t*t/6.0); return factor_lj*philj; } diff --git a/src/pair_lj_cut.cpp b/src/pair_lj_cut.cpp index ab1710b2f..b8ea4a72b 100644 --- a/src/pair_lj_cut.cpp +++ b/src/pair_lj_cut.cpp @@ -1,730 +1,730 @@ /* ---------------------------------------------------------------------- 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 #include #include #include #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; writedata = 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(FLERR,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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(FLERR,arg[2]); double sigma_one = force->numeric(FLERR,arg[3]); double cut_one = cut_global; if (narg == 5) cut_one = force->numeric(FLERR,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,instance_me); else if (respa == 1) { irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respainner = 1; irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 3; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respaouter = 1; } else { irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respainner = 1; irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 2; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respamiddle = 1; irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 3; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respaouter = 1; } } else irequest = neighbor->request(this,instance_me); // 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); fwrite(&tail_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); fread(&tail_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); MPI_Bcast(&tail_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void PairLJCut::write_data(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) fprintf(fp,"%d %g %g\n",i,epsilon[i][i],sigma[i][i]); } /* ---------------------------------------------------------------------- proc 0 writes all pairs to data file ------------------------------------------------------------------------- */ void PairLJCut::write_data_all(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) fprintf(fp,"%d %d %g %g %g\n",i,j,epsilon[i][j],sigma[i][j],cut[i][j]); } /* ---------------------------------------------------------------------- */ 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(const char *str, int &dim) { dim = 2; if (strcmp(str,"epsilon") == 0) return (void *) epsilon; if (strcmp(str,"sigma") == 0) return (void *) sigma; return NULL; } diff --git a/src/pair_lj_cut_coul_cut.cpp b/src/pair_lj_cut_coul_cut.cpp index 79d3fa12a..0d2bff3c9 100644 --- a/src/pair_lj_cut_coul_cut.cpp +++ b/src/pair_lj_cut_coul_cut.cpp @@ -1,471 +1,471 @@ /* ---------------------------------------------------------------------- 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 #include #include #include #include "pair_lj_cut_coul_cut.h" #include "atom.h" #include "comm.h" #include "force.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; /* ---------------------------------------------------------------------- */ PairLJCutCoulCut::PairLJCutCoulCut(LAMMPS *lmp) : Pair(lmp) { writedata = 1; } /* ---------------------------------------------------------------------- */ PairLJCutCoulCut::~PairLJCutCoulCut() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut_lj); memory->destroy(cut_ljsq); memory->destroy(cut_coul); memory->destroy(cut_coulsq); memory->destroy(epsilon); memory->destroy(sigma); memory->destroy(lj1); memory->destroy(lj2); memory->destroy(lj3); memory->destroy(lj4); memory->destroy(offset); } } /* ---------------------------------------------------------------------- */ void PairLJCutCoulCut::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; 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[itype][jtype]) forcecoul = qqrd2e * qtmp*q[j]*sqrt(r2inv); 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 = (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[itype][jtype]) ecoul = factor_coul * qqrd2e * qtmp*q[j]*sqrt(r2inv); 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(); } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairLJCutCoulCut::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(cut_coul,n+1,n+1,"pair:cut_coul"); memory->create(cut_coulsq,n+1,n+1,"pair:cut_coulsq"); 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 PairLJCutCoulCut::settings(int narg, char **arg) { if (narg < 1 || narg > 2) error->all(FLERR,"Illegal pair_style command"); cut_lj_global = force->numeric(FLERR,arg[0]); if (narg == 1) cut_coul_global = cut_lj_global; else cut_coul_global = force->numeric(FLERR,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; cut_coul[i][j] = cut_coul_global; } } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairLJCutCoulCut::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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(FLERR,arg[2]); double sigma_one = force->numeric(FLERR,arg[3]); double cut_lj_one = cut_lj_global; double cut_coul_one = cut_coul_global; if (narg >= 5) cut_coul_one = cut_lj_one = force->numeric(FLERR,arg[4]); if (narg == 6) cut_coul_one = force->numeric(FLERR,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; cut_lj[i][j] = cut_lj_one; cut_coul[i][j] = cut_coul_one; setflag[i][j] = 1; count++; } } if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairLJCutCoulCut::init_style() { if (!atom->q_flag) error->all(FLERR,"Pair style lj/cut/coul/cut requires atom attribute q"); neighbor->request(this,instance_me); } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairLJCutCoulCut::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]); cut_coul[i][j] = mix_distance(cut_coul[i][i],cut_coul[j][j]); } double cut = MAX(cut_lj[i][j],cut_coul[i][j]); cut_ljsq[i][j] = cut_lj[i][j] * cut_lj[i][j]; cut_coulsq[i][j] = cut_coul[i][j] * cut_coul[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]; cut_coulsq[j][i] = cut_coulsq[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 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; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJCutCoulCut::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); fwrite(&cut_coul[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJCutCoulCut::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); fread(&cut_coul[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); MPI_Bcast(&cut_coul[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJCutCoulCut::write_restart_settings(FILE *fp) { fwrite(&cut_lj_global,sizeof(double),1,fp); fwrite(&cut_coul_global,sizeof(double),1,fp); fwrite(&offset_flag,sizeof(int),1,fp); fwrite(&mix_flag,sizeof(int),1,fp); fwrite(&tail_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJCutCoulCut::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&cut_lj_global,sizeof(double),1,fp); fread(&cut_coul_global,sizeof(double),1,fp); fread(&offset_flag,sizeof(int),1,fp); fread(&mix_flag,sizeof(int),1,fp); fread(&tail_flag,sizeof(int),1,fp); } MPI_Bcast(&cut_lj_global,1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_coul_global,1,MPI_DOUBLE,0,world); MPI_Bcast(&offset_flag,1,MPI_INT,0,world); MPI_Bcast(&mix_flag,1,MPI_INT,0,world); MPI_Bcast(&tail_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void PairLJCutCoulCut::write_data(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) fprintf(fp,"%d %g %g\n",i,epsilon[i][i],sigma[i][i]); } /* ---------------------------------------------------------------------- proc 0 writes all pairs to data file ------------------------------------------------------------------------- */ void PairLJCutCoulCut::write_data_all(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) fprintf(fp,"%d %d %g %g %g\n",i,j,epsilon[i][j],sigma[i][j],cut_lj[i][j]); } /* ---------------------------------------------------------------------- */ double PairLJCutCoulCut::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; r2inv = 1.0/rsq; if (rsq < cut_coulsq[itype][jtype]) forcecoul = force->qqrd2e * atom->q[i]*atom->q[j]*sqrt(r2inv); 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 = (factor_coul*forcecoul + factor_lj*forcelj) * r2inv; double eng = 0.0; if (rsq < cut_coulsq[itype][jtype]) { phicoul = force->qqrd2e * atom->q[i]*atom->q[j]*sqrt(r2inv); eng += factor_coul*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 *PairLJCutCoulCut::extract(const char *str, int &dim) { dim = 0; if (strcmp(str,"cut_coul") == 0) return (void *) &cut_coul; dim = 2; if (strcmp(str,"epsilon") == 0) return (void *) epsilon; if (strcmp(str,"sigma") == 0) return (void *) sigma; return NULL; } diff --git a/src/pair_lj_cut_coul_dsf.cpp b/src/pair_lj_cut_coul_dsf.cpp index d80c7e74c..538336d8e 100644 --- a/src/pair_lj_cut_coul_dsf.cpp +++ b/src/pair_lj_cut_coul_dsf.cpp @@ -1,481 +1,481 @@ /* ---------------------------------------------------------------------- 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: Trung Dac Nguyen (ORNL) References: Fennell and Gezelter, JCP 124, 234104 (2006) ------------------------------------------------------------------------- */ #include #include #include #include #include "pair_lj_cut_coul_dsf.h" #include "atom.h" #include "comm.h" #include "force.h" #include "neighbor.h" #include "neigh_list.h" #include "memory.h" #include "math_const.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 /* ---------------------------------------------------------------------- */ PairLJCutCoulDSF::PairLJCutCoulDSF(LAMMPS *lmp) : Pair(lmp) { single_enable = 0; } /* ---------------------------------------------------------------------- */ PairLJCutCoulDSF::~PairLJCutCoulDSF() { if (!copymode) { 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 PairLJCutCoulDSF::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 r,rsq,r2inv,r6inv,forcecoul,forcelj,factor_coul,factor_lj; double prefactor,erfcc,erfcd,t; 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_lj = force->special_lj; 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]; if (eflag) { double e_self = -(e_shift/2.0 + alpha/MY_PIS) * qtmp*qtmp*qqrd2e; ev_tally(i,i,nlocal,0,0.0,e_self,0.0,0.0,0.0,0.0); } 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]); } else forcelj = 0.0; if (rsq < cut_coulsq) { r = sqrt(rsq); prefactor = qqrd2e*qtmp*q[j]/r; erfcd = exp(-alpha*alpha*r*r); t = 1.0 / (1.0 + EWALD_P*alpha*r); erfcc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * erfcd; forcecoul = prefactor * (erfcc/r + 2.0*alpha/MY_PIS * erfcd + r*f_shift) * r; if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor; } else forcecoul = 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_ljsq[itype][jtype]) { evdwl = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]) - offset[itype][jtype]; evdwl *= factor_lj; } else evdwl = 0.0; if (rsq < cut_coulsq) { ecoul = prefactor * (erfcc - r*e_shift - rsq*f_shift); if (factor_coul < 1.0) ecoul -= (1.0-factor_coul)*prefactor; } else ecoul = 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 PairLJCutCoulDSF::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 PairLJCutCoulDSF::settings(int narg, char **arg) { if (narg < 2 || narg > 3) error->all(FLERR,"Illegal pair_style command"); alpha = force->numeric(FLERR,arg[0]); cut_lj_global = force->numeric(FLERR,arg[1]); if (narg == 2) cut_coul = cut_lj_global; else cut_coul = force->numeric(FLERR,arg[2]); // 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 PairLJCutCoulDSF::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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(FLERR,arg[2]); double sigma_one = force->numeric(FLERR,arg[3]); double cut_lj_one = cut_lj_global; if (narg == 5) cut_lj_one = force->numeric(FLERR,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 PairLJCutCoulDSF::init_style() { if (!atom->q_flag) error->all(FLERR,"Pair style lj/cut/coul/dsf requires atom attribute q"); neighbor->request(this,instance_me); cut_coulsq = cut_coul * cut_coul; double erfcc = erfc(alpha*cut_coul); double erfcd = exp(-alpha*alpha*cut_coul*cut_coul); f_shift = -(erfcc/cut_coulsq + 2.0/MY_PIS*alpha*erfcd/cut_coul); e_shift = erfcc/cut_coul - f_shift*cut_coul; } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairLJCutCoulDSF::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]; // 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; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJCutCoulDSF::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 PairLJCutCoulDSF::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 PairLJCutCoulDSF::write_restart_settings(FILE *fp) { fwrite(&alpha,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); fwrite(&tail_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJCutCoulDSF::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&alpha,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); fread(&tail_flag,sizeof(int),1,fp); } MPI_Bcast(&alpha,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); MPI_Bcast(&tail_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- */ double PairLJCutCoulDSF::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r2inv,r6inv,r,erfcc,erfcd,prefactor; double forcecoul,forcelj,phicoul,philj; r2inv = 1.0/rsq; if (rsq < cut_ljsq[itype][jtype]) { r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); } else forcelj = 0.0; if (rsq < cut_coulsq) { r = sqrt(rsq); prefactor = factor_coul * force->qqrd2e * atom->q[i]*atom->q[j]/r; erfcc = erfc(alpha*r); erfcd = exp(-alpha*alpha*r*r); forcecoul = prefactor * (erfcc/r + 2.0*alpha/MY_PIS * erfcd + r*f_shift) * r; } else forcecoul = 0.0; fforce = (forcecoul + factor_lj*forcelj) * r2inv; double eng = 0.0; if (rsq < cut_ljsq[itype][jtype]) { philj = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]) - offset[itype][jtype]; eng += factor_lj*philj; } if (rsq < cut_coulsq) { phicoul = prefactor * (erfcc - r*e_shift - rsq*f_shift); eng += phicoul; } return eng; } /* ---------------------------------------------------------------------- */ void *PairLJCutCoulDSF::extract(const char *str, int &dim) { if (strcmp(str,"cut_coul") == 0) { dim = 0; return (void *) &cut_coul; } return NULL; } diff --git a/src/pair_lj_expand.cpp b/src/pair_lj_expand.cpp index 237ee91cc..90f1ae0df 100644 --- a/src/pair_lj_expand.cpp +++ b/src/pair_lj_expand.cpp @@ -1,427 +1,427 @@ /* ---------------------------------------------------------------------- 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 #include #include #include #include "pair_lj_expand.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; /* ---------------------------------------------------------------------- */ PairLJExpand::PairLJExpand(LAMMPS *lmp) : Pair(lmp) { writedata = 1; } /* ---------------------------------------------------------------------- */ PairLJExpand::~PairLJExpand() { if (!copymode) { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut); memory->destroy(epsilon); memory->destroy(sigma); memory->destroy(shift); memory->destroy(lj1); memory->destroy(lj2); memory->destroy(lj3); memory->destroy(lj4); memory->destroy(offset); } } } /* ---------------------------------------------------------------------- */ void PairLJExpand::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; double r,rshift,rshiftsq; 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); rshift = r - shift[itype][jtype]; rshiftsq = rshift*rshift; r2inv = 1.0/rshiftsq; r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); fpair = factor_lj*forcelj/rshift/r; 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(); } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairLJExpand::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(shift,n+1,n+1,"pair:shift"); 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 PairLJExpand::settings(int narg, char **arg) { if (narg != 1) error->all(FLERR,"Illegal pair_style command"); cut_global = force->numeric(FLERR,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 PairLJExpand::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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(FLERR,arg[2]); double sigma_one = force->numeric(FLERR,arg[3]); double shift_one = force->numeric(FLERR,arg[4]); double cut_one = cut_global; if (narg == 6) cut_one = force->numeric(FLERR,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; shift[i][j] = shift_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 PairLJExpand::init_one(int i, int j) { // always mix shift arithmetically 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]); shift[i][j] = 0.5 * (shift[i][i] + shift[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]; shift[j][i] = shift[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 sig2 = sigma[i][j]*sigma[i][j]; double sig6 = sig2*sig2*sig2; double rc1 = cut[i][j]; double rc2 = rc1*rc1; double rc3 = rc2*rc1; double rc9 = rc3*rc3*rc3; double shift1 = shift[i][j]; double shift2 = shift1*shift1; double shift3 = shift2*shift1; etail_ij = 8.0*MY_PI*all[0]*all[1]*epsilon[i][j] * sig6 * ((1.0/9.0 + 2.0*shift1/(10.0*rc1) + shift2/(11.0*rc2))*sig6/rc9 - (1.0/3.0 + 2.0*shift1/(4.0*rc1) + shift2/(5.0*rc2))/rc3); ptail_ij = 16.0*MY_PI*all[0]*all[1]*epsilon[i][j] * sig6 * ((1.0/9.0 + 3.0*shift1/(10.0*rc1) + 3.0*shift2/(11.0*rc2) + shift3/(12.0*rc3))*2.0*sig6/rc9 - (1.0/3.0 + 3.0*shift1/(4.0*rc1) + 3.0*shift2/(5.0*rc2) + shift3/(6.0*rc3))/rc3); } return cut[i][j] + shift[i][j]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJExpand::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(&shift[i][j],sizeof(double),1,fp); fwrite(&cut[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJExpand::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(&shift[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(&shift[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJExpand::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); fwrite(&tail_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJExpand::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); fread(&tail_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); MPI_Bcast(&tail_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void PairLJExpand::write_data(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) fprintf(fp,"%d %g %g %g\n",i,epsilon[i][i],sigma[i][i],shift[i][i]); } /* ---------------------------------------------------------------------- proc 0 writes all pairs to data file ------------------------------------------------------------------------- */ void PairLJExpand::write_data_all(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) fprintf(fp,"%d %d %g %g %g %g\n",i,j, epsilon[i][j],sigma[i][j],shift[i][j],cut[i][j]); } /* ---------------------------------------------------------------------- */ double PairLJExpand::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r,rshift,rshiftsq,r2inv,r6inv,forcelj,philj; r = sqrt(rsq); rshift = r - shift[itype][jtype]; rshiftsq = rshift*rshift; r2inv = 1.0/rshiftsq; r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); fforce = factor_lj*forcelj/rshift/r; philj = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]) - offset[itype][jtype]; return factor_lj*philj; } /* ---------------------------------------------------------------------- */ void *PairLJExpand::extract(const char *str, int &dim) { dim = 2; if (strcmp(str,"epsilon") == 0) return (void *) epsilon; if (strcmp(str,"sigma") == 0) return (void *) sigma; if (strcmp(str,"delta") == 0) return (void *) shift; return NULL; } diff --git a/src/pair_lj_gromacs.cpp b/src/pair_lj_gromacs.cpp index d5b24b733..bb0a6e647 100644 --- a/src/pair_lj_gromacs.cpp +++ b/src/pair_lj_gromacs.cpp @@ -1,444 +1,444 @@ /* ---------------------------------------------------------------------- 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: Mark Stevens (SNL) ------------------------------------------------------------------------- */ #include #include #include #include #include "pair_lj_gromacs.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; /* ---------------------------------------------------------------------- */ PairLJGromacs::PairLJGromacs(LAMMPS *lmp) : Pair(lmp) { writedata = 1; } /* ---------------------------------------------------------------------- */ PairLJGromacs::~PairLJGromacs() { if (!copymode) { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut); memory->destroy(cut_inner); memory->destroy(cut_inner_sq); memory->destroy(epsilon); memory->destroy(sigma); memory->destroy(lj1); memory->destroy(lj2); memory->destroy(lj3); memory->destroy(lj4); memory->destroy(ljsw1); memory->destroy(ljsw2); memory->destroy(ljsw3); memory->destroy(ljsw4); memory->destroy(ljsw5); } } } /* ---------------------------------------------------------------------- */ void PairLJGromacs::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; double r,t,fswitch,eswitch; 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]); if (rsq > cut_inner_sq[itype][jtype]) { r = sqrt(rsq); t = r - cut_inner[itype][jtype]; fswitch = r*t*t*(ljsw1[itype][jtype] + ljsw2[itype][jtype]*t); forcelj += fswitch; } 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]); evdwl += ljsw5[itype][jtype]; if (rsq > cut_inner_sq[itype][jtype]) { eswitch = t*t*t*(ljsw3[itype][jtype] + ljsw4[itype][jtype]*t); evdwl += eswitch; } 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 PairLJGromacs::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(cut_inner,n+1,n+1,"pair:cut_inner"); memory->create(cut_inner_sq,n+1,n+1,"pair:cut_inner_sq"); 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(ljsw1,n+1,n+1,"pair:ljsw1"); memory->create(ljsw2,n+1,n+1,"pair:ljsw2"); memory->create(ljsw3,n+1,n+1,"pair:ljsw3"); memory->create(ljsw4,n+1,n+1,"pair:ljsw4"); memory->create(ljsw5,n+1,n+1,"pair:ljsw5"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairLJGromacs::settings(int narg, char **arg) { if (narg != 2) error->all(FLERR,"Illegal pair_style command"); cut_inner_global = force->numeric(FLERR,arg[0]); cut_global = force->numeric(FLERR,arg[1]); if (cut_inner_global <= 0.0 || cut_inner_global > cut_global) error->all(FLERR,"Illegal pair_style command"); // 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_inner[i][j] = cut_inner_global; cut[i][j] = cut_global; } } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairLJGromacs::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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(FLERR,arg[2]); double sigma_one = force->numeric(FLERR,arg[3]); double cut_inner_one = cut_inner_global; double cut_one = cut_global; if (narg == 6) { cut_inner_one = force->numeric(FLERR,arg[4]); cut_one = force->numeric(FLERR,arg[5]); } if (cut_inner_one <= 0.0 || cut_inner_one > cut_one) error->all(FLERR,"Incorrect args for pair coefficients"); 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_inner[i][j] = cut_inner_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 PairLJGromacs::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_inner[i][j] = mix_distance(cut_inner[i][i],cut_inner[j][j]); cut[i][j] = mix_distance(cut[i][i],cut[j][j]); } cut_inner_sq[i][j] = cut_inner[i][j]*cut_inner[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); double r6inv = 1.0/pow(cut[i][j],6.0); double r8inv = 1.0/pow(cut[i][j],8.0); double t = cut[i][j] - cut_inner[i][j]; double t2inv = 1.0/(t*t); double t3inv = t2inv/t; double t3 = 1.0/t3inv; double a6 = (7.0*cut_inner[i][j] - 10.0*cut[i][j])*r8inv*t2inv; double b6 = (9.0*cut[i][j] - 7.0*cut_inner[i][j])*r8inv*t3inv; double a12 = (13.0*cut_inner[i][j] - 16.0*cut[i][j])*r6inv*r8inv*t2inv; double b12 = (15.0*cut[i][j] - 13.0*cut_inner[i][j])*r6inv*r8inv*t3inv; double c6 = r6inv - t3*(6.0*a6/3.0 + 6.0*b6*t/4.0); double c12 = r6inv*r6inv - t3*(12.0*a12/3.0 + 12.0*b12*t/4.0); ljsw1[i][j] = lj1[i][j]*a12 - lj2[i][j]*a6; ljsw2[i][j] = lj1[i][j]*b12 - lj2[i][j]*b6; ljsw3[i][j] = -lj3[i][j]*12.0*a12/3.0 + lj4[i][j]*6.0*a6/3.0; ljsw4[i][j] = -lj3[i][j]*12.0*b12/4.0 + lj4[i][j]*6.0*b6/4.0; ljsw5[i][j] = -lj3[i][j]*c12 + lj4[i][j]*c6; cut_inner[j][i] = cut_inner[i][j]; cut_inner_sq[j][i] = cut_inner_sq[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]; ljsw1[j][i] = ljsw1[i][j]; ljsw2[j][i] = ljsw2[i][j]; ljsw3[j][i] = ljsw3[i][j]; ljsw4[j][i] = ljsw4[i][j]; ljsw5[j][i] = ljsw5[i][j]; return cut[i][j]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJGromacs::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_inner[i][j],sizeof(double),1,fp); fwrite(&cut[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJGromacs::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_inner[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_inner[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJGromacs::write_restart_settings(FILE *fp) { fwrite(&cut_inner_global,sizeof(double),1,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 PairLJGromacs::read_restart_settings(FILE *fp) { int me = comm->me; if (me == 0) { fread(&cut_inner_global,sizeof(double),1,fp); fread(&cut_global,sizeof(double),1,fp); fread(&offset_flag,sizeof(int),1,fp); fread(&mix_flag,sizeof(int),1,fp); } MPI_Bcast(&cut_inner_global,1,MPI_DOUBLE,0,world); 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); } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void PairLJGromacs::write_data(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) fprintf(fp,"%d %g %g\n",i,epsilon[i][i],sigma[i][i]); } /* ---------------------------------------------------------------------- proc 0 writes all pairs to data file ------------------------------------------------------------------------- */ void PairLJGromacs::write_data_all(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) fprintf(fp,"%d %d %g %g %g %g\n",i,j, epsilon[i][j],sigma[i][j],cut_inner[i][j],cut[i][j]); } /* ---------------------------------------------------------------------- */ double PairLJGromacs::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r2inv,r6inv,forcelj,philj; double r,t,fswitch,phiswitch; r2inv = 1.0/rsq; r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); if (rsq > cut_inner_sq[itype][jtype]) { r = sqrt(rsq); t = r - cut_inner[itype][jtype]; fswitch = r*t*t*(ljsw1[itype][jtype] + ljsw2[itype][jtype]*t); forcelj += fswitch; } fforce = factor_lj*forcelj*r2inv; philj = r6inv * (lj3[itype][jtype]*r6inv - lj4[itype][jtype]); philj += ljsw5[itype][jtype]; if (rsq > cut_inner_sq[itype][jtype]) { phiswitch = t*t*t*(ljsw3[itype][jtype] + ljsw4[itype][jtype]*t); philj += phiswitch; } return factor_lj*philj; } diff --git a/src/pair_lj_gromacs_coul_gromacs.cpp b/src/pair_lj_gromacs_coul_gromacs.cpp index b68a557dc..26e433b38 100644 --- a/src/pair_lj_gromacs_coul_gromacs.cpp +++ b/src/pair_lj_gromacs_coul_gromacs.cpp @@ -1,511 +1,511 @@ /* ---------------------------------------------------------------------- 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: Mark Stevens (SNL) ------------------------------------------------------------------------- */ #include #include #include #include #include "pair_lj_gromacs_coul_gromacs.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; /* ---------------------------------------------------------------------- */ PairLJGromacsCoulGromacs::PairLJGromacsCoulGromacs(LAMMPS *lmp) : Pair(lmp) { writedata = 1; } /* ---------------------------------------------------------------------- */ PairLJGromacsCoulGromacs::~PairLJGromacsCoulGromacs() { if (!copymode) { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(epsilon); memory->destroy(sigma); memory->destroy(lj1); memory->destroy(lj2); memory->destroy(lj3); memory->destroy(lj4); memory->destroy(ljsw1); memory->destroy(ljsw2); memory->destroy(ljsw3); memory->destroy(ljsw4); memory->destroy(ljsw5); } } } /* ---------------------------------------------------------------------- */ void PairLJGromacsCoulGromacs::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 r,tlj,tc,fswitch,fswitchcoul,eswitch,ecoulswitch; 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; // skip if qi or qj = 0.0 since this potential may be used as // coarse-grain model with many uncharged atoms if (rsq < cut_coulsq && qtmp != 0.0 && q[j] != 0.0) { forcecoul = qqrd2e * qtmp*q[j]*sqrt(r2inv); if (rsq > cut_coul_innersq) { r = sqrt(rsq); tc = r - cut_coul_inner; fswitchcoul = qqrd2e * qtmp*q[j]*r*tc*tc*(coulsw1 + coulsw2*tc); forcecoul += fswitchcoul; } } 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) { r = sqrt(rsq); tlj = r - cut_lj_inner; fswitch = r*tlj*tlj*(ljsw1[itype][jtype] + ljsw2[itype][jtype]*tlj); forcelj += fswitch; } } 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) - coulsw5); if (rsq > cut_coul_innersq) { ecoulswitch = tc*tc*tc * (coulsw3 + coulsw4*tc); ecoul += qqrd2e*qtmp*q[j]*ecoulswitch; } ecoul *= factor_coul; } else ecoul = 0.0; if (rsq < cut_ljsq) { evdwl = r6inv * (lj3[itype][jtype]*r6inv - lj4[itype][jtype]); evdwl += ljsw5[itype][jtype]; if (rsq > cut_lj_innersq) { eswitch = tlj*tlj*tlj * (ljsw3[itype][jtype] + ljsw4[itype][jtype]*tlj); evdwl += eswitch; } 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 PairLJGromacsCoulGromacs::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(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(ljsw1,n+1,n+1,"pair:ljsw1"); memory->create(ljsw2,n+1,n+1,"pair:ljsw2"); memory->create(ljsw3,n+1,n+1,"pair:ljsw3"); memory->create(ljsw4,n+1,n+1,"pair:ljsw4"); memory->create(ljsw5,n+1,n+1,"pair:ljsw5"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairLJGromacsCoulGromacs::settings(int narg, char **arg) { if (narg != 2 && narg != 4) error->all(FLERR,"Illegal pair_style command"); cut_lj_inner = force->numeric(FLERR,arg[0]); cut_lj = force->numeric(FLERR,arg[1]); if (narg == 2) { cut_coul_inner = cut_lj_inner; cut_coul = cut_lj; } else { cut_coul_inner = force->numeric(FLERR,arg[2]); cut_coul = force->numeric(FLERR,arg[3]); } if (cut_lj_inner <= 0.0 || cut_coul_inner < 0.0) error->all(FLERR,"Illegal pair_style command"); if (cut_lj_inner > cut_lj || cut_coul_inner > cut_coul) error->all(FLERR,"Illegal pair_style command"); } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairLJGromacsCoulGromacs::coeff(int narg, char **arg) { if (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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(FLERR,arg[2]); double sigma_one = force->numeric(FLERR,arg[3]); 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; setflag[i][j] = 1; count++; } } if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairLJGromacsCoulGromacs::init_style() { if (!atom->q_flag) error->all(FLERR, "Pair style lj/gromacs/coul/gromacs requires atom attribute q"); neighbor->request(this,instance_me); 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); } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairLJGromacsCoulGromacs::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]); } 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); double r6inv = 1.0/pow(cut_lj,6.0); double r8inv = 1.0/pow(cut_lj,8.0); double t = cut_lj - cut_lj_inner; double t2inv = 1.0/(t*t); double t3inv = t2inv/t; double t3 = 1.0/t3inv; double a6 = (7.0*cut_lj_inner - 10.0*cut_lj)*r8inv*t2inv; double b6 = (9.0*cut_lj - 7.0*cut_lj_inner)*r8inv*t3inv; double a12 = (13.0*cut_lj_inner - 16.0*cut_lj)*r6inv*r8inv*t2inv; double b12 = (15.0*cut_lj - 13.0*cut_lj_inner)*r6inv*r8inv*t3inv; double c6 = r6inv - t3*(6.0*a6/3.0 + 6.0*b6*t/4.0); double c12 = r6inv*r6inv - t3*(12.0*a12/3.0 + 12.0*b12*t/4.0); ljsw1[i][j] = lj1[i][j]*a12 - lj2[i][j]*a6; ljsw2[i][j] = lj1[i][j]*b12 - lj2[i][j]*b6; ljsw3[i][j] = -lj3[i][j]*12.0*a12/3.0 + lj4[i][j]*6.0*a6/3.0; ljsw4[i][j] = -lj3[i][j]*12.0*b12/4.0 + lj4[i][j]*6.0*b6/4.0; ljsw5[i][j] = -lj3[i][j]*c12 + lj4[i][j]*c6; double r3inv = 1.0/pow(cut_coul,3.0); t = cut_coul - cut_coul_inner; t2inv = 1.0/(t*t); t3inv = t2inv/t; double a1 = (2.0*cut_coul_inner - 5.0*cut_coul) * r3inv*t2inv; double b1 = (4.0*cut_coul - 2.0*cut_coul_inner) * r3inv*t3inv; coulsw1 = a1; coulsw2 = b1; coulsw3 = -a1/3.0; coulsw4 = -b1/4.0; coulsw5 = 1.0/cut_coul - t*t*t*(a1/3.0 + b1*t/4.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]; ljsw1[j][i] = ljsw1[i][j]; ljsw2[j][i] = ljsw2[i][j]; ljsw3[j][i] = ljsw3[i][j]; ljsw4[j][i] = ljsw4[i][j]; ljsw5[j][i] = ljsw5[i][j]; return cut; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJGromacsCoulGromacs::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); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJGromacsCoulGromacs::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); } MPI_Bcast(&epsilon[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJGromacsCoulGromacs::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 PairLJGromacsCoulGromacs::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); } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void PairLJGromacsCoulGromacs::write_data(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) fprintf(fp,"%d %g %g\n",i,epsilon[i][i],sigma[i][i]); } /* ---------------------------------------------------------------------- proc 0 writes all pairs to data file ------------------------------------------------------------------------- */ void PairLJGromacsCoulGromacs::write_data_all(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) fprintf(fp,"%d %d %g %g\n",i,j,epsilon[i][j],sigma[i][j]); } /* ---------------------------------------------------------------------- */ double PairLJGromacsCoulGromacs::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 r,tlj,tc,fswitch,phiswitch,fswitchcoul,phiswitchcoul; r2inv = 1.0/rsq; if (rsq < cut_coulsq) { forcecoul = force->qqrd2e * atom->q[i]*atom->q[j]*sqrt(r2inv); if (rsq > cut_coul_innersq) { r = sqrt(rsq); tc = r - cut_coul_inner; fswitchcoul = force->qqrd2e * atom->q[i]*atom->q[j] * r*tc*tc * (coulsw1 + coulsw2*tc); forcecoul += fswitchcoul; } } 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) { r = sqrt(rsq); tlj = r - cut_lj_inner; fswitch = r*tlj*tlj*(ljsw1[itype][jtype] + ljsw2[itype][jtype]*tlj); forcelj += fswitch; } } 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)-coulsw5); if (rsq > cut_coul_innersq) { phiswitchcoul = force->qqrd2e * atom->q[i]*atom->q[j] * tc*tc*tc * (coulsw3 + coulsw4*tc); phicoul += phiswitchcoul; } eng += factor_coul*phicoul; } if (rsq < cut_ljsq) { philj = r6inv * (lj3[itype][jtype]*r6inv - lj4[itype][jtype]); philj += ljsw5[itype][jtype]; if (rsq > cut_lj_innersq) { phiswitch = tlj*tlj*tlj * (ljsw3[itype][jtype] + ljsw4[itype][jtype]*tlj); philj += phiswitch; } eng += factor_lj*philj; } return eng; } diff --git a/src/pair_lj_smooth.cpp b/src/pair_lj_smooth.cpp index b73545f57..c59b35aeb 100644 --- a/src/pair_lj_smooth.cpp +++ b/src/pair_lj_smooth.cpp @@ -1,456 +1,456 @@ /* ---------------------------------------------------------------------- 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: Craig Maloney (UCSB) ------------------------------------------------------------------------- */ #include #include #include #include "pair_lj_smooth.h" #include "atom.h" #include "comm.h" #include "force.h" #include "neigh_list.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ PairLJSmooth::PairLJSmooth(LAMMPS *lmp) : Pair(lmp) { writedata = 1; } /* ---------------------------------------------------------------------- */ PairLJSmooth::~PairLJSmooth() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut); memory->destroy(cut_inner); memory->destroy(cut_inner_sq); memory->destroy(epsilon); memory->destroy(sigma); memory->destroy(lj1); memory->destroy(lj2); memory->destroy(lj3); memory->destroy(lj4); memory->destroy(ljsw0); memory->destroy(ljsw1); memory->destroy(ljsw2); memory->destroy(ljsw3); memory->destroy(ljsw4); memory->destroy(offset); } } /* ---------------------------------------------------------------------- */ void PairLJSmooth::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; double r,t,tsq,fskin; 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; if (rsq < cut_inner_sq[itype][jtype]) { r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv-lj2[itype][jtype]); } else { r = sqrt(rsq); t = r - cut_inner[itype][jtype]; tsq = t*t; fskin = ljsw1[itype][jtype] + ljsw2[itype][jtype]*t + ljsw3[itype][jtype]*tsq + ljsw4[itype][jtype]*tsq*t; forcelj = fskin*r; } 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) { if (rsq < cut_inner_sq[itype][jtype]) evdwl = r6inv * (lj3[itype][jtype]*r6inv - lj4[itype][jtype]) - offset[itype][jtype]; else evdwl = ljsw0[itype][jtype] - ljsw1[itype][jtype]*t - ljsw2[itype][jtype]*tsq/2.0 - ljsw3[itype][jtype]*tsq*t/3.0 - ljsw4[itype][jtype]*tsq*tsq/4.0 - 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 PairLJSmooth::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(cut_inner,n+1,n+1,"pair:cut_inner"); memory->create(cut_inner_sq,n+1,n+1,"pair:cut_inner_sq"); 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(ljsw0,n+1,n+1,"pair:ljsw0"); memory->create(ljsw1,n+1,n+1,"pair:ljsw1"); memory->create(ljsw2,n+1,n+1,"pair:ljsw2"); memory->create(ljsw3,n+1,n+1,"pair:ljsw3"); memory->create(ljsw4,n+1,n+1,"pair:ljsw4"); memory->create(offset,n+1,n+1,"pair:offset"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairLJSmooth::settings(int narg, char **arg) { if (narg != 2) error->all(FLERR,"Illegal pair_style command"); cut_inner_global = force->numeric(FLERR,arg[0]); cut_global = force->numeric(FLERR,arg[1]); if (cut_inner_global <= 0.0 || cut_inner_global > cut_global) error->all(FLERR,"Illegal pair_style command"); // 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_inner[i][j] = cut_inner_global; cut[i][j] = cut_global; } } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairLJSmooth::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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(FLERR,arg[2]); double sigma_one = force->numeric(FLERR,arg[3]); double cut_inner_one = cut_inner_global; double cut_one = cut_global; if (narg == 6) { cut_inner_one = force->numeric(FLERR,arg[4]); cut_one = force->numeric(FLERR,arg[5]); } if (cut_inner_one <= 0.0 || cut_inner_one > cut_one) error->all(FLERR,"Incorrect args for pair coefficients"); 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_inner[i][j] = cut_inner_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 PairLJSmooth::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_inner[i][j] = mix_distance(cut_inner[i][i],cut_inner[j][j]); cut[i][j] = mix_distance(cut[i][i],cut[j][j]); } cut_inner_sq[i][j] = cut_inner[i][j]*cut_inner[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 (cut_inner[i][j] != cut[i][j]) { double r6inv = 1.0/pow(cut_inner[i][j],6.0); double t = cut[i][j] - cut_inner[i][j]; double tsq = t*t; double ratio = sigma[i][j] / cut_inner[i][j]; ljsw0[i][j] = 4.0*epsilon[i][j]*(pow(ratio,12.0) - pow(ratio,6.0)); ljsw1[i][j] = r6inv*(lj1[i][j]*r6inv-lj2[i][j]) / cut_inner[i][j]; ljsw2[i][j] = -r6inv * (13.0*lj1[i][j]*r6inv - 7.0*lj2[i][j]) / cut_inner_sq[i][j]; ljsw3[i][j] = -(3.0/tsq) * (ljsw1[i][j] + 2.0/3.0*ljsw2[i][j]*t); ljsw4[i][j] = -1.0/(3.0*tsq) * (ljsw2[i][j] + 2.0*ljsw3[i][j]*t); if (offset_flag) offset[i][j] = ljsw0[i][j] - ljsw1[i][j]*t - ljsw2[i][j]*tsq/2.0 - ljsw3[i][j]*tsq*t/3.0 - ljsw4[i][j]*tsq*tsq/4.0; else offset[i][j] = 0.0; } else { ljsw0[i][j] = 0.0; ljsw1[i][j] = 0.0; ljsw2[i][j] = 0.0; ljsw3[i][j] = 0.0; ljsw4[i][j] = 0.0; double ratio = sigma[i][j] / cut_inner[i][j]; if (offset_flag) offset[i][j] = 4.0 * epsilon[i][j] * (pow(ratio,12.0) - pow(ratio,6.0)); else offset[i][j] = 0.0; } cut_inner[j][i] = cut_inner[i][j]; cut_inner_sq[j][i] = cut_inner_sq[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]; ljsw0[j][i] = ljsw0[i][j]; ljsw1[j][i] = ljsw1[i][j]; ljsw2[j][i] = ljsw2[i][j]; ljsw3[j][i] = ljsw3[i][j]; ljsw4[j][i] = ljsw4[i][j]; offset[j][i] = offset[i][j]; return cut[i][j]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJSmooth::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_inner[i][j],sizeof(double),1,fp); fwrite(&cut[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJSmooth::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_inner[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_inner[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJSmooth::write_restart_settings(FILE *fp) { fwrite(&cut_inner_global,sizeof(double),1,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 PairLJSmooth::read_restart_settings(FILE *fp) { int me = comm->me; if (me == 0) { fread(&cut_inner_global,sizeof(double),1,fp); fread(&cut_global,sizeof(double),1,fp); fread(&offset_flag,sizeof(int),1,fp); fread(&mix_flag,sizeof(int),1,fp); } MPI_Bcast(&cut_inner_global,1,MPI_DOUBLE,0,world); 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); } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void PairLJSmooth::write_data(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) fprintf(fp,"%d %g %g\n",i,epsilon[i][i],sigma[i][i]); } /* ---------------------------------------------------------------------- proc 0 writes all pairs to data file ------------------------------------------------------------------------- */ void PairLJSmooth::write_data_all(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) fprintf(fp,"%d %d %g %g %g %g\n",i,j, epsilon[i][j],sigma[i][j],cut_inner[i][j],cut[i][j]); } /* ---------------------------------------------------------------------- */ double PairLJSmooth::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r2inv,r6inv,forcelj,philj,r,t,tsq,fskin; r2inv = 1.0/rsq; if (rsq < cut_inner_sq[itype][jtype]) { r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv-lj2[itype][jtype]); } else { r = sqrt(rsq); t = r - cut_inner[itype][jtype]; tsq = t*t; fskin = ljsw1[itype][jtype] + ljsw2[itype][jtype]*t + ljsw3[itype][jtype]*tsq + ljsw4[itype][jtype]*tsq*t; forcelj = fskin*r; } fforce = factor_lj*forcelj*r2inv; if (rsq < cut_inner_sq[itype][jtype]) philj = r6inv * (lj3[itype][jtype]*r6inv - lj4[itype][jtype]) - offset[itype][jtype]; else philj = ljsw0[itype][jtype] - ljsw1[itype][jtype]*t - ljsw2[itype][jtype]*tsq/2.0 - ljsw3[itype][jtype]*tsq*t/3.0 - ljsw4[itype][jtype]*tsq*tsq/4.0 - offset[itype][jtype]; return factor_lj*philj; } diff --git a/src/pair_lj_smooth_linear.cpp b/src/pair_lj_smooth_linear.cpp index fa41bcae4..189475aa7 100644 --- a/src/pair_lj_smooth_linear.cpp +++ b/src/pair_lj_smooth_linear.cpp @@ -1,349 +1,349 @@ /* ---------------------------------------------------------------------- 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: Jonathan Zimmerman (Sandia) ------------------------------------------------------------------------- */ #include #include #include #include "pair_lj_smooth_linear.h" #include "atom.h" #include "comm.h" #include "force.h" #include "neigh_list.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ PairLJSmoothLinear::PairLJSmoothLinear(LAMMPS *lmp) : Pair(lmp) {} /* ---------------------------------------------------------------------- */ PairLJSmoothLinear::~PairLJSmoothLinear() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut); memory->destroy(epsilon); memory->destroy(sigma); memory->destroy(ljcut); memory->destroy(dljcut); memory->destroy(lj1); memory->destroy(lj2); memory->destroy(lj3); memory->destroy(lj4); } } /* ---------------------------------------------------------------------- */ void PairLJSmoothLinear::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; double r,rinv; 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; rinv = sqrt(r2inv); forcelj = r6inv*(lj1[itype][jtype]*r6inv-lj2[itype][jtype]); forcelj = rinv*forcelj - dljcut[itype][jtype]; fpair = factor_lj*forcelj*rinv; 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) { r = sqrt(rsq); evdwl = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]); evdwl = evdwl - ljcut[itype][jtype] + (r-cut[itype][jtype])*dljcut[itype][jtype]; } 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 PairLJSmoothLinear::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(ljcut,n+1,n+1,"pair:ljcut"); memory->create(dljcut,n+1,n+1,"pair:dljcut"); 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"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairLJSmoothLinear::settings(int narg, char **arg) { if (narg != 1) error->all(FLERR,"Illegal pair_style command"); cut_global = force->numeric(FLERR,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 PairLJSmoothLinear::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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(FLERR,arg[2]); double sigma_one = force->numeric(FLERR,arg[3]); double cut_one = cut_global; if (narg == 5) { cut_one = force->numeric(FLERR,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 for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairLJSmoothLinear::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); double cut6inv = pow(cut[i][j],-6.0); double cutinv = 1.0/cut[i][j]; ljcut[i][j] = cut6inv*(lj3[i][j]*cut6inv-lj4[i][j]); dljcut[i][j] = cutinv*cut6inv*(lj1[i][j]*cut6inv-lj2[i][j]); cut[j][i] = cut[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]; cut[j][i] = cut[i][j]; ljcut[j][i] = ljcut[i][j]; dljcut[j][i] = dljcut[i][j]; return cut[i][j]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJSmoothLinear::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 PairLJSmoothLinear::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 PairLJSmoothLinear::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 PairLJSmoothLinear::read_restart_settings(FILE *fp) { int me = comm->me; if (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 PairLJSmoothLinear::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r2inv,r6inv,forcelj,philj,r,rinv; r2inv = 1.0/rsq; r6inv = r2inv*r2inv*r2inv; rinv = sqrt(r2inv); r = sqrt(rsq); forcelj = r6inv*(lj1[itype][jtype]*r6inv-lj2[itype][jtype]); forcelj = rinv*forcelj - dljcut[itype][jtype]; fforce = factor_lj*forcelj*rinv; philj = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]); philj = philj - ljcut[itype][jtype] + (r-cut[itype][jtype])*dljcut[itype][jtype]; return factor_lj*philj; } diff --git a/src/pair_mie_cut.cpp b/src/pair_mie_cut.cpp index 7cb67b943..b79c6c9bf 100644 --- a/src/pair_mie_cut.cpp +++ b/src/pair_mie_cut.cpp @@ -1,743 +1,743 @@ /* ---------------------------------------------------------------------- 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: Cassiano Aimoli (aimoli@gmail.com) ------------------------------------------------------------------------- */ #include #include #include #include #include "pair_mie_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; /* ---------------------------------------------------------------------- */ PairMIECut::PairMIECut(LAMMPS *lmp) : Pair(lmp) { respa_enable = 1; } /* ---------------------------------------------------------------------- */ PairMIECut::~PairMIECut() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut); memory->destroy(epsilon); memory->destroy(sigma); memory->destroy(gamR); memory->destroy(gamA); memory->destroy(Cmie); memory->destroy(mie1); memory->destroy(mie2); memory->destroy(mie3); memory->destroy(mie4); memory->destroy(offset); } } /* ---------------------------------------------------------------------- */ void PairMIECut::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,rgamR,rgamA,forcemie,factor_mie; 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_mie = 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_mie = special_mie[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; rgamA = pow(r2inv,(gamA[itype][jtype]/2.0)); rgamR = pow(r2inv,(gamR[itype][jtype]/2.0)); forcemie = (mie1[itype][jtype]*rgamR - mie2[itype][jtype]*rgamA); fpair = factor_mie*forcemie*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 = (mie3[itype][jtype]*rgamR - mie4[itype][jtype]*rgamA) - offset[itype][jtype]; evdwl *= factor_mie; } if (evflag) ev_tally(i,j,nlocal,newton_pair, evdwl,0.0,fpair,delx,dely,delz); } } } if (vflag_fdotr) virial_fdotr_compute(); } /* ---------------------------------------------------------------------- */ void PairMIECut::compute_inner() { int i,j,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,fpair; double rsq,r2inv,rgamR,rgamA,forcemie,factor_mie,rsw; int *ilist,*jlist,*numneigh,**firstneigh; double **x = atom->x; double **f = atom->f; int *type = atom->type; int nlocal = atom->nlocal; double *special_mie = 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_mie = special_mie[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) { jtype = type[j]; r2inv = 1.0/rsq; rgamA = pow(r2inv,(gamA[itype][jtype]/2.0)); rgamR = pow(r2inv,(gamR[itype][jtype]/2.0)); forcemie = (mie1[itype][jtype]*rgamR - mie2[itype][jtype]*rgamA); fpair = factor_mie*forcemie*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 PairMIECut::compute_middle() { int i,j,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,fpair; double rsq,r2inv,rgamR,rgamA,forcemie,factor_mie,rsw; int *ilist,*jlist,*numneigh,**firstneigh; double **x = atom->x; double **f = atom->f; int *type = atom->type; int nlocal = atom->nlocal; double *special_mie = 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_mie = special_mie[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) { jtype = type[j]; r2inv = 1.0/rsq; rgamA = pow(r2inv,(gamA[itype][jtype]/2.0)); rgamR = pow(r2inv,(gamR[itype][jtype]/2.0)); forcemie = (mie1[itype][jtype]*rgamR - mie2[itype][jtype]*rgamA); fpair = factor_mie*forcemie*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 PairMIECut::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,rgamR,rgamA,forcemie,factor_mie,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_mie = 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_mie = special_mie[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; rgamA = pow(r2inv,(gamA[itype][jtype]/2.0)); rgamR = pow(r2inv,(gamR[itype][jtype]/2.0)); forcemie = (mie1[itype][jtype]*rgamR - mie2[itype][jtype]*rgamA); fpair = factor_mie*forcemie*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; rgamA = pow(r2inv,(gamA[itype][jtype]/2.0)); rgamR = pow(r2inv,(gamR[itype][jtype]/2.0)); evdwl = (mie3[itype][jtype]*rgamR - mie4[itype][jtype]*rgamA) - offset[itype][jtype]; evdwl *= factor_mie; } if (vflag) { if (rsq <= cut_in_off_sq) { r2inv = 1.0/rsq; rgamA = pow(r2inv,(gamA[itype][jtype]/2.0)); rgamR = pow(r2inv,(gamR[itype][jtype]/2.0)); forcemie = (mie1[itype][jtype]*rgamR - mie2[itype][jtype]*rgamA); fpair = factor_mie*forcemie*r2inv; } else if (rsq < cut_in_on_sq) fpair = factor_mie*forcemie*r2inv; } if (evflag) ev_tally(i,j,nlocal,newton_pair, evdwl,0.0,fpair,delx,dely,delz); } } } } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairMIECut::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(gamR,n+1,n+1,"pair:gamR"); memory->create(gamA,n+1,n+1,"pair:gamA"); memory->create(Cmie,n+1,n+1,"pair:Cmie"); memory->create(mie1,n+1,n+1,"pair:mie1"); memory->create(mie2,n+1,n+1,"pair:mie2"); memory->create(mie3,n+1,n+1,"pair:mie3"); memory->create(mie4,n+1,n+1,"pair:mie4"); memory->create(offset,n+1,n+1,"pair:offset"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairMIECut::settings(int narg, char **arg) { if (narg != 1) error->all(FLERR,"Illegal pair_style command"); cut_global = force->numeric(FLERR,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 PairMIECut::coeff(int narg, char **arg) { if (narg < 6 || narg > 7) 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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(FLERR,arg[2]); double sigma_one = force->numeric(FLERR,arg[3]); double gamR_one = force->numeric(FLERR,arg[4]); double gamA_one = force->numeric(FLERR,arg[5]); double cut_one = cut_global; if (narg == 7) cut_one = force->numeric(FLERR,arg[6]); 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; gamR[i][j] = gamR_one; gamA[i][j] = gamA_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 PairMIECut::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,instance_me); else if (respa == 1) { irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respainner = 1; irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 3; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respaouter = 1; } else { irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respainner = 1; irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 2; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respamiddle = 1; irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->id = 3; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respaouter = 1; } } else irequest = neighbor->request(this,instance_me); // 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 PairMIECut::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 PairMIECut::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]); gamR[i][j] = mix_distance(gamR[i][i],gamR[j][j]); gamA[i][j] = mix_distance(gamA[i][i],gamA[j][j]); cut[i][j] = mix_distance(cut[i][i],cut[j][j]); } gamA[j][i] = gamA[i][j]; gamR[j][i] = gamR[i][j]; Cmie[i][j] = (gamR[i][j]/(gamR[i][j]-gamA[i][j]) * pow((gamR[i][j]/gamA[i][j]), (gamA[i][j]/(gamR[i][j]-gamA[i][j])))); mie1[i][j] = Cmie[i][j] * gamR[i][j]* epsilon[i][j] * pow(sigma[i][j],gamR[i][j]); mie2[i][j] = Cmie[i][j] * gamA[i][j] * epsilon[i][j] * pow(sigma[i][j],gamA[i][j]); mie3[i][j] = Cmie[i][j] * epsilon[i][j] * pow(sigma[i][j],gamR[i][j]); mie4[i][j] = Cmie[i][j] * epsilon[i][j] * pow(sigma[i][j],gamA[i][j]); if (offset_flag) { double ratio = sigma[i][j] / cut[i][j]; offset[i][j] = Cmie[i][j] * epsilon[i][j] * (pow(ratio,gamR[i][j]) - pow(ratio,gamA[i][j])); } else offset[i][j] = 0.0; mie1[j][i] = mie1[i][j]; mie2[j][i] = mie2[i][j]; mie3[j][i] = mie3[i][j]; mie4[j][i] = mie4[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 siggamA = pow(sigma[i][j],gamA[i][j]); double siggamR = pow(sigma[i][j],gamR[i][j]); double rcgamA = pow(cut[i][j],(gamA[i][j]-3.0)); double rcgamR = pow(cut[i][j],(gamR[i][j]-3.0)); etail_ij = Cmie[i][j]*2.0*MY_PI*all[0]*all[1]*epsilon[i][j]* (siggamR/((gamR[i][j]-3.0)*rcgamR)-siggamA/((gamA[i][j]-3.0)*rcgamA)); ptail_ij = Cmie[i][j]*2.0*MY_PI*all[0]*all[1]*epsilon[i][j]/3.0* ((gamR[i][j]/(gamR[i][j]-3.0))*siggamR/rcgamR- (gamA[i][j]/(gamA[i][j]-3.0))*siggamA/rcgamA); } return cut[i][j]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairMIECut::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(&gamR[i][j],sizeof(double),1,fp); fwrite(&gamA[i][j],sizeof(double),1,fp); fwrite(&cut[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairMIECut::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(&gamR[i][j],sizeof(double),1,fp); fread(&gamA[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(&gamR[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&gamA[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairMIECut::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); fwrite(&tail_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairMIECut::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); fread(&tail_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); MPI_Bcast(&tail_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- */ double PairMIECut::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_mie, double &fforce) { double r2inv,rgamR,rgamA,forcemie,phimie; r2inv = 1.0/rsq; rgamA = pow(r2inv,(gamA[itype][jtype]/2.0)); rgamR = pow(r2inv,(gamR[itype][jtype]/2.0)); forcemie = (mie1[itype][jtype]*rgamR - mie2[itype][jtype]*rgamA); fforce = factor_mie*forcemie*r2inv; phimie = (mie3[itype][jtype]*rgamR - mie4[itype][jtype]*rgamA) - offset[itype][jtype]; return factor_mie*phimie; } /* ---------------------------------------------------------------------- */ void *PairMIECut::extract(const char *str, int &dim) { dim = 2; if (strcmp(str,"epsilon") == 0) return (void *) epsilon; if (strcmp(str,"sigma") == 0) return (void *) sigma; if (strcmp(str,"gamR") == 0) return (void *) gamR; if (strcmp(str,"gamA") == 0) return (void *) gamA; return NULL; } diff --git a/src/pair_morse.cpp b/src/pair_morse.cpp index 4e2d47be5..503a88259 100644 --- a/src/pair_morse.cpp +++ b/src/pair_morse.cpp @@ -1,360 +1,360 @@ /* ---------------------------------------------------------------------- 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 #include #include #include #include "pair_morse.h" #include "atom.h" #include "comm.h" #include "force.h" #include "neigh_list.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ PairMorse::PairMorse(LAMMPS *lmp) : Pair(lmp) { writedata = 1; } /* ---------------------------------------------------------------------- */ PairMorse::~PairMorse() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut); memory->destroy(d0); memory->destroy(alpha); memory->destroy(r0); memory->destroy(morse1); memory->destroy(offset); } } /* ---------------------------------------------------------------------- */ void PairMorse::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,r,dr,dexp,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); dr = r - r0[itype][jtype]; dexp = exp(-alpha[itype][jtype] * dr); fpair = factor_lj * morse1[itype][jtype] * (dexp*dexp - dexp) / r; 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 = d0[itype][jtype] * (dexp*dexp - 2.0*dexp) - 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 PairMorse::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(d0,n+1,n+1,"pair:d0"); memory->create(alpha,n+1,n+1,"pair:alpha"); memory->create(r0,n+1,n+1,"pair:r0"); memory->create(morse1,n+1,n+1,"pair:morse1"); memory->create(offset,n+1,n+1,"pair:offset"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairMorse::settings(int narg, char **arg) { if (narg != 1) error->all(FLERR,"Illegal pair_style command"); cut_global = force->numeric(FLERR,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 PairMorse::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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double d0_one = force->numeric(FLERR,arg[2]); double alpha_one = force->numeric(FLERR,arg[3]); double r0_one = force->numeric(FLERR,arg[4]); double cut_one = cut_global; if (narg == 6) cut_one = force->numeric(FLERR,arg[5]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { d0[i][j] = d0_one; alpha[i][j] = alpha_one; r0[i][j] = r0_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 PairMorse::init_one(int i, int j) { if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set"); morse1[i][j] = 2.0*d0[i][j]*alpha[i][j]; if (offset_flag) { double alpha_dr = -alpha[i][j] * (cut[i][j] - r0[i][j]); offset[i][j] = d0[i][j] * (exp(2.0*alpha_dr) - 2.0*exp(alpha_dr)); } else offset[i][j] = 0.0; d0[j][i] = d0[i][j]; alpha[j][i] = alpha[i][j]; r0[j][i] = r0[i][j]; morse1[j][i] = morse1[i][j]; offset[j][i] = offset[i][j]; return cut[i][j]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairMorse::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(&d0[i][j],sizeof(double),1,fp); fwrite(&alpha[i][j],sizeof(double),1,fp); fwrite(&r0[i][j],sizeof(double),1,fp); fwrite(&cut[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairMorse::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(&d0[i][j],sizeof(double),1,fp); fread(&alpha[i][j],sizeof(double),1,fp); fread(&r0[i][j],sizeof(double),1,fp); fread(&cut[i][j],sizeof(double),1,fp); } MPI_Bcast(&d0[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&alpha[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&r0[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairMorse::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 PairMorse::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); } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void PairMorse::write_data(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) fprintf(fp,"%d %g %g %g\n",i,d0[i][i],alpha[i][i],r0[i][i]); } /* ---------------------------------------------------------------------- proc 0 writes all pairs to data file ------------------------------------------------------------------------- */ void PairMorse::write_data_all(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) fprintf(fp,"%d %d %g %g %g %g\n", i,j,d0[i][j],alpha[i][j],r0[i][j],cut[i][j]); } /* ---------------------------------------------------------------------- */ double PairMorse::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r,dr,dexp,phi; r = sqrt(rsq); dr = r - r0[itype][jtype]; dexp = exp(-alpha[itype][jtype] * dr); fforce = factor_lj * morse1[itype][jtype] * (dexp*dexp - dexp) / r; phi = d0[itype][jtype] * (dexp*dexp - 2.0*dexp) - offset[itype][jtype]; return factor_lj*phi; } /* ---------------------------------------------------------------------- */ void *PairMorse::extract(const char *str, int &dim) { dim = 2; if (strcmp(str,"d0") == 0) return (void *) d0; if (strcmp(str,"r0") == 0) return (void *) r0; if (strcmp(str,"alpha") == 0) return (void *) alpha; return NULL; } diff --git a/src/pair_soft.cpp b/src/pair_soft.cpp index d9b9bb819..8ffd13930 100644 --- a/src/pair_soft.cpp +++ b/src/pair_soft.cpp @@ -1,332 +1,332 @@ /* ---------------------------------------------------------------------- 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 #include #include #include #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) { writedata = 1; } /* ---------------------------------------------------------------------- */ 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(FLERR,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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double prefactor_one = force->numeric(FLERR,arg[2]); double cut_one = cut_global; if (narg == 4) cut_one = force->numeric(FLERR,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); } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void PairSoft::write_data(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) fprintf(fp,"%d %g\n",i,prefactor[i][i]); } /* ---------------------------------------------------------------------- proc 0 writes all pairs to data file ------------------------------------------------------------------------- */ void PairSoft::write_data_all(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) fprintf(fp,"%d %d %g %g\n",i,j,prefactor[i][j],cut[i][j]); } /* ---------------------------------------------------------------------- */ 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(const char *str, int &dim) { dim = 2; if (strcmp(str,"a") == 0) return (void *) prefactor; return NULL; } diff --git a/src/pair_table.cpp b/src/pair_table.cpp index f83e499a2..c4bc3e7dd 100644 --- a/src/pair_table.cpp +++ b/src/pair_table.cpp @@ -1,1058 +1,1058 @@ /* ---------------------------------------------------------------------- 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 #include #include #include #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; enum{NONE,RLINEAR,RSQ,BMP}; #define MAXLINE 1024 #define EPSILONR 1.0e-6 /* ---------------------------------------------------------------------- */ 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; char estr[128]; 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) { sprintf(estr,"Pair distance < table inner cutoff: " "ijtype %d %d dist %g",itype,jtype,sqrt(rsq)); error->one(FLERR,estr); } if (tabstyle == LOOKUP) { itable = static_cast ((rsq - tb->innersq) * tb->invdelta); if (itable >= tlm1) { sprintf(estr,"Pair distance > table outer cutoff: " "ijtype %d %d dist %g",itype,jtype,sqrt(rsq)); error->one(FLERR,estr); } fpair = factor_lj * tb->f[itable]; } else if (tabstyle == LINEAR) { itable = static_cast ((rsq - tb->innersq) * tb->invdelta); if (itable >= tlm1) { sprintf(estr,"Pair distance > table outer cutoff: " "ijtype %d %d dist %g",itype,jtype,sqrt(rsq)); error->one(FLERR,estr); } 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) { sprintf(estr,"Pair distance > table outer cutoff: " "ijtype %d %d dist %g",itype,jtype,sqrt(rsq)); error->one(FLERR,estr); } 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; const int nt = atom->ntypes + 1; memory->create(setflag,nt,nt,"pair:setflag"); memory->create(cutsq,nt,nt,"pair:cutsq"); memory->create(tabindex,nt,nt,"pair:tabindex"); memset(&setflag[0][0],0,nt*nt*sizeof(int)); memset(&cutsq[0][0],0,nt*nt*sizeof(double)); memset(&tabindex[0][0],0,nt*nt*sizeof(int)); } /* ---------------------------------------------------------------------- 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(FLERR,arg[1]); if (tablength < 2) error->all(FLERR,"Illegal number of pair table entries"); // optional keywords // assert the tabulation is compatible with a specific long-range solver int iarg = 2; while (iarg < narg) { if (strcmp(arg[iarg],"ewald") == 0) ewaldflag = 1; else if (strcmp(arg[iarg],"pppm") == 0) pppmflag = 1; else if (strcmp(arg[iarg],"msm") == 0) msmflag = 1; else if (strcmp(arg[iarg],"dispersion") == 0) dispersionflag = 1; else if (strcmp(arg[iarg],"tip4p") == 0) tip4pflag = 1; else error->all(FLERR,"Illegal pair_style command"); iarg++; } // 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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,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(FLERR,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 = force->open_potential(file); 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 char *word = strtok(line," \t\n\r"); if (strcmp(word,keyword) == 0) 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 rfile,rnew; union_int_float_t rsq_lookup; int rerror = 0; int cerror = 0; fgets(line,MAXLINE,fp); for (int i = 0; i < tb->ninput; i++) { if (NULL == fgets(line,MAXLINE,fp)) error->one(FLERR,"Premature end of file in pair table"); if (4 != sscanf(line,"%d %lg %lg %lg", &itmp,&rfile,&tb->efile[i],&tb->ffile[i])) ++cerror; rnew = rfile; if (tb->rflag == RLINEAR) rnew = tb->rlo + (tb->rhi - tb->rlo)*i/(tb->ninput-1); else if (tb->rflag == RSQ) { rnew = tb->rlo*tb->rlo + (tb->rhi*tb->rhi - tb->rlo*tb->rlo)*i/(tb->ninput-1); rnew = sqrt(rnew); } 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; } rnew = sqrtf(rsq_lookup.f); } if (tb->rflag && fabs(rnew-rfile)/rfile > EPSILONR) rerror++; tb->rfile[i] = rnew; } // close file fclose(fp); // warn if force != dE/dr at any point that is not an inflection point // check via secant approximation to dE/dr // skip two end points since do not have surrounding secants // inflection point is where curvature changes sign double r,e,f,rprev,rnext,eprev,enext,fleft,fright; int ferror = 0; for (int i = 1; i < tb->ninput-1; i++) { r = tb->rfile[i]; rprev = tb->rfile[i-1]; rnext = tb->rfile[i+1]; e = tb->efile[i]; eprev = tb->efile[i-1]; enext = tb->efile[i+1]; f = tb->ffile[i]; fleft = - (e-eprev) / (r-rprev); fright = - (enext-e) / (rnext-r); if (f < fleft && f < fright) ferror++; if (f > fleft && f > fright) ferror++; //printf("Values %d: %g %g %g\n",i,r,e,f); //printf(" secant %d %d %g: %g %g %g\n",i,ferror,r,fleft,fright,f); } if (ferror) { char str[128]; sprintf(str,"%d of %d force values in table are inconsistent with -dE/dr.\n" " Should only be flagged at inflection points",ferror,tb->ninput); error->warning(FLERR,str); } // warn if re-computed distance values differ from file values if (rerror) { char str[128]; sprintf(str,"%d of %d distance values in table with relative error\n" " over %g to re-computed values",rerror,tb->ninput,EPSILONR); error->warning(FLERR,str); } // warn if data was read incompletely, e.g. columns were missing if (cerror) { char str[128]; sprintf(str,"%d of %d lines in table were incomplete\n" " or could not be parsed completely",cerror,tb->ninput); error->warning(FLERR,str); } } /* ---------------------------------------------------------------------- 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 FPRIME fplo fphi N is required, other params are optional ------------------------------------------------------------------------- */ void PairTable::param_extract(Table *tb, char *line) { tb->ninput = 0; tb->rflag = NONE; 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 = RLINEAR; 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,"FPRIME") == 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 = dh/dg at inner and at cut // h(r) = e(r) and g(r) = r^2 // dh/dg = (de/dr) / 2r = -f/2r double ep0 = - tb->f[0] / (2.0 * sqrt(tb->innersq)); double epn = - tb->f[tlm1] / (2.0 * tb->cut); 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); fwrite(&ewaldflag,sizeof(int),1,fp); fwrite(&pppmflag,sizeof(int),1,fp); fwrite(&msmflag,sizeof(int),1,fp); fwrite(&dispersionflag,sizeof(int),1,fp); fwrite(&tip4pflag,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); fread(&ewaldflag,sizeof(int),1,fp); fread(&pppmflag,sizeof(int),1,fp); fread(&msmflag,sizeof(int),1,fp); fread(&dispersionflag,sizeof(int),1,fp); fread(&tip4pflag,sizeof(int),1,fp); } MPI_Bcast(&tabstyle,1,MPI_INT,0,world); MPI_Bcast(&tablength,1,MPI_INT,0,world); MPI_Bcast(&ewaldflag,1,MPI_INT,0,world); MPI_Bcast(&pppmflag,1,MPI_INT,0,world); MPI_Bcast(&msmflag,1,MPI_INT,0,world); MPI_Bcast(&dispersionflag,1,MPI_INT,0,world); MPI_Bcast(&tip4pflag,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(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"); dim = 0; return &tables[0].cut; } diff --git a/src/pair_yukawa.cpp b/src/pair_yukawa.cpp index 2cc309d94..a38e2aa88 100644 --- a/src/pair_yukawa.cpp +++ b/src/pair_yukawa.cpp @@ -1,338 +1,338 @@ /* ---------------------------------------------------------------------- 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 #include #include "pair_yukawa.h" #include "atom.h" #include "force.h" #include "comm.h" #include "neigh_list.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ PairYukawa::PairYukawa(LAMMPS *lmp) : Pair(lmp) { writedata = 1; } /* ---------------------------------------------------------------------- */ PairYukawa::~PairYukawa() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(rad); memory->destroy(cut); memory->destroy(a); memory->destroy(offset); } } /* ---------------------------------------------------------------------- */ void PairYukawa::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,r,rinv,screening,forceyukawa,factor; 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 = 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; r = sqrt(rsq); rinv = 1.0/r; screening = exp(-kappa*r); forceyukawa = a[itype][jtype] * screening * (kappa + rinv); fpair = factor*forceyukawa * 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] * screening * rinv - offset[itype][jtype]; evdwl *= factor; } 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 PairYukawa::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(rad,n+1,"pair:rad"); memory->create(cut,n+1,n+1,"pair:cut"); memory->create(a,n+1,n+1,"pair:a"); memory->create(offset,n+1,n+1,"pair:offset"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairYukawa::settings(int narg, char **arg) { if (narg != 2) error->all(FLERR,"Illegal pair_style command"); kappa = force->numeric(FLERR,arg[0]); cut_global = force->numeric(FLERR,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[i][j] = cut_global; } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairYukawa::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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double a_one = force->numeric(FLERR,arg[2]); double cut_one = cut_global; if (narg == 4) cut_one = force->numeric(FLERR,arg[3]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { a[i][j] = a_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 PairYukawa::init_one(int i, int j) { if (setflag[i][j] == 0) { a[i][j] = mix_energy(a[i][i],a[j][j],1.0,1.0); cut[i][j] = mix_distance(cut[i][i],cut[j][j]); } if (offset_flag) { double screening = exp(-kappa * cut[i][j]); offset[i][j] = a[i][j] * screening / cut[i][j]; } else offset[i][j] = 0.0; a[j][i] = a[i][j]; offset[j][i] = offset[i][j]; return cut[i][j]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairYukawa::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(&cut[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairYukawa::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(&cut[i][j],sizeof(double),1,fp); } MPI_Bcast(&a[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairYukawa::write_restart_settings(FILE *fp) { fwrite(&kappa,sizeof(double),1,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 PairYukawa::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&kappa,sizeof(double),1,fp); fread(&cut_global,sizeof(double),1,fp); fread(&offset_flag,sizeof(int),1,fp); fread(&mix_flag,sizeof(int),1,fp); } MPI_Bcast(&kappa,1,MPI_DOUBLE,0,world); 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); } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void PairYukawa::write_data(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) fprintf(fp,"%d %g\n",i,a[i][i]); } /* ---------------------------------------------------------------------- proc 0 writes all pairs to data file ------------------------------------------------------------------------- */ void PairYukawa::write_data_all(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) fprintf(fp,"%d %d %g %g\n",i,j,a[i][j],cut[i][j]); } /* ---------------------------------------------------------------------- */ double PairYukawa::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r2inv,r,rinv,screening,forceyukawa,phi; r2inv = 1.0/rsq; r = sqrt(rsq); rinv = 1.0/r; screening = exp(-kappa*r); forceyukawa = a[itype][jtype] * screening * (kappa + rinv); fforce = factor_lj*forceyukawa * r2inv; phi = a[itype][jtype] * screening * rinv - offset[itype][jtype]; return factor_lj*phi; } diff --git a/src/pair_zbl.cpp b/src/pair_zbl.cpp index 696220098..86c6c64d7 100644 --- a/src/pair_zbl.cpp +++ b/src/pair_zbl.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. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing authors: Stephen Foiles, Aidan Thompson (SNL) ------------------------------------------------------------------------- */ #include #include #include #include #include "pair_zbl.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" // From J.F. Zeigler, J. P. Biersack and U. Littmark, // "The Stopping and Range of Ions in Matter" volume 1, Pergamon, 1985. using namespace LAMMPS_NS; using namespace MathConst; using namespace PairZBLConstants; /* ---------------------------------------------------------------------- */ PairZBL::PairZBL(LAMMPS *lmp) : Pair(lmp) {} /* ---------------------------------------------------------------------- */ PairZBL::~PairZBL() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(z); memory->destroy(d1a); memory->destroy(d2a); memory->destroy(d3a); memory->destroy(d4a); memory->destroy(zze); memory->destroy(sw1); memory->destroy(sw2); memory->destroy(sw3); memory->destroy(sw4); memory->destroy(sw5); } } /* ---------------------------------------------------------------------- */ void PairZBL::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,r,t,fswitch,eswitch; 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; 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]; if (rsq < cut_globalsq) { r = sqrt(rsq); fpair = dzbldr(r, itype, jtype); if (rsq > cut_innersq) { t = r - cut_inner; fswitch = t*t * (sw1[itype][jtype] + sw2[itype][jtype]*t); fpair += fswitch; } fpair *= -1.0/r; 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 = e_zbl(r, itype, jtype); evdwl += sw5[itype][jtype]; if (rsq > cut_innersq) { eswitch = t*t*t * (sw3[itype][jtype] + sw4[itype][jtype]*t); evdwl += eswitch; } } 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 PairZBL::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(z,n+1,"pair:z"); memory->create(d1a,n+1,n+1,"pair:d1a"); memory->create(d2a,n+1,n+1,"pair:d2a"); memory->create(d3a,n+1,n+1,"pair:d3a"); memory->create(d4a,n+1,n+1,"pair:d4a"); memory->create(zze,n+1,n+1,"pair:zze"); memory->create(sw1,n+1,n+1,"pair:sw1"); memory->create(sw2,n+1,n+1,"pair:sw2"); memory->create(sw3,n+1,n+1,"pair:sw3"); memory->create(sw4,n+1,n+1,"pair:sw4"); memory->create(sw5,n+1,n+1,"pair:sw5"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairZBL::settings(int narg, char **arg) { if (narg != 2) error->all(FLERR,"Illegal pair_style command"); cut_inner = force->numeric(FLERR,arg[0]); cut_global = force->numeric(FLERR,arg[1]); if (cut_inner <= 0.0 ) error->all(FLERR,"Illegal pair_style command"); if (cut_inner > cut_global) error->all(FLERR,"Illegal pair_style command"); } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairZBL::coeff(int narg, char **arg) { double z_one, z_two; if (narg != 4) error->all(FLERR,"Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi; - force->bounds(arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); int jlo,jhi; - force->bounds(arg[1],atom->ntypes,jlo,jhi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); z_one = force->numeric(FLERR,arg[2]); z_two = force->numeric(FLERR,arg[3]); // set flag for each i-j pair // set z-parameter only for i-i pairs int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { if (i == j) { if (z_one != z_two) error->all(FLERR,"Incorrect args for pair coefficients"); z[i] = z_one; } setflag[i][j] = 1; set_coeff(i, j, z_one, z_two); count++; } } if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairZBL::init_style() { neighbor->request(this,instance_me); cut_innersq = cut_inner * cut_inner; cut_globalsq = cut_global * cut_global; } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairZBL::init_one(int i, int j) { if (setflag[i][j] == 0) set_coeff(i, j, z[i], z[j]); return cut_global; } /* ---------------------------------------------------------------------- */ double PairZBL::single(int i, int j, int itype, int jtype, double rsq, double dummy1, double dummy2, double &fforce) { double phi,r,t,eswitch,fswitch; r = sqrt(rsq); fforce = dzbldr(r, itype, jtype); if (rsq > cut_innersq) { t = r - cut_inner; fswitch = t*t * (sw1[itype][jtype] + sw2[itype][jtype]*t); fforce += fswitch; } fforce *= -1.0/r; phi = e_zbl(r, itype, jtype); phi += sw5[itype][jtype]; if (rsq > cut_innersq) { eswitch = t*t*t * (sw3[itype][jtype] + sw4[itype][jtype]*t); phi += eswitch; } return phi; } /* ---------------------------------------------------------------------- compute ZBL pair energy ------------------------------------------------------------------------- */ double PairZBL::e_zbl(double r, int i, int j) { double d1aij = d1a[i][j]; double d2aij = d2a[i][j]; double d3aij = d3a[i][j]; double d4aij = d4a[i][j]; double zzeij = zze[i][j]; double rinv = 1.0/r; double sum = c1*exp(-d1aij*r); sum += c2*exp(-d2aij*r); sum += c3*exp(-d3aij*r); sum += c4*exp(-d4aij*r); double result = zzeij*sum*rinv; return result; } /* ---------------------------------------------------------------------- compute ZBL first derivative ------------------------------------------------------------------------- */ double PairZBL::dzbldr(double r, int i, int j) { double d1aij = d1a[i][j]; double d2aij = d2a[i][j]; double d3aij = d3a[i][j]; double d4aij = d4a[i][j]; double zzeij = zze[i][j]; double rinv = 1.0/r; double e1 = exp(-d1aij*r); double e2 = exp(-d2aij*r); double e3 = exp(-d3aij*r); double e4 = exp(-d4aij*r); double sum = c1*e1; sum += c2*e2; sum += c3*e3; sum += c4*e4; double sum_p = -c1*d1aij*e1; sum_p -= c2*d2aij*e2; sum_p -= c3*d3aij*e3; sum_p -= c4*d4aij*e4; double result = zzeij*(sum_p - sum*rinv)*rinv; return result; } /* ---------------------------------------------------------------------- compute ZBL second derivative ------------------------------------------------------------------------- */ double PairZBL::d2zbldr2(double r, int i, int j) { double d1aij = d1a[i][j]; double d2aij = d2a[i][j]; double d3aij = d3a[i][j]; double d4aij = d4a[i][j]; double zzeij = zze[i][j]; double rinv = 1.0/r; double e1 = exp(-d1aij*r); double e2 = exp(-d2aij*r); double e3 = exp(-d3aij*r); double e4 = exp(-d4aij*r); double sum = c1*e1; sum += c2*e2; sum += c3*e3; sum += c4*e4; double sum_p = c1*e1*d1aij; sum_p += c2*e2*d2aij; sum_p += c3*e3*d3aij; sum_p += c4*e4*d4aij; double sum_pp = c1*e1*d1aij*d1aij; sum_pp += c2*e2*d2aij*d2aij; sum_pp += c3*e3*d3aij*d3aij; sum_pp += c4*e4*d4aij*d4aij; double result = zzeij*(sum_pp + 2.0*sum_p*rinv + 2.0*sum*rinv*rinv)*rinv; return result; } /* ---------------------------------------------------------------------- calculate the i,j entries in the various coeff arrays ------------------------------------------------------------------------- */ void PairZBL::set_coeff(int i, int j, double zi, double zj) { double ainv = (pow(zi,pzbl) + pow(zj,pzbl))/(a0*force->angstrom); d1a[i][j] = d1*ainv; d2a[i][j] = d2*ainv; d3a[i][j] = d3*ainv; d4a[i][j] = d4*ainv; zze[i][j] = zi*zj*force->qqr2e*force->qelectron*force->qelectron; d1a[j][i] = d1a[i][j]; d2a[j][i] = d2a[i][j]; d3a[j][i] = d3a[i][j]; d4a[j][i] = d4a[i][j]; zze[j][i] = zze[i][j]; // e = t^3 (sw3 + sw4*t) + sw5 // = A/3*t^3 + B/4*t^4 + C // sw3 = A/3 // sw4 = B/4 // sw5 = C // dedr = t^2 (sw1 + sw2*t) // = A*t^2 + B*t^3 // sw1 = A // sw2 = B // de2dr2 = 2*A*t + 3*B*t^2 // Require that at t = tc: // e = -Fc // dedr = -Fc' // d2edr2 = -Fc'' // Hence: // A = (-3Fc' + tc*Fc'')/tc^2 // B = ( 2Fc' - tc*Fc'')/tc^3 // C = -Fc + tc/2*Fc' - tc^2/12*Fc'' double tc = cut_global - cut_inner; double fc = e_zbl(cut_global, i, j); double fcp = dzbldr(cut_global, i, j); double fcpp = d2zbldr2(cut_global, i, j); double swa = (-3.0*fcp + tc*fcpp)/(tc*tc); double swb = ( 2.0*fcp - tc*fcpp)/(tc*tc*tc); double swc = -fc + (tc/2.0)*fcp - (tc*tc/12.0)*fcpp; sw1[i][j] = swa; sw2[i][j] = swb; sw3[i][j] = swa/3.0; sw4[i][j] = swb/4.0; sw5[i][j] = swc; sw1[j][i] = sw1[i][j]; sw2[j][i] = sw2[i][j]; sw3[j][i] = sw3[i][j]; sw4[j][i] = sw4[i][j]; sw5[j][i] = sw5[i][j]; } diff --git a/src/pair_zero.cpp b/src/pair_zero.cpp index 787ed2993..ab6d713cc 100644 --- a/src/pair_zero.cpp +++ b/src/pair_zero.cpp @@ -1,233 +1,233 @@ /* ---------------------------------------------------------------------- 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: Carsten Svaneborg (SDU) ------------------------------------------------------------------------- */ #include #include #include #include #include "pair_zero.h" #include "atom.h" #include "comm.h" #include "force.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ PairZero::PairZero(LAMMPS *lmp) : Pair(lmp) { coeffflag=1; writedata=1; } /* ---------------------------------------------------------------------- */ PairZero::~PairZero() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut); } } /* ---------------------------------------------------------------------- */ void PairZero::compute(int eflag, int vflag) { if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; if (vflag_fdotr) virial_fdotr_compute(); } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairZero::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"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairZero::settings(int narg, char **arg) { if ((narg != 1) && (narg != 2)) error->all(FLERR,"Illegal pair_style command"); cut_global = force->numeric(FLERR,arg[0]); if (narg == 2) { if (strcmp("nocoeff",arg[1]) == 0) coeffflag=0; else error->all(FLERR,"Illegal pair_style command"); } // 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++) cut[i][j] = cut_global; } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairZero::coeff(int narg, char **arg) { if ((narg < 2) || (coeffflag && 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); + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); double cut_one = cut_global; if (coeffflag && (narg == 3)) cut_one = force->numeric(FLERR,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; 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 PairZero::init_one(int i, int j) { if (setflag[i][j] == 0) { cut[i][j] = mix_distance(cut[i][i],cut[j][j]); } return cut[i][j]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairZero::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 PairZero::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 PairZero::write_restart_settings(FILE *fp) { fwrite(&cut_global,sizeof(double),1,fp); fwrite(&coeffflag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairZero::read_restart_settings(FILE *fp) { int me = comm->me; if (me == 0) { fread(&cut_global,sizeof(double),1,fp); fread(&coeffflag,sizeof(int),1,fp); } MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world); MPI_Bcast(&coeffflag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- proc 0 writes to data file ------------------------------------------------------------------------- */ void PairZero::write_data(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) fprintf(fp,"%d\n",i); } /* ---------------------------------------------------------------------- proc 0 writes all pairs to data file ------------------------------------------------------------------------- */ void PairZero::write_data_all(FILE *fp) { for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) fprintf(fp,"%d %d %g\n",i,j,cut[i][j]); } diff --git a/src/set.cpp b/src/set.cpp index 56fbf42e5..82d0bce12 100644 --- a/src/set.cpp +++ b/src/set.cpp @@ -1,1082 +1,1082 @@ /* ---------------------------------------------------------------------- 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 #include #include #include #include "set.h" #include "atom.h" #include "atom_vec.h" #include "atom_vec_ellipsoid.h" #include "atom_vec_line.h" #include "atom_vec_tri.h" #include "atom_vec_body.h" #include "domain.h" #include "region.h" #include "group.h" #include "comm.h" #include "neighbor.h" #include "force.h" #include "pair.h" #include "input.h" #include "variable.h" #include "random_park.h" #include "math_extra.h" #include "math_const.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace MathConst; enum{ATOM_SELECT,MOL_SELECT,TYPE_SELECT,GROUP_SELECT,REGION_SELECT}; enum{TYPE,TYPE_FRACTION,MOLECULE,X,Y,Z,CHARGE,MASS,SHAPE,LENGTH,TRI, DIPOLE,DIPOLE_RANDOM,QUAT,QUAT_RANDOM,THETA,THETA_RANDOM,ANGMOM,OMEGA, DIAMETER,DENSITY,VOLUME,IMAGE,BOND,ANGLE,DIHEDRAL,IMPROPER, MESO_E,MESO_CV,MESO_RHO,SMD_MASS_DENSITY,SMD_CONTACT_RADIUS,DPDTHETA, INAME,DNAME}; #define BIG INT_MAX /* ---------------------------------------------------------------------- */ void Set::command(int narg, char **arg) { if (domain->box_exist == 0) error->all(FLERR,"Set command before simulation box is defined"); if (atom->natoms == 0) error->all(FLERR,"Set command with no atoms existing"); if (narg < 3) error->all(FLERR,"Illegal set command"); // style and ID info if (strcmp(arg[0],"atom") == 0) style = ATOM_SELECT; else if (strcmp(arg[0],"mol") == 0) style = MOL_SELECT; else if (strcmp(arg[0],"type") == 0) style = TYPE_SELECT; else if (strcmp(arg[0],"group") == 0) style = GROUP_SELECT; else if (strcmp(arg[0],"region") == 0) style = REGION_SELECT; else error->all(FLERR,"Illegal set command"); int n = strlen(arg[1]) + 1; id = new char[n]; strcpy(id,arg[1]); select = NULL; selection(atom->nlocal); // loop over keyword/value pairs // call appropriate routine to reset attributes if (comm->me == 0 && screen) fprintf(screen,"Setting atom values ...\n"); int allcount,origarg; int iarg = 2; while (iarg < narg) { varflag = varflag1 = varflag2 = varflag3 = varflag4 = 0; count = 0; origarg = iarg; if (strcmp(arg[iarg],"type") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal set command"); if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1); else ivalue = force->inumeric(FLERR,arg[iarg+1]); set(TYPE); iarg += 2; } else if (strcmp(arg[iarg],"type/fraction") == 0) { if (iarg+4 > narg) error->all(FLERR,"Illegal set command"); newtype = force->inumeric(FLERR,arg[iarg+1]); fraction = force->numeric(FLERR,arg[iarg+2]); ivalue = force->inumeric(FLERR,arg[iarg+3]); if (newtype <= 0 || newtype > atom->ntypes) error->all(FLERR,"Invalid value in set command"); if (fraction < 0.0 || fraction > 1.0) error->all(FLERR,"Invalid value in set command"); if (ivalue <= 0) error->all(FLERR,"Invalid random number seed in set command"); setrandom(TYPE_FRACTION); iarg += 4; } else if (strcmp(arg[iarg],"mol") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal set command"); if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1); else ivalue = force->inumeric(FLERR,arg[iarg+1]); if (!atom->molecule_flag) error->all(FLERR,"Cannot set this attribute for this atom style"); set(MOLECULE); iarg += 2; } else if (strcmp(arg[iarg],"x") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal set command"); if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1); else dvalue = force->numeric(FLERR,arg[iarg+1]); set(X); iarg += 2; } else if (strcmp(arg[iarg],"y") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal set command"); if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1); else dvalue = force->numeric(FLERR,arg[iarg+1]); set(Y); iarg += 2; } else if (strcmp(arg[iarg],"z") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal set command"); if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1); else dvalue = force->numeric(FLERR,arg[iarg+1]); set(Z); iarg += 2; } else if (strcmp(arg[iarg],"charge") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal set command"); if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1); else dvalue = force->numeric(FLERR,arg[iarg+1]); if (!atom->q_flag) error->all(FLERR,"Cannot set this attribute for this atom style"); set(CHARGE); iarg += 2; } else if (strcmp(arg[iarg],"mass") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal set command"); if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1); else dvalue = force->numeric(FLERR,arg[iarg+1]); if (!atom->rmass_flag) error->all(FLERR,"Cannot set this attribute for this atom style"); set(MASS); iarg += 2; } else if (strcmp(arg[iarg],"shape") == 0) { if (iarg+4 > narg) error->all(FLERR,"Illegal set command"); if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1); else xvalue = force->numeric(FLERR,arg[iarg+1]); if (strstr(arg[iarg+2],"v_") == arg[iarg+2]) varparse(arg[iarg+2],2); else yvalue = force->numeric(FLERR,arg[iarg+2]); if (strstr(arg[iarg+3],"v_") == arg[iarg+3]) varparse(arg[iarg+3],3); else zvalue = force->numeric(FLERR,arg[iarg+3]); if (!atom->ellipsoid_flag) error->all(FLERR,"Cannot set this attribute for this atom style"); set(SHAPE); iarg += 4; } else if (strcmp(arg[iarg],"length") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal set command"); if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1); else dvalue = force->numeric(FLERR,arg[iarg+1]); if (!atom->line_flag) error->all(FLERR,"Cannot set this attribute for this atom style"); set(LENGTH); iarg += 2; } else if (strcmp(arg[iarg],"tri") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal set command"); if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1); else dvalue = force->numeric(FLERR,arg[iarg+1]); if (!atom->tri_flag) error->all(FLERR,"Cannot set this attribute for this atom style"); set(TRI); iarg += 2; } else if (strcmp(arg[iarg],"dipole") == 0) { if (iarg+4 > narg) error->all(FLERR,"Illegal set command"); if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1); else xvalue = force->numeric(FLERR,arg[iarg+1]); if (strstr(arg[iarg+2],"v_") == arg[iarg+2]) varparse(arg[iarg+2],2); else yvalue = force->numeric(FLERR,arg[iarg+2]); if (strstr(arg[iarg+3],"v_") == arg[iarg+3]) varparse(arg[iarg+3],3); else zvalue = force->numeric(FLERR,arg[iarg+3]); if (!atom->mu_flag) error->all(FLERR,"Cannot set this attribute for this atom style"); set(DIPOLE); iarg += 4; } else if (strcmp(arg[iarg],"dipole/random") == 0) { if (iarg+3 > narg) error->all(FLERR,"Illegal set command"); ivalue = force->inumeric(FLERR,arg[iarg+1]); dvalue = force->numeric(FLERR,arg[iarg+2]); if (!atom->mu_flag) error->all(FLERR,"Cannot set this attribute for this atom style"); if (ivalue <= 0) error->all(FLERR,"Invalid random number seed in set command"); if (dvalue <= 0.0) error->all(FLERR,"Invalid dipole length in set command"); setrandom(DIPOLE_RANDOM); iarg += 3; } else if (strcmp(arg[iarg],"quat") == 0) { if (iarg+5 > narg) error->all(FLERR,"Illegal set command"); if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1); else xvalue = force->numeric(FLERR,arg[iarg+1]); if (strstr(arg[iarg+2],"v_") == arg[iarg+2]) varparse(arg[iarg+2],2); else yvalue = force->numeric(FLERR,arg[iarg+2]); if (strstr(arg[iarg+3],"v_") == arg[iarg+3]) varparse(arg[iarg+3],3); else zvalue = force->numeric(FLERR,arg[iarg+3]); if (strstr(arg[iarg+4],"v_") == arg[iarg+4]) varparse(arg[iarg+4],4); else wvalue = force->numeric(FLERR,arg[iarg+4]); if (!atom->ellipsoid_flag && !atom->tri_flag && !atom->body_flag) error->all(FLERR,"Cannot set this attribute for this atom style"); set(QUAT); iarg += 5; } else if (strcmp(arg[iarg],"quat/random") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal set command"); ivalue = force->inumeric(FLERR,arg[iarg+1]); if (!atom->ellipsoid_flag && !atom->tri_flag && !atom->body_flag) error->all(FLERR,"Cannot set this attribute for this atom style"); if (ivalue <= 0) error->all(FLERR,"Invalid random number seed in set command"); setrandom(QUAT_RANDOM); iarg += 2; } else if (strcmp(arg[iarg],"theta") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal set command"); if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1); else { dvalue = force->numeric(FLERR,arg[iarg+1]); dvalue *= MY_PI/180.0; } if (!atom->line_flag) error->all(FLERR,"Cannot set this attribute for this atom style"); set(THETA); iarg += 2; } else if (strcmp(arg[iarg],"theta/random") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal set command"); ivalue = force->inumeric(FLERR,arg[iarg+1]); if (!atom->line_flag) error->all(FLERR,"Cannot set this attribute for this atom style"); if (ivalue <= 0) error->all(FLERR,"Invalid random number seed in set command"); set(THETA_RANDOM); iarg += 2; } else if (strcmp(arg[iarg],"angmom") == 0) { if (iarg+4 > narg) error->all(FLERR,"Illegal set command"); if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1); else xvalue = force->numeric(FLERR,arg[iarg+1]); if (strstr(arg[iarg+2],"v_") == arg[iarg+2]) varparse(arg[iarg+2],2); else yvalue = force->numeric(FLERR,arg[iarg+2]); if (strstr(arg[iarg+3],"v_") == arg[iarg+3]) varparse(arg[iarg+3],3); else zvalue = force->numeric(FLERR,arg[iarg+3]); if (!atom->angmom_flag) error->all(FLERR,"Cannot set this attribute for this atom style"); set(ANGMOM); iarg += 4; } else if (strcmp(arg[iarg],"omega") == 0) { if (iarg+4 > narg) error->all(FLERR,"Illegal set command"); if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1); else xvalue = force->numeric(FLERR,arg[iarg+1]); if (strstr(arg[iarg+2],"v_") == arg[iarg+2]) varparse(arg[iarg+2],2); else yvalue = force->numeric(FLERR,arg[iarg+2]); if (strstr(arg[iarg+3],"v_") == arg[iarg+3]) varparse(arg[iarg+3],3); else zvalue = force->numeric(FLERR,arg[iarg+3]); if (!atom->omega_flag) error->all(FLERR,"Cannot set this attribute for this atom style"); set(OMEGA); iarg += 4; } else if (strcmp(arg[iarg],"diameter") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal set command"); if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1); else dvalue = force->numeric(FLERR,arg[iarg+1]); if (!atom->radius_flag) error->all(FLERR,"Cannot set this attribute for this atom style"); set(DIAMETER); iarg += 2; } else if (strcmp(arg[iarg],"density") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal set command"); if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1); else dvalue = force->numeric(FLERR,arg[iarg+1]); if (!atom->rmass_flag) error->all(FLERR,"Cannot set this attribute for this atom style"); if (dvalue <= 0.0) error->all(FLERR,"Invalid density in set command"); set(DENSITY); iarg += 2; } else if (strcmp(arg[iarg],"volume") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal set command"); if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1); else dvalue = force->numeric(FLERR,arg[iarg+1]); if (!atom->vfrac_flag) error->all(FLERR,"Cannot set this attribute for this atom style"); if (dvalue <= 0.0) error->all(FLERR,"Invalid volume in set command"); set(VOLUME); iarg += 2; } else if (strcmp(arg[iarg],"image") == 0) { if (iarg+4 > narg) error->all(FLERR,"Illegal set command"); ximageflag = yimageflag = zimageflag = 0; if (strcmp(arg[iarg+1],"NULL") != 0) { ximageflag = 1; ximage = force->inumeric(FLERR,arg[iarg+1]); } if (strcmp(arg[iarg+2],"NULL") != 0) { yimageflag = 1; yimage = force->inumeric(FLERR,arg[iarg+2]); } if (strcmp(arg[iarg+3],"NULL") != 0) { zimageflag = 1; zimage = force->inumeric(FLERR,arg[iarg+3]); } if (ximageflag && ximage && !domain->xperiodic) error->all(FLERR, "Cannot set non-zero image flag for non-periodic dimension"); if (yimageflag && yimage && !domain->yperiodic) error->all(FLERR, "Cannot set non-zero image flag for non-periodic dimension"); if (zimageflag && zimage && !domain->zperiodic) error->all(FLERR, "Cannot set non-zero image flag for non-periodic dimension"); set(IMAGE); iarg += 4; } else if (strcmp(arg[iarg],"bond") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal set command"); ivalue = force->inumeric(FLERR,arg[iarg+1]); if (atom->avec->bonds_allow == 0) error->all(FLERR,"Cannot set this attribute for this atom style"); if (ivalue <= 0 || ivalue > atom->nbondtypes) error->all(FLERR,"Invalid value in set command"); topology(BOND); iarg += 2; } else if (strcmp(arg[iarg],"angle") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal set command"); ivalue = force->inumeric(FLERR,arg[iarg+1]); if (atom->avec->angles_allow == 0) error->all(FLERR,"Cannot set this attribute for this atom style"); if (ivalue <= 0 || ivalue > atom->nangletypes) error->all(FLERR,"Invalid value in set command"); topology(ANGLE); iarg += 2; } else if (strcmp(arg[iarg],"dihedral") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal set command"); ivalue = force->inumeric(FLERR,arg[iarg+1]); if (atom->avec->dihedrals_allow == 0) error->all(FLERR,"Cannot set this attribute for this atom style"); if (ivalue <= 0 || ivalue > atom->ndihedraltypes) error->all(FLERR,"Invalid value in set command"); topology(DIHEDRAL); iarg += 2; } else if (strcmp(arg[iarg],"improper") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal set command"); ivalue = force->inumeric(FLERR,arg[iarg+1]); if (atom->avec->impropers_allow == 0) error->all(FLERR,"Cannot set this attribute for this atom style"); if (ivalue <= 0 || ivalue > atom->nimpropertypes) error->all(FLERR,"Invalid value in set command"); topology(IMPROPER); iarg += 2; } else if (strcmp(arg[iarg],"meso/e") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal set command"); if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1); else dvalue = force->numeric(FLERR,arg[iarg+1]); if (!atom->e_flag) error->all(FLERR,"Cannot set meso/e for this atom style"); set(MESO_E); iarg += 2; } else if (strcmp(arg[iarg],"meso/cv") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal set command"); if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1); else dvalue = force->numeric(FLERR,arg[iarg+1]); if (!atom->cv_flag) error->all(FLERR,"Cannot set meso/cv for this atom style"); set(MESO_CV); iarg += 2; } else if (strcmp(arg[iarg],"meso/rho") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal set command"); if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1); else dvalue = force->numeric(FLERR,arg[iarg+1]); if (!atom->rho_flag) error->all(FLERR,"Cannot set meso/rho for this atom style"); set(MESO_RHO); iarg += 2; } else if (strcmp(arg[iarg],"smd/mass/density") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal set command"); if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1); else dvalue = force->numeric(FLERR,arg[iarg+1]); if (!atom->smd_flag) error->all(FLERR,"Cannot set smd/mass/density for this atom style"); set(SMD_MASS_DENSITY); iarg += 2; } else if (strcmp(arg[iarg],"smd/contact/radius") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal set command"); if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1); else dvalue = force->numeric(FLERR,arg[iarg+1]); if (!atom->smd_flag) error->all(FLERR,"Cannot set smd/contact/radius " "for this atom style"); set(SMD_CONTACT_RADIUS); iarg += 2; } else if (strcmp(arg[iarg],"dpd/theta") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal set command"); if (strcmp(arg[iarg+1],"NULL") == 0) dvalue = -1.0; else if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1); else { dvalue = force->numeric(FLERR,arg[iarg+1]); if (dvalue < 0.0) error->all(FLERR,"Illegal set command"); } if (!atom->dpd_flag) error->all(FLERR,"Cannot set dpd/theta for this atom style"); set(DPDTHETA); iarg += 2; } else if (strstr(arg[iarg],"i_") == arg[iarg]) { if (iarg+2 > narg) error->all(FLERR,"Illegal set command"); if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1); else ivalue = force->inumeric(FLERR,arg[iarg+1]); int flag; index_custom = atom->find_custom(&arg[iarg][2],flag); if (index_custom < 0 || flag != 0) error->all(FLERR,"Set command integer vector does not exist"); set(INAME); iarg += 2; } else if (strstr(arg[iarg],"d_") == arg[iarg]) { if (iarg+2 > narg) error->all(FLERR,"Illegal set command"); if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1); else dvalue = force->numeric(FLERR,arg[iarg+1]); int flag; index_custom = atom->find_custom(&arg[iarg][2],flag); if (index_custom < 0 || flag != 1) error->all(FLERR,"Set command floating point vector does not exist"); set(DNAME); iarg += 2; } else error->all(FLERR,"Illegal set command"); // statistics MPI_Allreduce(&count,&allcount,1,MPI_INT,MPI_SUM,world); if (comm->me == 0) { if (screen) fprintf(screen," %d settings made for %s\n", allcount,arg[origarg]); if (logfile) fprintf(logfile," %d settings made for %s\n", allcount,arg[origarg]); } } // free local memory delete [] id; delete [] select; } /* ---------------------------------------------------------------------- select atoms according to ATOM, MOLECULE, TYPE, GROUP, REGION style n = nlocal or nlocal+nghost depending on keyword ------------------------------------------------------------------------- */ void Set::selection(int n) { delete [] select; select = new int[n]; int nlo,nhi; if (style == ATOM_SELECT) { if (atom->tag_enable == 0) error->all(FLERR,"Cannot use set atom with no atom IDs defined"); bigint nlobig,nhibig; - force->boundsbig(id,MAXTAGINT,nlobig,nhibig); + force->boundsbig(FLERR,id,MAXTAGINT,nlobig,nhibig); tagint *tag = atom->tag; for (int i = 0; i < n; i++) if (tag[i] >= nlobig && tag[i] <= nhibig) select[i] = 1; else select[i] = 0; } else if (style == MOL_SELECT) { if (atom->molecule_flag == 0) error->all(FLERR,"Cannot use set mol with no molecule IDs defined"); bigint nlobig,nhibig; - force->boundsbig(id,MAXTAGINT,nlobig,nhibig); + force->boundsbig(FLERR,id,MAXTAGINT,nlobig,nhibig); tagint *molecule = atom->molecule; for (int i = 0; i < n; i++) if (molecule[i] >= nlobig && molecule[i] <= nhibig) select[i] = 1; else select[i] = 0; } else if (style == TYPE_SELECT) { - force->bounds(id,atom->ntypes,nlo,nhi); + force->bounds(FLERR,id,atom->ntypes,nlo,nhi); int *type = atom->type; for (int i = 0; i < n; i++) if (type[i] >= nlo && type[i] <= nhi) select[i] = 1; else select[i] = 0; } else if (style == GROUP_SELECT) { int igroup = group->find(id); if (igroup == -1) error->all(FLERR,"Could not find set group ID"); int groupbit = group->bitmask[igroup]; int *mask = atom->mask; for (int i = 0; i < n; i++) if (mask[i] & groupbit) select[i] = 1; else select[i] = 0; } else if (style == REGION_SELECT) { int iregion = domain->find_region(id); if (iregion == -1) error->all(FLERR,"Set region ID does not exist"); domain->regions[iregion]->prematch(); double **x = atom->x; for (int i = 0; i < n; i++) if (domain->regions[iregion]->match(x[i][0],x[i][1],x[i][2])) select[i] = 1; else select[i] = 0; } } /* ---------------------------------------------------------------------- set owned atom properties directly either scalar or per-atom values from atom-style variable(s) ------------------------------------------------------------------------- */ void Set::set(int keyword) { // evaluate atom-style variable(s) if necessary vec1 = vec2 = vec3 = vec4 = NULL; if (varflag) { int nlocal = atom->nlocal; if (varflag1) { memory->create(vec1,nlocal,"set:vec1"); input->variable->compute_atom(ivar1,0,vec1,1,0); } if (varflag2) { memory->create(vec2,nlocal,"set:vec2"); input->variable->compute_atom(ivar2,0,vec2,1,0); } if (varflag3) { memory->create(vec3,nlocal,"set:vec3"); input->variable->compute_atom(ivar3,0,vec3,1,0); } if (varflag4) { memory->create(vec4,nlocal,"set:vec4"); input->variable->compute_atom(ivar4,0,vec4,1,0); } } // loop over selected atoms AtomVecEllipsoid *avec_ellipsoid = (AtomVecEllipsoid *) atom->style_match("ellipsoid"); AtomVecLine *avec_line = (AtomVecLine *) atom->style_match("line"); AtomVecTri *avec_tri = (AtomVecTri *) atom->style_match("tri"); AtomVecBody *avec_body = (AtomVecBody *) atom->style_match("body"); int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) { if (!select[i]) continue; // overwrite dvalue, ivalue, xyzw value if variables defined // else the input script scalar value remains in place if (varflag) { if (varflag1) { dvalue = xvalue = vec1[i]; ivalue = static_cast (dvalue); } if (varflag2) yvalue = vec2[i]; if (varflag3) zvalue = vec3[i]; if (varflag4) wvalue = vec4[i]; } // set values in per-atom arrays // error check here in case atom-style variables generated bogus value if (keyword == TYPE) { if (ivalue <= 0 || ivalue > atom->ntypes) error->one(FLERR,"Invalid value in set command"); atom->type[i] = ivalue; } else if (keyword == MOLECULE) atom->molecule[i] = ivalue; else if (keyword == X) atom->x[i][0] = dvalue; else if (keyword == Y) atom->x[i][1] = dvalue; else if (keyword == Z) atom->x[i][2] = dvalue; else if (keyword == CHARGE) atom->q[i] = dvalue; else if (keyword == MASS) { if (dvalue <= 0.0) error->one(FLERR,"Invalid mass in set command"); atom->rmass[i] = dvalue; } else if (keyword == DIAMETER) { if (dvalue < 0.0) error->one(FLERR,"Invalid diameter in set command"); atom->radius[i] = 0.5 * dvalue; } else if (keyword == VOLUME) { if (dvalue <= 0.0) error->one(FLERR,"Invalid volume in set command"); atom->vfrac[i] = dvalue; } else if (keyword == MESO_E) atom->e[i] = dvalue; else if (keyword == MESO_CV) atom->cv[i] = dvalue; else if (keyword == MESO_RHO) atom->rho[i] = dvalue; else if (keyword == SMD_MASS_DENSITY) { // set mass from volume and supplied mass density atom->rmass[i] = atom->vfrac[i] * dvalue; } else if (keyword == SMD_CONTACT_RADIUS) atom->contact_radius[i] = dvalue; else if (keyword == DPDTHETA) { if (dvalue >= 0.0) atom->dpdTheta[i] = dvalue; else { double onemass; if (atom->rmass) onemass = atom->rmass[i]; else onemass = atom->mass[atom->type[i]]; double vx = atom->v[i][0]; double vy = atom->v[i][1]; double vz = atom->v[i][2]; double tfactor = force->mvv2e / (domain->dimension * force->boltz); atom->dpdTheta[i] = tfactor * onemass * (vx*vx + vy*vy + vz*vz); } } // set shape of ellipsoidal particle else if (keyword == SHAPE) { if (xvalue < 0.0 || yvalue < 0.0 || zvalue < 0.0) error->one(FLERR,"Invalid shape in set command"); if (xvalue > 0.0 || yvalue > 0.0 || zvalue > 0.0) { if (xvalue == 0.0 || yvalue == 0.0 || zvalue == 0.0) error->one(FLERR,"Invalid shape in set command"); } avec_ellipsoid->set_shape(i,0.5*xvalue,0.5*yvalue,0.5*zvalue); } // set length of line particle else if (keyword == LENGTH) { if (dvalue < 0.0) error->one(FLERR,"Invalid length in set command"); avec_line->set_length(i,dvalue); } // set corners of tri particle else if (keyword == TRI) { if (dvalue < 0.0) error->one(FLERR,"Invalid length in set command"); avec_tri->set_equilateral(i,dvalue); } // set rmass via density // if radius > 0.0, treat as sphere // if shape > 0.0, treat as ellipsoid // if length > 0.0, treat as line // if area > 0.0, treat as tri // else set rmass to density directly else if (keyword == DENSITY) { if (dvalue <= 0.0) error->one(FLERR,"Invalid density in set command"); if (atom->radius_flag && atom->radius[i] > 0.0) atom->rmass[i] = 4.0*MY_PI/3.0 * atom->radius[i]*atom->radius[i]*atom->radius[i] * dvalue; else if (atom->ellipsoid_flag && atom->ellipsoid[i] >= 0) { double *shape = avec_ellipsoid->bonus[atom->ellipsoid[i]].shape; atom->rmass[i] = 4.0*MY_PI/3.0 * shape[0]*shape[1]*shape[2] * dvalue; } else if (atom->line_flag && atom->line[i] >= 0) { double length = avec_line->bonus[atom->line[i]].length; atom->rmass[i] = length * dvalue; } else if (atom->tri_flag && atom->tri[i] >= 0) { double *c1 = avec_tri->bonus[atom->tri[i]].c1; double *c2 = avec_tri->bonus[atom->tri[i]].c2; double *c3 = avec_tri->bonus[atom->tri[i]].c3; double c2mc1[3],c3mc1[3]; MathExtra::sub3(c2,c1,c2mc1); MathExtra::sub3(c3,c1,c3mc1); double norm[3]; MathExtra::cross3(c2mc1,c3mc1,norm); double area = 0.5 * MathExtra::len3(norm); atom->rmass[i] = area * dvalue; } else atom->rmass[i] = dvalue; } // set dipole moment else if (keyword == DIPOLE) { double **mu = atom->mu; mu[i][0] = xvalue; mu[i][1] = yvalue; mu[i][2] = zvalue; mu[i][3] = sqrt(mu[i][0]*mu[i][0] + mu[i][1]*mu[i][1] + mu[i][2]*mu[i][2]); } // set quaternion orientation of ellipsoid or tri or body particle // enforce quat rotation vector in z dir for 2d systems else if (keyword == QUAT) { double *quat; if (avec_ellipsoid && atom->ellipsoid[i] >= 0) quat = avec_ellipsoid->bonus[atom->ellipsoid[i]].quat; else if (avec_tri && atom->tri[i] >= 0) quat = avec_tri->bonus[atom->tri[i]].quat; else if (avec_body && atom->body[i] >= 0) quat = avec_body->bonus[atom->body[i]].quat; else error->one(FLERR,"Cannot set quaternion for atom that has none"); if (domain->dimension == 2 && (xvalue != 0.0 || yvalue != 0.0)) error->one(FLERR,"Cannot set quaternion with xy components " "for 2d system"); double theta2 = MY_PI2 * wvalue/180.0; double sintheta2 = sin(theta2); quat[0] = cos(theta2); quat[1] = xvalue * sintheta2; quat[2] = yvalue * sintheta2; quat[3] = zvalue * sintheta2; MathExtra::qnormalize(quat); } // set theta of line particle else if (keyword == THETA) { if (atom->line[i] < 0) error->one(FLERR,"Cannot set theta for atom that is not a line"); avec_line->bonus[atom->line[i]].theta = dvalue; } // set angmom or omega of particle else if (keyword == ANGMOM) { atom->angmom[i][0] = xvalue; atom->angmom[i][1] = yvalue; atom->angmom[i][2] = zvalue; } else if (keyword == OMEGA) { atom->omega[i][0] = xvalue; atom->omega[i][1] = yvalue; atom->omega[i][2] = zvalue; } // reset any or all of 3 image flags else if (keyword == IMAGE) { int xbox = (atom->image[i] & IMGMASK) - IMGMAX; int ybox = (atom->image[i] >> IMGBITS & IMGMASK) - IMGMAX; int zbox = (atom->image[i] >> IMG2BITS) - IMGMAX; if (ximageflag) xbox = ximage; if (yimageflag) ybox = yimage; if (zimageflag) zbox = zimage; atom->image[i] = ((imageint) (xbox + IMGMAX) & IMGMASK) | (((imageint) (ybox + IMGMAX) & IMGMASK) << IMGBITS) | (((imageint) (zbox + IMGMAX) & IMGMASK) << IMG2BITS); } // set value for custom integer or double vector else if (keyword == INAME) { atom->ivector[index_custom][i] = ivalue; } else if (keyword == DNAME) { atom->dvector[index_custom][i] = dvalue; } count++; } // clear up per-atom memory if allocated memory->destroy(vec1); memory->destroy(vec2); memory->destroy(vec3); memory->destroy(vec4); } /* ---------------------------------------------------------------------- set an owned atom property randomly set seed based on atom coordinates make atom result independent of what proc owns it ------------------------------------------------------------------------- */ void Set::setrandom(int keyword) { int i; AtomVecEllipsoid *avec_ellipsoid = (AtomVecEllipsoid *) atom->style_match("ellipsoid"); AtomVecLine *avec_line = (AtomVecLine *) atom->style_match("line"); AtomVecTri *avec_tri = (AtomVecTri *) atom->style_match("tri"); AtomVecBody *avec_body = (AtomVecBody *) atom->style_match("body"); RanPark *random = new RanPark(lmp,1); double **x = atom->x; int seed = ivalue; // set fraction of atom types to newtype if (keyword == TYPE_FRACTION) { int nlocal = atom->nlocal; for (i = 0; i < nlocal; i++) if (select[i]) { random->reset(seed,x[i]); if (random->uniform() > fraction) continue; atom->type[i] = newtype; count++; } // set dipole moments to random orientations in 3d or 2d // dipole length is determined by dipole type array } else if (keyword == DIPOLE_RANDOM) { double **mu = atom->mu; int nlocal = atom->nlocal; double msq,scale; if (domain->dimension == 3) { for (i = 0; i < nlocal; i++) if (select[i]) { random->reset(seed,x[i]); mu[i][0] = random->uniform() - 0.5; mu[i][1] = random->uniform() - 0.5; mu[i][2] = random->uniform() - 0.5; msq = mu[i][0]*mu[i][0] + mu[i][1]*mu[i][1] + mu[i][2]*mu[i][2]; scale = dvalue/sqrt(msq); mu[i][0] *= scale; mu[i][1] *= scale; mu[i][2] *= scale; mu[i][3] = dvalue; count++; } } else { for (i = 0; i < nlocal; i++) if (select[i]) { random->reset(seed,x[i]); mu[i][0] = random->uniform() - 0.5; mu[i][1] = random->uniform() - 0.5; mu[i][2] = 0.0; msq = mu[i][0]*mu[i][0] + mu[i][1]*mu[i][1]; scale = dvalue/sqrt(msq); mu[i][0] *= scale; mu[i][1] *= scale; mu[i][3] = dvalue; count++; } } // set quaternions to random orientations in 3d and 2d } else if (keyword == QUAT_RANDOM) { int nlocal = atom->nlocal; double *quat; if (domain->dimension == 3) { double s,t1,t2,theta1,theta2; for (i = 0; i < nlocal; i++) if (select[i]) { if (avec_ellipsoid && atom->ellipsoid[i] >= 0) quat = avec_ellipsoid->bonus[atom->ellipsoid[i]].quat; else if (avec_tri && atom->tri[i] >= 0) quat = avec_tri->bonus[atom->tri[i]].quat; else if (avec_body && atom->body[i] >= 0) quat = avec_body->bonus[atom->body[i]].quat; else error->one(FLERR,"Cannot set quaternion for atom that has none"); random->reset(seed,x[i]); s = random->uniform(); t1 = sqrt(1.0-s); t2 = sqrt(s); theta1 = 2.0*MY_PI*random->uniform(); theta2 = 2.0*MY_PI*random->uniform(); quat[0] = cos(theta2)*t2; quat[1] = sin(theta1)*t1; quat[2] = cos(theta1)*t1; quat[3] = sin(theta2)*t2; count++; } } else { double theta2; for (i = 0; i < nlocal; i++) if (select[i]) { if (avec_ellipsoid && atom->ellipsoid[i] >= 0) quat = avec_ellipsoid->bonus[atom->ellipsoid[i]].quat; else if (avec_body && atom->body[i] >= 0) quat = avec_body->bonus[atom->body[i]].quat; else error->one(FLERR,"Cannot set quaternion for atom that has none"); random->reset(seed,x[i]); theta2 = MY_PI*random->uniform(); quat[0] = cos(theta2); quat[1] = 0.0; quat[2] = 0.0; quat[3] = sin(theta2); count++; } } // set theta to random orientation in 2d } else if (keyword == THETA_RANDOM) { int nlocal = atom->nlocal; for (i = 0; i < nlocal; i++) { if (select[i]) { if (atom->line[i] < 0) error->one(FLERR,"Cannot set theta for atom that is not a line"); random->reset(seed,x[i]); avec_line->bonus[atom->line[i]].theta = MY_2PI*random->uniform(); count++; } } } delete random; } /* ---------------------------------------------------------------------- */ void Set::topology(int keyword) { int m,atom1,atom2,atom3,atom4; // error check if (atom->molecular == 2) error->all(FLERR,"Cannot set bond topology types for atom style template"); // border swap to acquire ghost atom info // enforce PBC before in case atoms are outside box // init entire system since comm->exchange is done // comm::init needs neighbor::init needs pair::init needs kspace::init, etc if (comm->me == 0 && screen) fprintf(screen," system init for set ...\n"); lmp->init(); if (domain->triclinic) domain->x2lamda(atom->nlocal); domain->pbc(); domain->reset_box(); comm->setup(); comm->exchange(); comm->borders(); if (domain->triclinic) domain->lamda2x(atom->nlocal+atom->nghost); // select both owned and ghost atoms selection(atom->nlocal + atom->nghost); // for BOND, each of 2 atoms must be in group if (keyword == BOND) { int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) for (m = 0; m < atom->num_bond[i]; m++) { atom1 = atom->map(atom->bond_atom[i][m]); if (atom1 == -1) error->one(FLERR,"Bond atom missing in set command"); if (select[i] && select[atom1]) { atom->bond_type[i][m] = ivalue; count++; } } } // for ANGLE, each of 3 atoms must be in group if (keyword == ANGLE) { int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) for (m = 0; m < atom->num_angle[i]; m++) { atom1 = atom->map(atom->angle_atom1[i][m]); atom2 = atom->map(atom->angle_atom2[i][m]); atom3 = atom->map(atom->angle_atom3[i][m]); if (atom1 == -1 || atom2 == -1 || atom3 == -1) error->one(FLERR,"Angle atom missing in set command"); if (select[atom1] && select[atom2] && select[atom3]) { atom->angle_type[i][m] = ivalue; count++; } } } // for DIHEDRAL, each of 4 atoms must be in group if (keyword == DIHEDRAL) { int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) for (m = 0; m < atom->num_dihedral[i]; m++) { atom1 = atom->map(atom->dihedral_atom1[i][m]); atom2 = atom->map(atom->dihedral_atom2[i][m]); atom3 = atom->map(atom->dihedral_atom3[i][m]); atom4 = atom->map(atom->dihedral_atom4[i][m]); if (atom1 == -1 || atom2 == -1 || atom3 == -1 || atom4 == -1) error->one(FLERR,"Dihedral atom missing in set command"); if (select[atom1] && select[atom2] && select[atom3] && select[atom4]) { atom->dihedral_type[i][m] = ivalue; count++; } } } // for IMPROPER, each of 4 atoms must be in group if (keyword == IMPROPER) { int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) for (m = 0; m < atom->num_improper[i]; m++) { atom1 = atom->map(atom->improper_atom1[i][m]); atom2 = atom->map(atom->improper_atom2[i][m]); atom3 = atom->map(atom->improper_atom3[i][m]); atom4 = atom->map(atom->improper_atom4[i][m]); if (atom1 == -1 || atom2 == -1 || atom3 == -1 || atom4 == -1) error->one(FLERR,"Improper atom missing in set command"); if (select[atom1] && select[atom2] && select[atom3] && select[atom4]) { atom->improper_type[i][m] = ivalue; count++; } } } } /* ---------------------------------------------------------------------- */ void Set::varparse(char *name, int m) { varflag = 1; name = &name[2]; int n = strlen(name) + 1; char *str = new char[n]; strcpy(str,name); int ivar = input->variable->find(str); delete [] str; if (ivar < 0) error->all(FLERR,"Variable name for set command does not exist"); if (!input->variable->atomstyle(ivar)) error->all(FLERR,"Variable for set command is invalid style"); if (m == 1) { varflag1 = 1; ivar1 = ivar; } else if (m == 2) { varflag2 = 1; ivar2 = ivar; } else if (m == 3) { varflag3 = 1; ivar3 = ivar; } else if (m == 4) { varflag4 = 1; ivar4 = ivar; } }