diff --git a/src/ASPHERE/pair_gayberne.cpp b/src/ASPHERE/pair_gayberne.cpp index aa0d0c2a7..62fd2bbea 100755 --- a/src/ASPHERE/pair_gayberne.cpp +++ b/src/ASPHERE/pair_gayberne.cpp @@ -1,907 +1,902 @@ /* ---------------------------------------------------------------------- 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 "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "pair_gayberne.h" #include "math_extra.h" #include "atom.h" #include "atom_vec.h" #include "comm.h" #include "force.h" #include "neighbor.h" #include "neigh_list.h" #include "integrate.h" #include "memory.h" #include "error.h" #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) using namespace LAMMPS_NS; enum{SPHERE_SPHERE,SPHERE_ELLIPSE,ELLIPSE_SPHERE,ELLIPSE_ELLIPSE}; /* ---------------------------------------------------------------------- */ PairGayBerne::PairGayBerne(LAMMPS *lmp) : Pair(lmp) { single_enable = 0; } /* ---------------------------------------------------------------------- free all arrays ------------------------------------------------------------------------- */ PairGayBerne::~PairGayBerne() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(form); memory->destroy(epsilon); memory->destroy(sigma); memory->destroy(shape); 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; evdwl = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; double **x = atom->x; double **f = atom->f; double **quat = atom->quat; double **tor = atom->torque; int *type = atom->type; int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; 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) { MathExtra::quat_to_mat_trans(quat[i],a1); MathExtra::diag_times3(well[itype],a1,temp); MathExtra::transpose_times3(a1,temp,b1); MathExtra::diag_times3(shape[itype],a1,temp); MathExtra::transpose_times3(a1,temp,g1); } jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; - - if (j < nall) factor_lj = 1.0; - else { - factor_lj = special_lj[j/nall]; - j %= nall; - } + 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: MathExtra::quat_to_mat_trans(quat[j],a2); MathExtra::diag_times3(well[jtype],a2,temp); MathExtra::transpose_times3(a2,temp,b2); MathExtra::diag_times3(shape[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: MathExtra::quat_to_mat_trans(quat[j],a2); MathExtra::diag_times3(well[jtype],a2,temp); MathExtra::transpose_times3(a2,temp,b2); MathExtra::diag_times3(shape[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_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(shape,n+1,3,"pair:shape"); 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("Illegal pair_style command"); gamma = force->numeric(arg[0]); upsilon = force->numeric(arg[1])/2.0; mu = force->numeric(arg[2]); cut_global = force->numeric(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("Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(arg[2]); double sigma_one = force->numeric(arg[3]); double eia_one = force->numeric(arg[4]); double eib_one = force->numeric(arg[5]); double eic_one = force->numeric(arg[6]); double eja_one = force->numeric(arg[7]); double ejb_one = force->numeric(arg[8]); double ejc_one = force->numeric(arg[9]); double cut_one = cut_global; if (narg == 11) cut_one = force->numeric(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("Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairGayBerne::init_style() { if (!atom->quat_flag || !atom->torque_flag || !atom->avec->shape_type) error->all("Pair gayberne requires atom attributes quat, torque, shape"); if (atom->radius_flag) error->all("Pair gayberne cannot be used with atom attribute diameter"); int irequest = neighbor->request(this); // per-type shape precalculations for (int i = 1; i <= atom->ntypes; i++) { if (setwell[i]) { double *one = atom->shape[i]; shape[i][0] = one[0]*one[0]; shape[i][1] = one[1]*one[1]; shape[i][2] = one[2]*one[2]; lshape[i] = (one[0]*one[1]+one[2]*one[2])*sqrt(one[0]*one[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("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 (atom->shape[i][0] != atom->shape[i][1] || atom->shape[i][0] != atom->shape[i][2] || atom->shape[i][1] != atom->shape[i][2]) ishape = 1; if (setwell[i] == 1) ishape = 1; int jshape = 0; if (atom->shape[j][0] != atom->shape[j][1] || atom->shape[j][0] != atom->shape[j][2] || atom->shape[j][1] != atom->shape[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]; 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]; 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); } /* ---------------------------------------------------------------------- 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]; MathExtra::mldivide3(g12,r12,kappa,error); // 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); MathExtra::mldivide3(b12,r12,iota,error); // 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::row_times3(kappa,g1,tempv2); MathExtra::cross3(tempv,tempv2,dUr); double dUr2[3]; if (newton_pair || j < nlocal) { MathExtra::row_times3(kappa,g2,tempv2); MathExtra::cross3(tempv,tempv2,dUr2); } // compute d_chi MathExtra::row_times3(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::row_times3(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,shape[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,shape[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]+shape[type[j]][0]; g12[1][1] = g1[1][1]+shape[type[j]][0]; g12[2][2] = g1[2][2]+shape[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]; MathExtra::mldivide3(g12,r12,kappa,error); // 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]; MathExtra::mldivide3(b12,r12,iota,error); // 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::row_times3(kappa,g1,tempv2); MathExtra::cross3(tempv,tempv2,dUr); // compute d_chi MathExtra::row_times3(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,shape[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_resquared.cpp b/src/ASPHERE/pair_resquared.cpp index 4be78b42d..e61f8c1f3 100755 --- a/src/ASPHERE/pair_resquared.cpp +++ b/src/ASPHERE/pair_resquared.cpp @@ -1,990 +1,985 @@ /* ---------------------------------------------------------------------- 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 "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "pair_resquared.h" #include "math_extra.h" #include "atom.h" #include "atom_vec.h" #include "comm.h" #include "force.h" #include "neighbor.h" #include "neigh_list.h" #include "integrate.h" #include "memory.h" #include "error.h" #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) using namespace LAMMPS_NS; enum{SPHERE_SPHERE,SPHERE_ELLIPSE,ELLIPSE_SPHERE,ELLIPSE_ELLIPSE}; /* ---------------------------------------------------------------------- */ PairRESquared::PairRESquared(LAMMPS *lmp) : Pair(lmp), b_alpha(45.0/56.0), cr60(pow(60.0,1.0/3.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(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; - int nall = nlocal + atom->nghost; 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]; - - if (j < nall) factor_lj = 1.0; - else { - factor_lj = special_lj[j/nall]; - j %= nall; - } + 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; 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_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(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("Illegal pair_style command"); cut_global = force->numeric(arg[0]); // reset cutoffs that have been explicitly set if (allocated) { int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i+1; j <= atom->ntypes; j++) if (setflag[i][j]) cut[i][j] = cut_global; } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairRESquared::coeff(int narg, char **arg) { if (narg < 10 || narg > 11) error->all("Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(arg[2]); double sigma_one = force->numeric(arg[3]); double eia_one = force->numeric(arg[4]); double eib_one = force->numeric(arg[5]); double eic_one = force->numeric(arg[6]); double eja_one = force->numeric(arg[7]); double ejb_one = force->numeric(arg[8]); double ejc_one = force->numeric(arg[9]); double cut_one = cut_global; if (narg == 11) cut_one = force->numeric(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("Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairRESquared::init_style() { if (!atom->quat_flag || !atom->torque_flag || !atom->avec->shape_type) error->all("Pair resquared requires atom attributes quat, torque, shape"); if (atom->radius_flag) error->all("Pair resquared cannot be used with atom attribute diameter"); int irequest = neighbor->request(this); // per-type shape precalculations for (int i = 1; i <= atom->ntypes; i++) { if (setwell[i]) { double *one = atom->shape[i]; shape2[i][0] = one[0]*one[0]; shape2[i][1] = one[1]*one[1]; shape2[i][2] = one[2]*one[2]; lshape[i] = one[0]*one[1]*one[2]; } } } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairRESquared::init_one(int i, int j) { double **shape = atom->shape; if (setwell[i] == 0 || setwell[j] == 0) error->all("Pair resquared epsilon a,b,c coeffs are not all set"); int ishape = 0; if (shape[i][0] != 0.0 && shape[i][1] != 0.0 && shape[i][2] != 0.0) ishape = 1; int jshape = 0; if (shape[j][0] != 0.0 && shape[j][1] != 0.0 && shape[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("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]; 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]; 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 MathExtra::quat_to_mat_trans(atom->quat[i],ws.A); MathExtra::transpose_times_diag3(ws.A,well[atom->type[i]],ws.aTe); MathExtra::transpose_times_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; double **shape = atom->shape; // 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); MathExtra::mldivide3(temp,rhat,s,error); sigma12 = 1.0/sqrt(0.5*MathExtra::dot3(s,rhat)); MathExtra::times_column3(wi.A,rhat,z1); MathExtra::times_column3(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); MathExtra::mldivide3(temp,rhat,w,error); 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 = (shape[type[i]][0]+stemp)*(shape[type[i]][1]+stemp)* (shape[type[i]][2]+stemp)*(shape[type[j]][0]+stemp)* (shape[type[j]][1]+stemp)*(shape[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 = (shape[type[i]][0]+stemp)*(shape[type[i]][1]+stemp)* (shape[type[i]][2]+stemp)*(shape[type[j]][0]+stemp)* (shape[type[j]][1]+stemp)*(shape[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/(shape[type[i]][0]*2.0+h12)+ 1.0/(shape[type[i]][1]*2.0+h12)+ 1.0/(shape[type[i]][2]*2.0+h12)+ 1.0/(shape[type[j]][0]*2.0+h12)+ 1.0/(shape[type[j]][1]*2.0+h12)+ 1.0/(shape[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/(shape[type[i]][0]*cr60+h12)+ 1.0/(shape[type[i]][1]*cr60+h12)+ 1.0/(shape[type[i]][2]*cr60+h12)+ 1.0/(shape[type[j]][0]*cr60+h12)+ 1.0/(shape[type[j]][1]*cr60+h12)+ 1.0/(shape[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::times_column3(wi.A,u,u1); MathExtra::times_column3(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::row_times3(fourw,wi.aTe,fwae); for (int i=0; i<3; i++) { MathExtra::times_column3(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::times_column3(wi.lA[i],w,tempv); dchi = -MathExtra::dot3(fwae,tempv); MathExtra::times_column3(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::row_times3(fourw,wj.aTe,fwae); for (int i=0; i<3; i++) { MathExtra::times_column3(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::times_column3(wj.lA[i],w,tempv); dchi = -MathExtra::dot3(fwae,tempv); MathExtra::times_column3(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; double **shape = atom->shape; // 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] = shape[type[i]][0]+half_sigma; scorrect[1] = shape[type[i]][1]+half_sigma; scorrect[2] = shape[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_times_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 MathExtra::mldivide3(gamma,rhat,s,error); 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; MathExtra::mldivide3(temp,rhat,w,error); 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 = (shape[type[i]][0]+stemp)*(shape[type[i]][1]+stemp)* (shape[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 = (shape[type[i]][0]+stemp)*(shape[type[i]][1]+stemp)* (shape[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/(shape[type[i]][0]*2.0+h12)+ 1.0/(shape[type[i]][1]*2.0+h12)+ 1.0/(shape[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/(shape[type[i]][0]*cr60+h12)+ 1.0/(shape[type[i]][1]*cr60+h12)+ 1.0/(shape[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::row_times3(fourw,wi.aTe,fwae); for (int i=0; i<3; i++) { MathExtra::times_column3(wi.lA[i],rhat,p); double tempv[3]; MathExtra::times_column3(wi.lA[i],w,tempv); dchi = -MathExtra::dot3(fwae,tempv); MathExtra::times_column3(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/CLASS2/pair_lj_class2.cpp b/src/CLASS2/pair_lj_class2.cpp index 9b6f41893..894123979 100644 --- a/src/CLASS2/pair_lj_class2.cpp +++ b/src/CLASS2/pair_lj_class2.cpp @@ -1,373 +1,368 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "pair_lj_class2.h" #include "atom.h" #include "comm.h" #include "force.h" #include "neigh_list.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) /* ---------------------------------------------------------------------- */ PairLJClass2::PairLJClass2(LAMMPS *lmp) : Pair(lmp) {} /* ---------------------------------------------------------------------- */ PairLJClass2::~PairLJClass2() { 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; - int nall = nlocal + atom->nghost; 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]; - - if (j < nall) factor_lj = 1.0; - else { - factor_lj = special_lj[j/nall]; - j %= nall; - } + 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_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("Illegal pair_style command"); cut_global = force->numeric(arg[0]); // reset cutoffs that have been explicitly set if (allocated) { int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i+1; j <= atom->ntypes; j++) if (setflag[i][j]) cut[i][j] = cut_global; } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairLJClass2::coeff(int narg, char **arg) { if (narg < 4 || narg > 5) error->all("Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(arg[2]); double sigma_one = force->numeric(arg[3]); double cut_one = cut_global; if (narg == 5) cut_one = force->numeric(arg[4]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { epsilon[i][j] = epsilon_one; sigma[i][j] = sigma_one; cut[i][j] = cut_one; setflag[i][j] = 1; count++; } } if (count == 0) error->all("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 PI = 4.0*atan(1.0); 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*PI*all[0]*all[1]*epsilon[i][j] * sig6 * (sig3 - 3.0*rc3) / (3.0*rc6); ptail_ij = 2.0*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); } /* ---------------------------------------------------------------------- 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); } 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 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 8c8dc7e22..2c91f9c0a 100644 --- a/src/CLASS2/pair_lj_class2_coul_cut.cpp +++ b/src/CLASS2/pair_lj_class2_coul_cut.cpp @@ -1,446 +1,441 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "pair_lj_class2_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; #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) /* ---------------------------------------------------------------------- */ PairLJClass2CoulCut::PairLJClass2CoulCut(LAMMPS *lmp) : Pair(lmp) {} /* ---------------------------------------------------------------------- */ PairLJClass2CoulCut::~PairLJClass2CoulCut() { 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; - int nall = nlocal + atom->nghost; 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]; - - if (j < nall) factor_coul = factor_lj = 1.0; - else { - factor_coul = special_coul[j/nall]; - factor_lj = special_lj[j/nall]; - j %= nall; - } + 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_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("Illegal pair_style command"); cut_lj_global = force->numeric(arg[0]); if (narg == 1) cut_coul_global = cut_lj_global; else cut_coul_global = force->numeric(arg[1]); // reset cutoffs that have been explicitly set if (allocated) { int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i+1; j <= atom->ntypes; j++) if (setflag[i][j]) { cut_lj[i][j] = cut_lj_global; 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("Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(arg[2]); double sigma_one = force->numeric(arg[3]); double cut_lj_one = cut_lj_global; double cut_coul_one = cut_coul_global; if (narg >= 5) cut_coul_one = cut_lj_one = force->numeric(arg[4]); if (narg == 6) cut_coul_one = force->numeric(arg[5]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { epsilon[i][j] = epsilon_one; sigma[i][j] = sigma_one; cut_lj[i][j] = cut_lj_one; cut_coul[i][j] = cut_coul_one; setflag[i][j] = 1; count++; } } if (count == 0) error->all("Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairLJClass2CoulCut::init_style() { if (!atom->q_flag) error->all("Pair style lj/class2/coul/cut requires atom attribute q"); int irequest = neighbor->request(this); } /* ---------------------------------------------------------------------- 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 PI = 4.0*atan(1.0); 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*PI*all[0]*all[1]*epsilon[i][j] * sig6 * (sig3 - 3.0*rc3) / (3.0*rc6); ptail_ij = 2.0*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); } /* ---------------------------------------------------------------------- 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); } 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); } /* ---------------------------------------------------------------------- */ 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 f714d1cc8..dd1bfc08f 100644 --- a/src/CLASS2/pair_lj_class2_coul_long.cpp +++ b/src/CLASS2/pair_lj_class2_coul_long.cpp @@ -1,475 +1,470 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "pair_lj_class2_coul_long.h" #include "atom.h" #include "comm.h" #include "force.h" #include "kspace.h" #include "neighbor.h" #include "neigh_list.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define EWALD_F 1.12837917 #define EWALD_P 0.3275911 #define A1 0.254829592 #define A2 -0.284496736 #define A3 1.421413741 #define A4 -1.453152027 #define A5 1.061405429 /* ---------------------------------------------------------------------- */ PairLJClass2CoulLong::PairLJClass2CoulLong(LAMMPS *lmp) : Pair(lmp) {} /* ---------------------------------------------------------------------- */ PairLJClass2CoulLong::~PairLJClass2CoulLong() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut_lj); memory->destroy(cut_ljsq); memory->destroy(epsilon); memory->destroy(sigma); memory->destroy(lj1); memory->destroy(lj2); memory->destroy(lj3); memory->destroy(lj4); memory->destroy(offset); } } /* ---------------------------------------------------------------------- */ void PairLJClass2CoulLong::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair; double rsq,r,rinv,r2inv,r3inv,r6inv,forcecoul,forcelj; double grij,expm2,prefactor,t,erfc; double factor_coul,factor_lj; int *ilist,*jlist,*numneigh,**firstneigh; evdwl = ecoul = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; double **x = atom->x; double **f = atom->f; double *q = atom->q; int *type = atom->type; int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; 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]; - - if (j < nall) factor_coul = factor_lj = 1.0; - else { - factor_coul = special_coul[j/nall]; - factor_lj = special_lj[j/nall]; - j %= nall; - } + factor_lj = special_lj[sbmask(j)]; + factor_coul = special_coul[sbmask(j)]; + j &= NEIGHMASK; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; jtype = type[j]; if (rsq < cutsq[itype][jtype]) { r2inv = 1.0/rsq; if (rsq < cut_coulsq) { r = sqrt(rsq); grij = g_ewald * r; expm2 = exp(-grij*grij); t = 1.0 / (1.0 + EWALD_P*grij); erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2; prefactor = qqrd2e * qtmp*q[j]/r; forcecoul = prefactor * (erfc + EWALD_F*grij*expm2); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor; } else forcecoul = 0.0; if (rsq < cut_ljsq[itype][jtype]) { rinv = sqrt(r2inv); r3inv = r2inv*rinv; r6inv = r3inv*r3inv; forcelj = r6inv * (lj1[itype][jtype]*r3inv - lj2[itype][jtype]); } else forcelj = 0.0; fpair = (forcecoul + factor_lj*forcelj) * r2inv; f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; if (newton_pair || j < nlocal) { f[j][0] -= delx*fpair; f[j][1] -= dely*fpair; f[j][2] -= delz*fpair; } if (eflag) { if (rsq < cut_coulsq) { ecoul = prefactor*erfc; if (factor_coul < 1.0) ecoul -= (1.0-factor_coul)*prefactor; } else ecoul = 0.0; if (rsq < cut_ljsq[itype][jtype]) { evdwl = r6inv*(lj3[itype][jtype]*r3inv-lj4[itype][jtype]) - offset[itype][jtype]; evdwl *= factor_lj; } else evdwl = 0.0; } if (evflag) ev_tally(i,j,nlocal,newton_pair, evdwl,ecoul,fpair,delx,dely,delz); } } } if (vflag_fdotr) virial_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("Illegal pair_style command"); cut_lj_global = force->numeric(arg[0]); if (narg == 1) cut_coul = cut_lj_global; else cut_coul = force->numeric(arg[1]); // reset cutoffs that have been explicitly set if (allocated) { int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i+1; j <= atom->ntypes; j++) if (setflag[i][j]) cut_lj[i][j] = cut_lj_global; } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairLJClass2CoulLong::coeff(int narg, char **arg) { if (narg < 4 || narg > 6) error->all("Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(arg[2]); double sigma_one = force->numeric(arg[3]); double cut_lj_one = cut_lj_global; if (narg == 5) cut_lj_one = force->numeric(arg[4]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { epsilon[i][j] = epsilon_one; sigma[i][j] = sigma_one; cut_lj[i][j] = cut_lj_one; setflag[i][j] = 1; count++; } } if (count == 0) error->all("Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairLJClass2CoulLong::init_style() { if (!atom->q_flag) error->all("Pair style lj/class2/coul/long requires atom attribute q"); int irequest = neighbor->request(this); cut_coulsq = cut_coul * cut_coul; // insure use of KSpace long-range solver, set g_ewald if (force->kspace == NULL) error->all("Pair style is incompatible with KSpace style"); g_ewald = force->kspace->g_ewald; } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairLJClass2CoulLong::init_one(int i, int j) { // always mix epsilon,sigma via sixthpower rules // mix distance via user-defined rule if (setflag[i][j] == 0) { epsilon[i][j] = 2.0 * sqrt(epsilon[i][i]*epsilon[j][j]) * pow(sigma[i][i],3.0) * pow(sigma[j][j],3.0) / (pow(sigma[i][i],6.0) + pow(sigma[j][j],6.0)); sigma[i][j] = pow((0.5 * (pow(sigma[i][i],6.0) + pow(sigma[j][j],6.0))),1.0/6.0); cut_lj[i][j] = mix_distance(cut_lj[i][i],cut_lj[j][j]); } double cut = MAX(cut_lj[i][j],cut_coul); cut_ljsq[i][j] = cut_lj[i][j] * cut_lj[i][j]; lj1[i][j] = 18.0 * epsilon[i][j] * pow(sigma[i][j],9.0); lj2[i][j] = 18.0 * epsilon[i][j] * pow(sigma[i][j],6.0); lj3[i][j] = 2.0 * epsilon[i][j] * pow(sigma[i][j],9.0); lj4[i][j] = 3.0 * epsilon[i][j] * pow(sigma[i][j],6.0); if (offset_flag) { double ratio = sigma[i][j] / cut_lj[i][j]; offset[i][j] = epsilon[i][j] * (2.0*pow(ratio,9.0) - 3.0*pow(ratio,6.0)); } else offset[i][j] = 0.0; cut_ljsq[j][i] = cut_ljsq[i][j]; lj1[j][i] = lj1[i][j]; lj2[j][i] = lj2[i][j]; lj3[j][i] = lj3[i][j]; lj4[j][i] = lj4[i][j]; offset[j][i] = offset[i][j]; // compute I,J contribution to long-range tail correction // count total # of atoms of type I and J via Allreduce if (tail_flag) { int *type = atom->type; int nlocal = atom->nlocal; double count[2],all[2]; count[0] = count[1] = 0.0; for (int k = 0; k < nlocal; k++) { if (type[k] == i) count[0] += 1.0; if (type[k] == j) count[1] += 1.0; } MPI_Allreduce(count,all,2,MPI_DOUBLE,MPI_SUM,world); double PI = 4.0*atan(1.0); 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*PI*all[0]*all[1]*epsilon[i][j] * sig6 * (sig3 - 3.0*rc3) / (3.0*rc6); ptail_ij = 2.0*PI*all[0]*all[1]*epsilon[i][j] * sig6 * (sig3 - 2.0*rc3) / rc6; } return cut; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJClass2CoulLong::write_restart(FILE *fp) { write_restart_settings(fp); int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { fwrite(&setflag[i][j],sizeof(int),1,fp); if (setflag[i][j]) { fwrite(&epsilon[i][j],sizeof(double),1,fp); fwrite(&sigma[i][j],sizeof(double),1,fp); fwrite(&cut_lj[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJClass2CoulLong::read_restart(FILE *fp) { read_restart_settings(fp); allocate(); int i,j; int me = comm->me; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp); MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world); if (setflag[i][j]) { if (me == 0) { fread(&epsilon[i][j],sizeof(double),1,fp); fread(&sigma[i][j],sizeof(double),1,fp); fread(&cut_lj[i][j],sizeof(double),1,fp); } MPI_Bcast(&epsilon[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_lj[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJClass2CoulLong::write_restart_settings(FILE *fp) { fwrite(&cut_lj_global,sizeof(double),1,fp); fwrite(&cut_coul,sizeof(double),1,fp); fwrite(&offset_flag,sizeof(int),1,fp); fwrite(&mix_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJClass2CoulLong::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&cut_lj_global,sizeof(double),1,fp); fread(&cut_coul,sizeof(double),1,fp); fread(&offset_flag,sizeof(int),1,fp); fread(&mix_flag,sizeof(int),1,fp); } MPI_Bcast(&cut_lj_global,1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_coul,1,MPI_DOUBLE,0,world); MPI_Bcast(&offset_flag,1,MPI_INT,0,world); MPI_Bcast(&mix_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- */ double PairLJClass2CoulLong::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r2inv,r,rinv,r3inv,r6inv,grij,expm2,t,erfc,prefactor; double forcecoul,forcelj,phicoul,philj; r2inv = 1.0/rsq; if (rsq < cut_coulsq) { r = sqrt(rsq); grij = g_ewald * r; expm2 = exp(-grij*grij); t = 1.0 / (1.0 + EWALD_P*grij); erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2; prefactor = force->qqrd2e * atom->q[i]*atom->q[j]/r; forcecoul = prefactor * (erfc + EWALD_F*grij*expm2); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor; } else forcecoul = 0.0; if (rsq < cut_ljsq[itype][jtype]) { rinv = sqrt(r2inv); r3inv = r2inv*rinv; r6inv = r3inv*r3inv; forcelj = r6inv * (lj1[itype][jtype]*r3inv - lj2[itype][jtype]); } else forcelj = 0.0; fforce = (forcecoul + factor_lj*forcelj) * r2inv; double eng = 0.0; if (rsq < cut_coulsq) { phicoul = prefactor*erfc; if (factor_coul < 1.0) phicoul -= (1.0-factor_coul)*prefactor; eng += phicoul; } if (rsq < cut_ljsq[itype][jtype]) { philj = r6inv*(lj3[itype][jtype]*r3inv-lj4[itype][jtype]) - offset[itype][jtype]; eng += factor_lj*philj; } return eng; } /* ---------------------------------------------------------------------- */ void *PairLJClass2CoulLong::extract(char *str, int &dim) { dim = 0; if (strcmp(str,"cut_coul") == 0) return (void *) &cut_coul; return NULL; } diff --git a/src/COLLOID/pair_colloid.cpp b/src/COLLOID/pair_colloid.cpp index 8bd67abfa..e79891307 100644 --- a/src/COLLOID/pair_colloid.cpp +++ b/src/COLLOID/pair_colloid.cpp @@ -1,525 +1,520 @@ /* ---------------------------------------------------------------------- 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 "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "pair_colloid.h" #include "atom.h" #include "comm.h" #include "force.h" #include "neigh_list.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) enum{SMALL_SMALL,SMALL_LARGE,LARGE_LARGE}; /* ---------------------------------------------------------------------- */ PairColloid::PairColloid(LAMMPS *lmp) : Pair(lmp) {} /* ---------------------------------------------------------------------- */ 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; - int nall = nlocal + atom->nghost; 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]; - - if (j < nall) factor_lj = 1.0; - else { - factor_lj = special_lj[j/nall]; - j %= nall; - } + 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("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] = pow(K[3],-7.0); g[1] = pow(K[4],-7.0); g[2] = pow(K[5],-7.0); g[3] = pow(K[6],-7.0); 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("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_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("Illegal pair_style command"); cut_global = force->numeric(arg[0]); // reset cutoffs that have been explicitly set if (allocated) { int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i+1; j <= atom->ntypes; j++) if (setflag[i][j]) cut[i][j] = cut_global; } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairColloid::coeff(int narg, char **arg) { if (narg < 6 || narg > 7) error->all("Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); double a12_one = force->numeric(arg[2]); double sigma_one = force->numeric(arg[3]); double d1_one = force->numeric(arg[4]); double d2_one = force->numeric(arg[5]); double cut_one = cut_global; if (narg == 7) cut_one = force->numeric(arg[6]); if (d1_one < 0.0 || d2_one < 0.0) error->all("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("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("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]; cut[j][i] = cut[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); } /* ---------------------------------------------------------------------- */ 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] = pow(K[3],-7.0); g[1] = pow(K[4],-7.0); g[2] = pow(K[5],-7.0); g[3] = pow(K[6],-7.0); 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 43ec4031e..8d8602922 100644 --- a/src/COLLOID/pair_lubricate.cpp +++ b/src/COLLOID/pair_lubricate.cpp @@ -1,544 +1,546 @@ /* ---------------------------------------------------------------------- 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: Randy Schunk (SNL) ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #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 "update.h" #include "memory.h" #include "random_mars.h" #include "error.h" using namespace LAMMPS_NS; #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) /* ---------------------------------------------------------------------- */ PairLubricate::PairLubricate(LAMMPS *lmp) : Pair(lmp) { single_enable = 0; random = NULL; } /* ---------------------------------------------------------------------- */ PairLubricate::~PairLubricate() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut); memory->destroy(cut_inner); } delete random; } /* ---------------------------------------------------------------------- */ void PairLubricate::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,fpair,fx,fy,fz,tx,ty,tz; double rsq,r,h_sep,radi,tfmag; double vr1,vr2,vr3,vnnr,vn1,vn2,vn3; double vt1,vt2,vt3,w1,w2,w3,v_shear1,v_shear2,v_shear3; double omega_t_1,omega_t_2,omega_t_3; double n_cross_omega_t_1,n_cross_omega_t_2,n_cross_omega_t_3; double wr1,wr2,wr3,wnnr,wn1,wn2,wn3,inv_inertia; double P_dot_wrel_1,P_dot_wrel_2,P_dot_wrel_3; double a_squeeze,a_shear,a_pump,a_twist; int *ilist,*jlist,*numneigh,**firstneigh; double PI = 4.0*atan(1.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; double **omega = atom->omega; double **angmom = atom->angmom; double **torque = atom->torque; double **shape = atom->shape; int *type = atom->type; int nlocal = atom->nlocal; int newton_pair = force->newton_pair; double vxmu2f = force->vxmu2f; double prethermostat = sqrt(2.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; // loop over neighbors of my atoms a_squeeze = a_shear = a_pump = a_twist = 0.0; 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 = shape[itype][0]; 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]) { r = sqrt(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 N.(v1-v2) = nn.(v1-v2) vnnr = vr1*delx + vr2*dely + vr3*delz; vnnr /= r; vn1 = delx*vnnr / r; vn2 = dely*vnnr / r; vn3 = delz*vnnr / r; // tangential component -P.(v1-v2) // P = (I - nn) where n is vector between centers vt1 = vr1 - vn1; vt2 = vr2 - vn2; vt3 = vr3 - vn3; // additive rotational velocity = omega_1 + omega_2 // use omega directly if it exists, else angmom // angular momentum = I*omega = 2/5 * M*R^2 * omega if (omega_flag) { w1 = omega[i][0] + omega[j][0]; w2 = omega[i][1] + omega[j][1]; w3 = omega[i][2] + omega[j][2]; } else { inv_inertia = 1.0 / (0.4*atom->mass[itype]*radi*radi); w1 = inv_inertia * (angmom[i][0] + angmom[j][0]); w2 = inv_inertia * (angmom[i][1] + angmom[j][1]); w3 = inv_inertia * (angmom[i][2] + angmom[j][2]); } // relative velocities n X P . (v1-v2) = n X (I-nn) . (v1-v2) v_shear1 = (dely*vt3 - delz*vt2) / r; v_shear2 = -(delx*vt3 - delz*vt1) / r; v_shear3 = (delx*vt2 - dely*vt1) / r; // relative rotation rate P.(omega1 + omega2) omega_t_1 = w1 - delx*(delx*w1) / rsq; omega_t_2 = w2 - dely*(dely*w2) / rsq; omega_t_3 = w3 - delz*(delz*w3) / rsq; // n X omega_t n_cross_omega_t_1 = (dely*omega_t_3 - delz*omega_t_2) / r; n_cross_omega_t_2 = -(delx*omega_t_3 - delz*omega_t_1) / r; n_cross_omega_t_3 = (delx*omega_t_2 - dely*omega_t_1) / r; // N.(w1-w2) and P.(w1-w2) if (omega_flag) { wr1 = omega[i][0] - omega[j][0]; wr2 = omega[i][1] - omega[j][1]; wr3 = omega[i][2] - omega[j][2]; } else { wr1 = inv_inertia * (angmom[i][0] - angmom[j][0]); wr2 = inv_inertia * (angmom[i][1] - angmom[j][1]); wr3 = inv_inertia * (angmom[i][2] - angmom[j][2]); } wnnr = wr1*delx + wr2*dely + wr3*delz; wn1 = delx*wnnr / rsq; wn2 = dely*wnnr / rsq; wn3 = delz*wnnr / rsq; P_dot_wrel_1 = wr1 - delx*(delx*wr1)/rsq; P_dot_wrel_2 = wr2 - dely*(dely*wr2)/rsq; P_dot_wrel_3 = wr3 - delz*(delz*wr3)/rsq; // compute components of pair-hydro h_sep = r - 2.0*radi; if (flag1) a_squeeze = (3.0*PI*mu*2.0*radi/2.0) * (2.0*radi/4.0/h_sep); if (flag2) a_shear = (PI*mu*2.*radi/2.0) * log(2.0*radi/2.0/h_sep)*(2.0*radi+h_sep)*(2.0*radi+h_sep)/4.0; if (flag3) a_pump = (PI*mu*pow(2.0*radi,4)/8.0) * ((3.0/20.0) * log(2.0*radi/2.0/h_sep) + (63.0/250.0) * (h_sep/2.0/radi) * log(2.0*radi/2.0/h_sep)); if (flag4) a_twist = (PI*mu*pow(2.0*radi,4)/4.0) * (h_sep/2.0/radi) * log(2.0/(2.0*h_sep)); if (h_sep >= cut_inner[itype][jtype]) { fx = -a_squeeze*vn1 - a_shear*(2.0/r)*(2.0/r)*vt1 + (2.0/r)*a_shear*n_cross_omega_t_1; fy = -a_squeeze*vn2 - a_shear*(2.0/r)*(2.0/r)*vt2 + (2.0/r)*a_shear*n_cross_omega_t_2; fz = -a_squeeze*vn3 - a_shear*(2.0/r)*(2.0/r)*vt3 + (2.0/r)*a_shear*n_cross_omega_t_3; fx *= vxmu2f; fy *= vxmu2f; fz *= vxmu2f; // add in thermostat force tfmag = prethermostat*sqrt(a_squeeze)*(random->uniform()-0.5); fx -= tfmag * delx/r; fy -= tfmag * dely/r; fz -= tfmag * delz/r; tx = -(2.0/r)*a_shear*v_shear1 - a_shear*omega_t_1 - a_pump*P_dot_wrel_1 - a_twist*wn1; ty = -(2.0/r)*a_shear*v_shear2 - a_shear*omega_t_2 - a_pump*P_dot_wrel_2 - a_twist*wn2; tz = -(2.0/r)*a_shear*v_shear3 - a_shear*omega_t_3 - a_pump*P_dot_wrel_3 - a_twist*wn3; torque[i][0] += vxmu2f * tx; torque[i][1] += vxmu2f * ty; torque[i][2] += vxmu2f * tz; } else { a_squeeze = (3.0*PI*mu*2.0*radi/2.0) * (2.0*radi/4.0/cut_inner[itype][jtype]); fpair = -a_squeeze*vnnr; fpair *= vxmu2f; // add in thermostat force fpair -= prethermostat*sqrt(a_squeeze)*(random->uniform()-0.5); fx = fpair * delx/r; fy = fpair * dely/r; fz = fpair * delz/r; } 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; if (h_sep >= cut_inner[itype][jtype]) { tx = -(2.0/r)*a_shear*v_shear1 - a_shear*omega_t_1 + a_pump*P_dot_wrel_1 + a_twist*wn1; ty = -(2.0/r)*a_shear*v_shear2 - a_shear*omega_t_2 + a_pump*P_dot_wrel_2 + a_twist*wn2; tz = -(2.0/r)*a_shear*v_shear3 - a_shear*omega_t_3 + a_pump*P_dot_wrel_3 + a_twist*wn3; 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); } } } if (vflag_fdotr) virial_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 != 9) error->all("Illegal pair_style command"); mu = force->numeric(arg[0]); flag1 = force->inumeric(arg[1]); flag2 = force->inumeric(arg[2]); flag3 = force->inumeric(arg[3]); flag4 = force->inumeric(arg[4]); cut_inner_global = force->numeric(arg[5]); cut_global = force->numeric(arg[6]); t_target = force->numeric(arg[7]); seed = force->inumeric(arg[8]); // initialize Marsaglia RNG with processor-unique seed if (seed <= 0) error->all("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_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("Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); double cut_inner_one = cut_inner_global; double cut_one = cut_global; if (narg == 4) { cut_inner_one = force->numeric(arg[2]); cut_one = force->numeric(arg[3]); } int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { cut_inner[i][j] = cut_inner_one; cut[i][j] = cut_one; setflag[i][j] = 1; count++; } } if (count == 0) error->all("Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairLubricate::init_style() { if (comm->ghost_velocity == 0) error->all("Pair lubricate requires ghost atoms store velocity"); if (!atom->torque_flag || !atom->avec->shape_type) error->all("Pair lubricate requires atom attributes torque and shape"); if (atom->radius_flag || atom->rmass_flag) error->all("Pair lubricate cannot be used with atom attributes " "diameter or rmass"); if (atom->omega_flag) omega_flag = 1; else if (atom->angmom_flag) omega_flag = 0; else error->all("Pair lubricate requires atom attribute omega or angmom"); // insure all particle shapes are finite-size, spherical, and monodisperse // for pair hybrid, should limit test to types using the pair style double radi = atom->shape[1][0]; if (radi == 0.0) error->all("Pair lubricate requires extended particles"); for (int i = 1; i <= atom->ntypes; i++) if (atom->shape[i][0] != radi || atom->shape[i][0] != radi || atom->shape[i][0] != radi) error->all("Pair lubricate requires spherical, mono-disperse particles"); int irequest = neighbor->request(this); } /* ---------------------------------------------------------------------- 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(&flag1,sizeof(int),1,fp); fwrite(&flag2,sizeof(int),1,fp); fwrite(&flag3,sizeof(int),1,fp); fwrite(&flag4,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); } /* ---------------------------------------------------------------------- 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(&flag1,sizeof(int),1,fp); fread(&flag2,sizeof(int),1,fp); fread(&flag3,sizeof(int),1,fp); fread(&flag4,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); } MPI_Bcast(&mu,1,MPI_DOUBLE,0,world); MPI_Bcast(&flag1,1,MPI_INT,0,world); MPI_Bcast(&flag2,1,MPI_INT,0,world); MPI_Bcast(&flag3,1,MPI_INT,0,world); MPI_Bcast(&flag4,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); // additional setup based on restart parameters delete random; random = new RanMars(lmp,seed + comm->me); } /* ---------------------------------------------------------------------- */ void *PairLubricate::extract(char *str, int &dim) { dim = 0; if (strcmp(str,"mu") == 0) return (void *) μ return NULL; } diff --git a/src/COLLOID/pair_yukawa_colloid.cpp b/src/COLLOID/pair_yukawa_colloid.cpp index 790603df9..69c974a58 100644 --- a/src/COLLOID/pair_yukawa_colloid.cpp +++ b/src/COLLOID/pair_yukawa_colloid.cpp @@ -1,193 +1,188 @@ /* ---------------------------------------------------------------------- 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) ------------------------------------------------------------------------- */ #include "math.h" #include "stdlib.h" #include "pair_yukawa_colloid.h" #include "atom.h" #include "atom_vec.h" #include "force.h" #include "comm.h" #include "neighbor.h" #include "neigh_list.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ PairYukawaColloid::PairYukawaColloid(LAMMPS *lmp) : PairYukawa(lmp) {} /* ---------------------------------------------------------------------- */ void PairYukawaColloid::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,ecoul,fpair,radi,radj; double rsq,r2inv,r,rinv,screening,forceyukawa,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 **shape = atom->shape; int *type = atom->type; int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; double *special_coul = force->special_coul; 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]; radi = shape[itype][0]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; - - if (j < nall) factor_coul = 1.0; - else { - factor_coul = special_coul[j/nall]; - j %= nall; - } + 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]; radj = shape[jtype][0]; if (rsq < cutsq[itype][jtype]) { r2inv = 1.0/rsq; r = sqrt(rsq); rinv = 1.0/r; screening = exp(-kappa*(r-(radi+radj))); forceyukawa = a[itype][jtype] * screening; fpair = factor_coul*forceyukawa * 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) { ecoul = a[itype][jtype]/kappa * screening - 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_compute(); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairYukawaColloid::init_style() { if (!atom->avec->shape_type) error->all("Pair yukawa/colloid requires atom attribute shape"); if (atom->radius_flag) error->all("Pair yukawa/colloid cannot be used with " "atom attribute diameter"); // insure all particle shapes are spherical // can be point particles or polydisperse for (int i = 1; i <= atom->ntypes; i++) if ((atom->shape[i][0] != atom->shape[i][1]) || (atom->shape[i][0] != atom->shape[i][2]) || (atom->shape[i][1] != atom->shape[i][2])) error->all("Pair yukawa/colloid requires spherical particles"); int irequest = neighbor->request(this); } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairYukawaColloid::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 radi = atom->shape[i][0]; double radj = atom->shape[j][0]; double screening = exp(-kappa * (cut[i][j] - (radi+radj))); offset[i][j] = a[i][j]/kappa * screening; } else offset[i][j] = 0.0; a[j][i] = a[i][j]; offset[j][i] = offset[i][j]; return cut[i][j]; } /* ---------------------------------------------------------------------- */ double PairYukawaColloid::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,radi,radj; int *type = atom->type; radi = atom->shape[itype][0]; radj = atom->shape[jtype][0]; r2inv = 1.0/rsq; r = sqrt(rsq); rinv = 1.0/r; screening = exp(-kappa*(r-(radi+radj))); forceyukawa = a[itype][jtype] * screening; fforce = factor_coul*forceyukawa * rinv; phi = a[itype][jtype]/kappa * screening - offset[itype][jtype]; return factor_coul*phi; } diff --git a/src/DIPOLE/pair_dipole_cut.cpp b/src/DIPOLE/pair_dipole_cut.cpp index 20fc4076d..a2e7c17bd 100644 --- a/src/DIPOLE/pair_dipole_cut.cpp +++ b/src/DIPOLE/pair_dipole_cut.cpp @@ -1,492 +1,487 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "math.h" #include "stdlib.h" #include "pair_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" using namespace LAMMPS_NS; #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) /* ---------------------------------------------------------------------- */ PairDipoleCut::PairDipoleCut(LAMMPS *lmp) : Pair(lmp) { single_enable = 0; } /* ---------------------------------------------------------------------- */ PairDipoleCut::~PairDipoleCut() { 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 PairDipoleCut::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; double *dipole = atom->dipole; int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; 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]; - - if (j < nall) factor_coul = factor_lj = 1.0; - else { - factor_coul = special_coul[j/nall]; - factor_lj = special_lj[j/nall]; - j = j % nall; - } + 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 (dipole[itype] > 0.0 && dipole[jtype] > 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 (dipole[itype] > 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 (dipole[jtype] > 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 (dipole[itype] > 0.0 && dipole[jtype] > 0.0) ecoul += r3inv*pdotp - 3.0*r5inv*pidotr*pjdotr; if (dipole[itype] > 0.0 && q[j] != 0.0) ecoul += -q[j]*r3inv*pidotr; if (dipole[jtype] > 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_compute(); } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairDipoleCut::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 PairDipoleCut::settings(int narg, char **arg) { if (narg < 1 || narg > 2) error->all("Incorrect args in pair_style command"); cut_lj_global = force->numeric(arg[0]); if (narg == 1) cut_coul_global = cut_lj_global; else cut_coul_global = force->numeric(arg[1]); // reset cutoffs that have been explicitly set if (allocated) { int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i+1; j <= atom->ntypes; j++) if (setflag[i][j]) { cut_lj[i][j] = cut_lj_global; cut_coul[i][j] = cut_coul_global; } } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairDipoleCut::coeff(int narg, char **arg) { if (narg < 4 || narg > 6) error->all("Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(arg[2]); double sigma_one = force->numeric(arg[3]); double cut_lj_one = cut_lj_global; double cut_coul_one = cut_coul_global; if (narg >= 5) cut_coul_one = cut_lj_one = force->numeric(arg[4]); if (narg == 6) cut_coul_one = force->numeric(arg[5]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { epsilon[i][j] = epsilon_one; sigma[i][j] = sigma_one; cut_lj[i][j] = cut_lj_one; cut_coul[i][j] = cut_coul_one; setflag[i][j] = 1; count++; } } if (count == 0) error->all("Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairDipoleCut::init_style() { if (!atom->q_flag || !atom->mu_flag || !atom->torque_flag || atom->dipole == NULL) error->all("Pair dipole/cut requires atom attributes " "q, mu, torque, dipole"); int irequest = neighbor->request(this); } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairDipoleCut::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 PairDipoleCut::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 PairDipoleCut::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 PairDipoleCut::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 PairDipoleCut::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/GPU/pair_gayberne_gpu.cpp b/src/GPU/pair_gayberne_gpu.cpp index eea45ad97..c8fc0cf35 100644 --- a/src/GPU/pair_gayberne_gpu.cpp +++ b/src/GPU/pair_gayberne_gpu.cpp @@ -1,464 +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 author: Mike Brown (SNL) ------------------------------------------------------------------------- */ #include "lmptype.h" #include "math.h" #include "stdio.h" #include "stdlib.h" #include "pair_gayberne_gpu.h" #include "math_extra.h" #include "atom.h" #include "atom_vec.h" #include "comm.h" #include "force.h" #include "neighbor.h" #include "neigh_list.h" #include "integrate.h" #include "memory.h" #include "error.h" #include "neigh_request.h" #include "universe.h" #include "domain.h" #include "update.h" #include "string.h" #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) // External functions from cuda library for atom decomposition bool gb_gpu_init(const int ntypes, const double gamma, const double upsilon, const double mu, double **shape, double **well, double **cutsq, double **sigma, double **epsilon, double *host_lshape, int **form, double **host_lj1, double **host_lj2, double **host_lj3, double **host_lj4, double **offset, double *special_lj, const int nlocal, const int nall, const int max_nbors, const double cell_size, int &gpu_mode, FILE *screen); void gb_gpu_clear(); int * gb_gpu_compute_n(const int timestep, const int ago, const int inum, const int nall, double **host_x, int *host_type, double *boxlo, double *boxhi, const bool eflag, const bool vflag, const bool eatom, const bool vatom, int &host_start, const double cpu_time, bool &success, double **host_quat); int * gb_gpu_compute(const int timestep, const int ago, const int inum, const int nall, double **host_x, int *host_type, int *ilist, int *numj, int **firstneigh, const bool eflag, const bool vflag, const bool eatom, const bool vatom, int &host_start, const double cpu_time, bool &success, double **host_quat); double gb_gpu_bytes(); using namespace LAMMPS_NS; enum{SPHERE_SPHERE,SPHERE_ELLIPSE,ELLIPSE_SPHERE,ELLIPSE_ELLIPSE}; /* ---------------------------------------------------------------------- */ PairGayBerneGPU::PairGayBerneGPU(LAMMPS *lmp) : PairGayBerne(lmp), gpu_mode(GPU_PAIR) { } /* ---------------------------------------------------------------------- free all arrays ------------------------------------------------------------------------- */ PairGayBerneGPU::~PairGayBerneGPU() { gb_gpu_clear(); cpu_time = 0.0; } /* ---------------------------------------------------------------------- */ void PairGayBerneGPU::compute(int eflag, int vflag) { int ntimestep = static_cast(update->ntimestep % MAXSMALLINT); if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; int nall = atom->nlocal + atom->nghost; int inum, host_start; bool success = true; if (gpu_mode == GPU_NEIGH) { inum = atom->nlocal; gpulist = gb_gpu_compute_n(ntimestep, neighbor->ago, inum, nall, atom->x, atom->type, domain->sublo, domain->subhi, eflag, vflag, eflag_atom, vflag_atom, host_start, cpu_time, success, atom->quat); } else { inum = list->inum; olist = gb_gpu_compute(ntimestep, neighbor->ago, inum, nall, atom->x, atom->type, list->ilist, list->numneigh, list->firstneigh, eflag, vflag, eflag_atom, vflag_atom, host_start, cpu_time, success, atom->quat); } if (!success) error->one("Out of memory on GPGPU"); if (host_start < inum) { cpu_time = MPI_Wtime(); if (gpu_mode == GPU_NEIGH) cpu_compute(gpulist,host_start,eflag,vflag); else cpu_compute(host_start,eflag,vflag); cpu_time = MPI_Wtime() - cpu_time; } } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairGayBerneGPU::init_style() { if (force->pair_match("gpu",0) == NULL) error->all("Cannot use pair hybrid with multiple GPU pair styles"); if (!atom->quat_flag || !atom->torque_flag || !atom->avec->shape_type) error->all("Pair gayberne requires atom attributes quat, torque, shape"); if (atom->radius_flag) error->all("Pair gayberne cannot be used with atom attribute diameter"); // per-type shape precalculations for (int i = 1; i <= atom->ntypes; i++) { if (setwell[i]) { double *one = atom->shape[i]; shape[i][0] = one[0]*one[0]; shape[i][1] = one[1]*one[1]; shape[i][2] = one[2]*one[2]; lshape[i] = (one[0]*one[1]+one[2]*one[2])*sqrt(one[0]*one[1]); } } // Repeat cutsq calculation because done after call to init_style double maxcut = -1.0; double cut; for (int i = 1; i <= atom->ntypes; i++) { for (int j = i; j <= atom->ntypes; j++) { if (setflag[i][j] != 0 || (setflag[i][i] != 0 && setflag[j][j] != 0)) { cut = init_one(i,j); cut *= cut; if (cut > maxcut) maxcut = cut; cutsq[i][j] = cutsq[j][i] = cut; } else cutsq[i][j] = cutsq[j][i] = 0.0; } } double cell_size = sqrt(maxcut) + neighbor->skin; bool init_ok = gb_gpu_init(atom->ntypes+1, gamma, upsilon, mu, shape, well, cutsq, sigma, epsilon, lshape, form, lj1, lj2, lj3, lj4, offset, force->special_lj, atom->nlocal, atom->nlocal+atom->nghost, 300, cell_size, gpu_mode, screen); if (!init_ok) error->one("Insufficient memory on accelerator (or no fix gpu)."); if (force->newton_pair) error->all("Cannot use newton pair with GPU Gay-Berne pair style"); if (gpu_mode != GPU_NEIGH) { int irequest = neighbor->request(this); neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->full = 1; } } /* ---------------------------------------------------------------------- */ double PairGayBerneGPU::memory_usage() { double bytes = Pair::memory_usage(); return bytes + gb_gpu_bytes(); } /* ---------------------------------------------------------------------- */ void PairGayBerneGPU::cpu_compute(int start, 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 **x = atom->x; double **f = atom->f; double **quat = atom->quat; double **tor = atom->torque; int *type = atom->type; int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; double *special_lj = force->special_lj; inum = list->inum; ilist = olist; numneigh = list->numneigh; firstneigh = list->firstneigh; // loop over neighbors of my atoms for (ii = start; ii < inum; ii++) { i = ilist[ii]; itype = type[i]; if (form[itype][itype] == ELLIPSE_ELLIPSE) { MathExtra::quat_to_mat_trans(quat[i],a1); MathExtra::diag_times3(well[itype],a1,temp); MathExtra::transpose_times3(a1,temp,b1); MathExtra::diag_times3(shape[itype],a1,temp); MathExtra::transpose_times3(a1,temp,g1); } jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; - - if (j < nall) factor_lj = 1.0; - else { - factor_lj = special_lj[j/nall]; - j %= nall; - } + 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: MathExtra::quat_to_mat_trans(quat[j],a2); MathExtra::diag_times3(well[jtype],a2,temp); MathExtra::transpose_times3(a2,temp,b2); MathExtra::diag_times3(shape[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: MathExtra::quat_to_mat_trans(quat[j],a2); MathExtra::diag_times3(well[jtype],a2,temp); MathExtra::transpose_times3(a2,temp,b2); MathExtra::diag_times3(shape[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 (eflag) evdwl = factor_lj*one_eng; if (evflag) ev_tally_xyz_full(i,evdwl,0.0,fforce[0],fforce[1],fforce[2], -r12[0],-r12[1],-r12[2]); } } } } /* ---------------------------------------------------------------------- */ void PairGayBerneGPU::cpu_compute(int *nbors, int start, int eflag, int vflag) { int i,j,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]; double **x = atom->x; double **f = atom->f; double **quat = atom->quat; double **tor = atom->torque; int *type = atom->type; int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; int stride = nlocal-start; double *special_lj = force->special_lj; // loop over neighbors of my atoms for (i = start; i < nlocal; i++) { itype = type[i]; if (form[itype][itype] == ELLIPSE_ELLIPSE) { MathExtra::quat_to_mat_trans(quat[i],a1); MathExtra::diag_times3(well[itype],a1,temp); MathExtra::transpose_times3(a1,temp,b1); MathExtra::diag_times3(shape[itype],a1,temp); MathExtra::transpose_times3(a1,temp,g1); } int *nbor = nbors+i-start; int jnum =* nbor; nbor += stride; int *nbor_end = nbor + stride * jnum; for ( ; nbor < nbor_end; nbor += stride) { j = *nbor; - - if (j < nall) factor_lj = 1.0; - else { - factor_lj = special_lj[j/nall]; - j %= nall; - } + 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: MathExtra::quat_to_mat_trans(quat[j],a2); MathExtra::diag_times3(well[jtype],a2,temp); MathExtra::transpose_times3(a2,temp,b2); MathExtra::diag_times3(shape[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: MathExtra::quat_to_mat_trans(quat[j],a2); MathExtra::diag_times3(well[jtype],a2,temp); MathExtra::transpose_times3(a2,temp,b2); MathExtra::diag_times3(shape[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 (eflag) evdwl = factor_lj*one_eng; if (j (b) ? (a) : (b)) // External functions from cuda library for atom decomposition bool lj96_gpu_init(const int ntypes, double **cutsq, double **host_lj1, double **host_lj2, double **host_lj3, double **host_lj4, double **offset, double *special_lj, const int nlocal, const int nall, const int max_nbors, const int maxspecial, const double cell_size, int &gpu_mode, FILE *screen); void lj96_gpu_clear(); int * lj96_gpu_compute_n(const int timestep, const int ago, const int inum, const int nall, double **host_x, int *host_type, double *boxlo, double *boxhi, int *tag, int **nspecial, int **special, const bool eflag, const bool vflag, const bool eatom, const bool vatom, int &host_start, const double cpu_time, bool &success); void lj96_gpu_compute(const int timestep, const int ago, const int inum, const int nall, double **host_x, int *host_type, int *ilist, int *numj, int **firstneigh, const bool eflag, const bool vflag, const bool eatom, const bool vatom, int &host_start, const double cpu_time, bool &success); double lj96_gpu_bytes(); using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ PairLJ96CutGPU::PairLJ96CutGPU(LAMMPS *lmp) : PairLJ96Cut(lmp), gpu_mode(GPU_PAIR) { respa_enable = 0; cpu_time = 0.0; } /* ---------------------------------------------------------------------- free all arrays ------------------------------------------------------------------------- */ PairLJ96CutGPU::~PairLJ96CutGPU() { lj96_gpu_clear(); } /* ---------------------------------------------------------------------- */ void PairLJ96CutGPU::compute(int eflag, int vflag) { int ntimestep = static_cast(update->ntimestep % MAXSMALLINT); if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; int nall = atom->nlocal + atom->nghost; int inum, host_start; bool success = true; if (gpu_mode == GPU_NEIGH) { inum = atom->nlocal; gpulist = lj96_gpu_compute_n(ntimestep, neighbor->ago, inum, nall, atom->x, atom->type, domain->sublo, domain->subhi, atom->tag, atom->nspecial, atom->special, eflag, vflag, eflag_atom, vflag_atom, host_start, cpu_time, success); } else { inum = list->inum; lj96_gpu_compute(ntimestep, neighbor->ago, inum, nall, atom->x, atom->type, list->ilist, list->numneigh, list->firstneigh, eflag, vflag, eflag_atom, vflag_atom, host_start, cpu_time, success); } if (!success) error->one("Out of memory on GPGPU"); if (host_startpair_match("gpu",0) == NULL) error->all("Cannot use pair hybrid with multiple GPU pair styles"); // Repeat cutsq calculation because done after call to init_style double maxcut = -1.0; double cut; for (int i = 1; i <= atom->ntypes; i++) { for (int j = i; j <= atom->ntypes; j++) { if (setflag[i][j] != 0 || (setflag[i][i] != 0 && setflag[j][j] != 0)) { cut = init_one(i,j); cut *= cut; if (cut > maxcut) maxcut = cut; cutsq[i][j] = cutsq[j][i] = cut; } else cutsq[i][j] = cutsq[j][i] = 0.0; } } double cell_size = sqrt(maxcut) + neighbor->skin; int maxspecial=0; if (atom->molecular) maxspecial=atom->maxspecial; bool init_ok = lj96_gpu_init(atom->ntypes+1, cutsq, lj1, lj2, lj3, lj4, offset, force->special_lj, atom->nlocal, atom->nlocal+atom->nghost, 300, maxspecial, cell_size, gpu_mode, screen); if (!init_ok) error->one("Insufficient memory on accelerator (or no fix gpu).\n"); if (force->newton_pair) error->all("Cannot use newton pair with GPU LJ96 pair style"); if (gpu_mode != GPU_NEIGH) { int irequest = neighbor->request(this); neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->full = 1; } } /* ---------------------------------------------------------------------- */ double PairLJ96CutGPU::memory_usage() { double bytes = Pair::memory_usage(); return bytes + lj96_gpu_bytes(); } /* ---------------------------------------------------------------------- */ void PairLJ96CutGPU::cpu_compute(int start, 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; double **x = atom->x; double **f = atom->f; int *type = atom->type; int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; double *special_lj = force->special_lj; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // loop over neighbors of my atoms for (ii = start; 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]; - - if (j < nall) factor_lj = 1.0; - else { - factor_lj = special_lj[j/nall]; - j %= nall; - } + 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 (eflag) { evdwl = r6inv*(lj3[itype][jtype]*r3inv-lj4[itype][jtype]) - offset[itype][jtype]; evdwl *= factor_lj; } if (evflag) ev_tally_full(i,evdwl,0.0,fpair,delx,dely,delz); } } } } /* ---------------------------------------------------------------------- */ void PairLJ96CutGPU::cpu_compute(int *nbors, int start, int eflag, int vflag) { int i,j,itype,jtype; int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; int stride = nlocal-start; double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair; double rsq,r2inv,r3inv,r6inv,forcelj,factor_lj; double *special_lj = force->special_lj; double **x = atom->x; double **f = atom->f; int *type = atom->type; // loop over neighbors of my atoms for (i = start; i < nlocal; i++) { xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; int *nbor = nbors + i - start; int jnum = *nbor; nbor += stride; int *nbor_end = nbor + stride * jnum; for (; nbor (b) ? (a) : (b)) #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 // External functions from cuda library for atom decomposition bool crml_gpu_init(const int ntypes, double cut_bothsq, double **host_lj1, double **host_lj2, double **host_lj3, double **host_lj4, double **offset, double *special_lj, const int nlocal, const int nall, const int max_nbors, const int maxspecial, const double cell_size, int &gpu_mode, FILE *screen, double host_cut_ljsq, double host_cut_coulsq, double *host_special_coul, const double qqrd2e, const double g_ewald, const double cut_lj_innersq, const double denom_lj, double **epsilon, double **sigma, const bool mix_arithmetic); void crml_gpu_clear(); int * crml_gpu_compute_n(const int timestep, const int ago, const int inum, const int nall, double **host_x, int *host_type, double *boxlo, double *boxhi, int *tag, int **nspecial, int **special, const bool eflag, const bool vflag, const bool eatom, const bool vatom, int &host_start, const double cpu_time, bool &success, double *host_q); void crml_gpu_compute(const int timestep, const int ago, const int inum, const int nall, double **host_x, int *host_type, int *ilist, int *numj, int **firstneigh, const bool eflag, const bool vflag, const bool eatom, const bool vatom, int &host_start, const double cpu_time, bool &success, double *host_q); double crml_gpu_bytes(); using namespace LAMMPS_NS; enum{GEOMETRIC,ARITHMETIC,SIXTHPOWER}; /* ---------------------------------------------------------------------- */ PairLJCharmmCoulLongGPU::PairLJCharmmCoulLongGPU(LAMMPS *lmp) : PairLJCharmmCoulLong(lmp), gpu_mode(GPU_PAIR) { respa_enable = 0; cpu_time = 0.0; } /* ---------------------------------------------------------------------- free all arrays ------------------------------------------------------------------------- */ PairLJCharmmCoulLongGPU::~PairLJCharmmCoulLongGPU() { crml_gpu_clear(); } /* ---------------------------------------------------------------------- */ void PairLJCharmmCoulLongGPU::compute(int eflag, int vflag) { int ntimestep = static_cast(update->ntimestep % MAXSMALLINT); if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; int nall = atom->nlocal + atom->nghost; int inum, host_start; bool success = true; if (gpu_mode == GPU_NEIGH) { inum = atom->nlocal; gpulist = crml_gpu_compute_n(ntimestep, neighbor->ago, inum, nall, atom->x, atom->type, domain->sublo, domain->subhi, atom->tag, atom->nspecial, atom->special, eflag, vflag, eflag_atom, vflag_atom, host_start, cpu_time, success, atom->q); } else { inum = list->inum; crml_gpu_compute(ntimestep, neighbor->ago, inum, nall, atom->x, atom->type, list->ilist, list->numneigh, list->firstneigh, eflag, vflag, eflag_atom, vflag_atom, host_start, cpu_time, success, atom->q); } if (!success) error->one("Out of memory on GPGPU"); if (host_startq_flag) error->all("Pair style lj/charmm/coul/long requires atom attribute q"); if (force->pair_match("gpu",0) == NULL) error->all("Cannot use pair hybrid with multiple GPU pair styles"); // Repeat cutsq calculation because done after call to init_style double cut; for (int i = 1; i <= atom->ntypes; i++) { for (int j = i; j <= atom->ntypes; j++) { if (setflag[i][j] != 0 || (setflag[i][i] != 0 && setflag[j][j] != 0)) cut = init_one(i,j); } } 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); double cell_size = sqrt(cut_bothsq) + neighbor->skin; // insure use of KSpace long-range solver, set g_ewald if (force->kspace == NULL) error->all("Pair style is incompatible with KSpace style"); g_ewald = force->kspace->g_ewald; // setup force tables if (ncoultablebits) init_tables(); int maxspecial=0; if (atom->molecular) maxspecial=atom->maxspecial; bool init_ok = crml_gpu_init(atom->ntypes+1, cut_bothsq, lj1, lj2, lj3, lj4, offset, force->special_lj, atom->nlocal, atom->nlocal+atom->nghost, 300, maxspecial, cell_size, gpu_mode, screen, cut_ljsq, cut_coulsq, force->special_coul, force->qqrd2e, g_ewald, cut_lj_innersq,denom_lj,epsilon,sigma, mix_flag == ARITHMETIC); if (!init_ok) error->one("Insufficient memory on accelerator (or no fix gpu).\n"); if (force->newton_pair) error->all("Cannot use newton pair with GPU CHARMM pair style"); if (gpu_mode != GPU_NEIGH) { int irequest = neighbor->request(this); neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->full = 1; } } /* ---------------------------------------------------------------------- */ double PairLJCharmmCoulLongGPU::memory_usage() { double bytes = Pair::memory_usage(); return bytes + crml_gpu_bytes(); } /* ---------------------------------------------------------------------- */ void PairLJCharmmCoulLongGPU::cpu_compute(int start, 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; double **x = atom->x; double **f = atom->f; double *q = atom->q; int *type = atom->type; int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; double *special_coul = force->special_coul; double *special_lj = force->special_lj; double qqrd2e = force->qqrd2e; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // loop over neighbors of my atoms for (ii = start; 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]; - - if (j < nall) factor_coul = factor_lj = 1.0; - else { - factor_coul = special_coul[j/nall]; - factor_lj = special_lj[j/nall]; - j %= nall; - } + factor_lj = special_lj[sbmask(j)]; + factor_coul = special_coul[sbmask(j)]; + j &= NEIGHMASK; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; if (rsq < cut_bothsq) { r2inv = 1.0/rsq; if (rsq < cut_coulsq) { if (!ncoultablebits || rsq <= tabinnersq) { r = sqrt(rsq); grij = g_ewald * r; expm2 = exp(-grij*grij); t = 1.0 / (1.0 + EWALD_P*grij); erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2; prefactor = qqrd2e * qtmp*q[j]/r; forcecoul = prefactor * (erfc + EWALD_F*grij*expm2); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor; } else { union_int_float_t rsq_lookup; rsq_lookup.f = rsq; itable = rsq_lookup.i & ncoulmask; itable >>= ncoulshiftbits; fraction = (rsq_lookup.f - rtable[itable]) * drtable[itable]; table = ftable[itable] + fraction*dftable[itable]; forcecoul = qtmp*q[j] * table; if (factor_coul < 1.0) { table = ctable[itable] + fraction*dctable[itable]; prefactor = qtmp*q[j] * table; forcecoul -= (1.0-factor_coul)*prefactor; } } } else forcecoul = 0.0; if (rsq < cut_ljsq) { r6inv = r2inv*r2inv*r2inv; jtype = type[j]; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); if (rsq > cut_lj_innersq) { switch1 = (cut_ljsq-rsq) * (cut_ljsq-rsq) * (cut_ljsq + 2.0*rsq - 3.0*cut_lj_innersq) / denom_lj; switch2 = 12.0*rsq * (cut_ljsq-rsq) * (rsq-cut_lj_innersq) / denom_lj; philj = r6inv * (lj3[itype][jtype]*r6inv - lj4[itype][jtype]); forcelj = forcelj*switch1 + philj*switch2; } } else forcelj = 0.0; fpair = (forcecoul + factor_lj*forcelj) * r2inv; f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; if (eflag) { if (rsq < cut_coulsq) { if (!ncoultablebits || rsq <= tabinnersq) ecoul = prefactor*erfc; else { table = etable[itable] + fraction*detable[itable]; ecoul = qtmp*q[j] * table; } if (factor_coul < 1.0) ecoul -= (1.0-factor_coul)*prefactor; } else ecoul = 0.0; if (rsq < cut_ljsq) { evdwl = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]); if (rsq > cut_lj_innersq) { switch1 = (cut_ljsq-rsq) * (cut_ljsq-rsq) * (cut_ljsq + 2.0*rsq - 3.0*cut_lj_innersq) / denom_lj; evdwl *= switch1; } evdwl *= factor_lj; } else evdwl = 0.0; } if (evflag) ev_tally_full(i,evdwl,ecoul,fpair,delx,dely,delz); } } } } /* ---------------------------------------------------------------------- */ void PairLJCharmmCoulLongGPU::cpu_compute(int *nbors, int start, int eflag, int vflag) { int i,j,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 rsq; evdwl = ecoul = 0.0; double **x = atom->x; double **f = atom->f; double *q = atom->q; int *type = atom->type; int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; int stride = nlocal - start; double *special_coul = force->special_coul; double *special_lj = force->special_lj; double qqrd2e = force->qqrd2e; // loop over neighbors of my atoms for (i = start; i < nlocal; i++) { qtmp = q[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; int *nbor = nbors + i - start; jnum = *nbor; nbor += stride; int *nbor_end = nbor + stride * jnum; for (; nbor>= ncoulshiftbits; fraction = (rsq_lookup.f - rtable[itable]) * drtable[itable]; table = ftable[itable] + fraction*dftable[itable]; forcecoul = qtmp*q[j] * table; if (factor_coul < 1.0) { table = ctable[itable] + fraction*dctable[itable]; prefactor = qtmp*q[j] * table; forcecoul -= (1.0-factor_coul)*prefactor; } } } else forcecoul = 0.0; if (rsq < cut_ljsq) { r6inv = r2inv*r2inv*r2inv; jtype = type[j]; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); if (rsq > cut_lj_innersq) { switch1 = (cut_ljsq-rsq) * (cut_ljsq-rsq) * (cut_ljsq + 2.0*rsq - 3.0*cut_lj_innersq) / denom_lj; switch2 = 12.0*rsq * (cut_ljsq-rsq) * (rsq-cut_lj_innersq) / denom_lj; philj = r6inv * (lj3[itype][jtype]*r6inv - lj4[itype][jtype]); forcelj = forcelj*switch1 + philj*switch2; } } else forcelj = 0.0; fpair = (forcecoul + factor_lj*forcelj) * r2inv; f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; if (eflag) { if (rsq < cut_coulsq) { if (!ncoultablebits || rsq <= tabinnersq) ecoul = prefactor*erfc; else { table = etable[itable] + fraction*detable[itable]; ecoul = qtmp*q[j] * table; } if (factor_coul < 1.0) ecoul -= (1.0-factor_coul)*prefactor; } else ecoul = 0.0; if (rsq < cut_ljsq) { evdwl = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]); if (rsq > cut_lj_innersq) { switch1 = (cut_ljsq-rsq) * (cut_ljsq-rsq) * (cut_ljsq + 2.0*rsq - 3.0*cut_lj_innersq) / denom_lj; evdwl *= switch1; } evdwl *= factor_lj; } else evdwl = 0.0; } if (j (b) ? (a) : (b)) // External functions from cuda library for atom decomposition bool ljc_gpu_init(const int ntypes, double **cutsq, double **host_lj1, double **host_lj2, double **host_lj3, double **host_lj4, double **offset, double *special_lj, const int nlocal, const int nall, const int max_nbors, const int maxspecial, const double cell_size, int &gpu_mode, FILE *screen, double **host_cut_ljsq, double **host_cut_coulsq, double *host_special_coul, const double qqrd2e); void ljc_gpu_clear(); int * ljc_gpu_compute_n(const int timestep, const int ago, const int inum, const int nall, double **host_x, int *host_type, double *boxlo, double *boxhi, int *tag, int **nspecial, int **special, const bool eflag, const bool vflag, const bool eatom, const bool vatom, int &host_start, const double cpu_time, bool &success, double *host_q); void ljc_gpu_compute(const int timestep, const int ago, const int inum, const int nall, double **host_x, int *host_type, int *ilist, int *numj, int **firstneigh, const bool eflag, const bool vflag, const bool eatom, const bool vatom, int &host_start, const double cpu_time, bool &success, double *host_q); double ljc_gpu_bytes(); using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ PairLJCutCoulCutGPU::PairLJCutCoulCutGPU(LAMMPS *lmp) : PairLJCutCoulCut(lmp), gpu_mode(GPU_PAIR) { respa_enable = 0; cpu_time = 0.0; } /* ---------------------------------------------------------------------- free all arrays ------------------------------------------------------------------------- */ PairLJCutCoulCutGPU::~PairLJCutCoulCutGPU() { ljc_gpu_clear(); } /* ---------------------------------------------------------------------- */ void PairLJCutCoulCutGPU::compute(int eflag, int vflag) { int ntimestep = static_cast(update->ntimestep % MAXSMALLINT); if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; int nall = atom->nlocal + atom->nghost; int inum, host_start; bool success = true; if (gpu_mode == GPU_NEIGH) { inum = atom->nlocal; gpulist = ljc_gpu_compute_n(ntimestep, neighbor->ago, inum, nall, atom->x, atom->type, domain->sublo, domain->subhi, atom->tag, atom->nspecial, atom->special, eflag, vflag, eflag_atom, vflag_atom, host_start, cpu_time, success, atom->q); } else { inum = list->inum; ljc_gpu_compute(ntimestep, neighbor->ago, inum, nall, atom->x, atom->type, list->ilist, list->numneigh, list->firstneigh, eflag, vflag, eflag_atom, vflag_atom, host_start, cpu_time, success, atom->q); } if (!success) error->one("Out of memory on GPGPU"); if (host_startq_flag) error->all("Pair style lj/cut/coul/cut requires atom attribute q"); if (force->pair_match("gpu",0) == NULL) error->all("Cannot use pair hybrid with multiple GPU pair styles"); // Repeat cutsq calculation because done after call to init_style double maxcut = -1.0; double cut; for (int i = 1; i <= atom->ntypes; i++) { for (int j = i; j <= atom->ntypes; j++) { if (setflag[i][j] != 0 || (setflag[i][i] != 0 && setflag[j][j] != 0)) { cut = init_one(i,j); cut *= cut; if (cut > maxcut) maxcut = cut; cutsq[i][j] = cutsq[j][i] = cut; } else cutsq[i][j] = cutsq[j][i] = 0.0; } } double cell_size = sqrt(maxcut) + neighbor->skin; int maxspecial=0; if (atom->molecular) maxspecial=atom->maxspecial; bool init_ok = ljc_gpu_init(atom->ntypes+1, cutsq, lj1, lj2, lj3, lj4, offset, force->special_lj, atom->nlocal, atom->nlocal+atom->nghost, 300, maxspecial, cell_size, gpu_mode, screen, cut_ljsq, cut_coulsq, force->special_coul, force->qqrd2e); if (!init_ok) error->one("Insufficient memory on accelerator (or no fix gpu).\n"); if (force->newton_pair) error->all("Cannot use newton pair with GPU LJ pair style"); if (gpu_mode != GPU_NEIGH) { int irequest = neighbor->request(this); neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->full = 1; } } /* ---------------------------------------------------------------------- */ double PairLJCutCoulCutGPU::memory_usage() { double bytes = Pair::memory_usage(); return bytes + ljc_gpu_bytes(); } /* ---------------------------------------------------------------------- */ void PairLJCutCoulCutGPU::cpu_compute(int start, 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; double **x = atom->x; double **f = atom->f; double *q = atom->q; int *type = atom->type; int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; 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 = start; 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]; - - if (j < nall) factor_coul = factor_lj = 1.0; - else { - factor_coul = special_coul[j/nall]; - factor_lj = special_lj[j/nall]; - j %= nall; - } + 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 (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_full(i,evdwl,ecoul,fpair,delx,dely,delz); } } } } /* ---------------------------------------------------------------------- */ void PairLJCutCoulCutGPU::cpu_compute(int *nbors, int start, int eflag, int vflag) { int i,j,jnum,itype,jtype; double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair; double rsq,r2inv,r6inv,forcecoul,forcelj,factor_coul,factor_lj; evdwl = ecoul = 0.0; double **x = atom->x; double **f = atom->f; double *q = atom->q; int *type = atom->type; int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; int stride = nlocal-start; double *special_coul = force->special_coul; double *special_lj = force->special_lj; double qqrd2e = force->qqrd2e; // loop over neighbors of my atoms for (i = start; i < nlocal; i++) { qtmp = q[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; int *nbor = nbors + i - start; jnum = *nbor; nbor += stride; int *nbor_end = nbor + stride * jnum; for (; nbor (b) ? (a) : (b)) #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 // External functions from cuda library for atom decomposition bool ljcl_gpu_init(const int ntypes, double **cutsq, double **host_lj1, double **host_lj2, double **host_lj3, double **host_lj4, double **offset, double *special_lj, const int nlocal, const int nall, const int max_nbors, const int maxspecial, const double cell_size, int &gpu_mode, FILE *screen, double **host_cut_ljsq, double host_cut_coulsq, double *host_special_coul, const double qqrd2e, const double g_ewald); void ljcl_gpu_clear(); int * ljcl_gpu_compute_n(const int timestep, const int ago, const int inum, const int nall, double **host_x, int *host_type, double *boxlo, double *boxhi, int *tag, int **nspecial, int **special, const bool eflag, const bool vflag, const bool eatom, const bool vatom, int &host_start, const double cpu_time, bool &success, double *host_q); void ljcl_gpu_compute(const int timestep, const int ago, const int inum, const int nall, double **host_x, int *host_type, int *ilist, int *numj, int **firstneigh, const bool eflag, const bool vflag, const bool eatom, const bool vatom, int &host_start, const double cpu_time, bool &success, double *host_q); double ljcl_gpu_bytes(); using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ PairLJCutCoulLongGPU::PairLJCutCoulLongGPU(LAMMPS *lmp) : PairLJCutCoulLong(lmp), gpu_mode(GPU_PAIR) { respa_enable = 0; cpu_time = 0.0; } /* ---------------------------------------------------------------------- free all arrays ------------------------------------------------------------------------- */ PairLJCutCoulLongGPU::~PairLJCutCoulLongGPU() { ljcl_gpu_clear(); } /* ---------------------------------------------------------------------- */ void PairLJCutCoulLongGPU::compute(int eflag, int vflag) { int ntimestep = static_cast(update->ntimestep % MAXSMALLINT); if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; int nall = atom->nlocal + atom->nghost; int inum, host_start; bool success = true; if (gpu_mode == GPU_NEIGH) { inum = atom->nlocal; gpulist = ljcl_gpu_compute_n(ntimestep, neighbor->ago, inum, nall, atom->x, atom->type, domain->sublo, domain->subhi, atom->tag, atom->nspecial, atom->special, eflag, vflag, eflag_atom, vflag_atom, host_start, cpu_time, success, atom->q); } else { inum = list->inum; ljcl_gpu_compute(ntimestep, neighbor->ago, inum, nall, atom->x, atom->type, list->ilist, list->numneigh, list->firstneigh, eflag, vflag, eflag_atom, vflag_atom, host_start, cpu_time, success, atom->q); } if (!success) error->one("Out of memory on GPGPU"); if (host_startq_flag) error->all("Pair style lj/cut/coul/cut requires atom attribute q"); if (force->pair_match("gpu",0) == NULL) error->all("Cannot use pair hybrid with multiple GPU pair styles"); // Repeat cutsq calculation because done after call to init_style double maxcut = -1.0; double cut; for (int i = 1; i <= atom->ntypes; i++) { for (int j = i; j <= atom->ntypes; j++) { if (setflag[i][j] != 0 || (setflag[i][i] != 0 && setflag[j][j] != 0)) { cut = init_one(i,j); cut *= cut; if (cut > maxcut) maxcut = cut; cutsq[i][j] = cutsq[j][i] = cut; } else cutsq[i][j] = cutsq[j][i] = 0.0; } } double cell_size = sqrt(maxcut) + neighbor->skin; cut_coulsq = cut_coul * cut_coul; // insure use of KSpace long-range solver, set g_ewald if (force->kspace == NULL) error->all("Pair style is incompatible with KSpace style"); g_ewald = force->kspace->g_ewald; // setup force tables if (ncoultablebits) init_tables(); int maxspecial=0; if (atom->molecular) maxspecial=atom->maxspecial; bool init_ok = ljcl_gpu_init(atom->ntypes+1, cutsq, lj1, lj2, lj3, lj4, offset, force->special_lj, atom->nlocal, atom->nlocal+atom->nghost, 300, maxspecial, cell_size, gpu_mode, screen, cut_ljsq, cut_coulsq, force->special_coul, force->qqrd2e, g_ewald); if (!init_ok) error->one("Insufficient memory on accelerator (or no fix gpu).\n"); if (force->newton_pair) error->all("Cannot use newton pair with GPU LJ pair style"); if (gpu_mode != GPU_NEIGH) { int irequest = neighbor->request(this); neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->full = 1; } } /* ---------------------------------------------------------------------- */ double PairLJCutCoulLongGPU::memory_usage() { double bytes = Pair::memory_usage(); return bytes + ljcl_gpu_bytes(); } /* ---------------------------------------------------------------------- */ void PairLJCutCoulLongGPU::cpu_compute(int start, 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; int *ilist,*jlist,*numneigh,**firstneigh; double rsq; evdwl = ecoul = 0.0; double **x = atom->x; double **f = atom->f; double *q = atom->q; int *type = atom->type; int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; double *special_coul = force->special_coul; double *special_lj = force->special_lj; double qqrd2e = force->qqrd2e; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // loop over neighbors of my atoms for (ii = start; 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]; - - if (j < nall) factor_coul = factor_lj = 1.0; - else { - factor_coul = special_coul[j/nall]; - factor_lj = special_lj[j/nall]; - j %= nall; - } + 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 (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_full(i,evdwl,ecoul,fpair,delx,dely,delz); } } } } /* ---------------------------------------------------------------------- */ void PairLJCutCoulLongGPU::cpu_compute(int *nbors, int start, int eflag, int vflag) { int i,j,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 rsq; evdwl = ecoul = 0.0; double **x = atom->x; double **f = atom->f; double *q = atom->q; int *type = atom->type; int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; int stride = nlocal-start; double *special_coul = force->special_coul; double *special_lj = force->special_lj; double qqrd2e = force->qqrd2e; // loop over neighbors of my atoms for (i = start; i < nlocal; i++) { qtmp = q[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; int *nbor = nbors + i - start; jnum = *nbor; nbor += stride; int *nbor_end = nbor + stride * jnum; for (; nbor>= 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 (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 (j (b) ? (a) : (b)) // External functions from cuda library for atom decomposition bool ljl_gpu_init(const int ntypes, double **cutsq, double **host_lj1, double **host_lj2, double **host_lj3, double **host_lj4, double **offset, double *special_lj, const int nlocal, const int nall, const int max_nbors, const int maxspecial, const double cell_size, int &gpu_mode, FILE *screen); void ljl_gpu_clear(); int * ljl_gpu_compute_n(const int timestep, const int ago, const int inum, const int nall, double **host_x, int *host_type, double *boxlo, double *boxhi, int *tag, int **nspecial, int **special, const bool eflag, const bool vflag, const bool eatom, const bool vatom, int &host_start, const double cpu_time, bool &success); void ljl_gpu_compute(const int timestep, const int ago, const int inum, const int nall, double **host_x, int *host_type, int *ilist, int *numj, int **firstneigh, const bool eflag, const bool vflag, const bool eatom, const bool vatom, int &host_start, const double cpu_time, bool &success); double ljl_gpu_bytes(); using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ PairLJCutGPU::PairLJCutGPU(LAMMPS *lmp) : PairLJCut(lmp), gpu_mode(GPU_PAIR) { respa_enable = 0; cpu_time = 0.0; } /* ---------------------------------------------------------------------- free all arrays ------------------------------------------------------------------------- */ PairLJCutGPU::~PairLJCutGPU() { ljl_gpu_clear(); } /* ---------------------------------------------------------------------- */ void PairLJCutGPU::compute(int eflag, int vflag) { int ntimestep = static_cast(update->ntimestep % MAXSMALLINT); if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; int nall = atom->nlocal + atom->nghost; int inum, host_start; bool success = true; if (gpu_mode == GPU_NEIGH) { inum = atom->nlocal; gpulist = ljl_gpu_compute_n(ntimestep, neighbor->ago, inum, nall, atom->x, atom->type, domain->sublo, domain->subhi, atom->tag, atom->nspecial, atom->special, eflag, vflag, eflag_atom, vflag_atom, host_start, cpu_time, success); } else { inum = list->inum; ljl_gpu_compute(ntimestep, neighbor->ago, inum, nall, atom->x, atom->type, list->ilist, list->numneigh, list->firstneigh, eflag, vflag, eflag_atom, vflag_atom, host_start, cpu_time, success); } if (!success) error->one("Out of memory on GPGPU"); if (host_startpair_match("gpu",0) == NULL) error->all("Cannot use pair hybrid with multiple GPU pair styles"); // Repeat cutsq calculation because done after call to init_style double maxcut = -1.0; double cut; for (int i = 1; i <= atom->ntypes; i++) { for (int j = i; j <= atom->ntypes; j++) { if (setflag[i][j] != 0 || (setflag[i][i] != 0 && setflag[j][j] != 0)) { cut = init_one(i,j); cut *= cut; if (cut > maxcut) maxcut = cut; cutsq[i][j] = cutsq[j][i] = cut; } else cutsq[i][j] = cutsq[j][i] = 0.0; } } double cell_size = sqrt(maxcut) + neighbor->skin; int maxspecial=0; if (atom->molecular) maxspecial=atom->maxspecial; bool init_ok = ljl_gpu_init(atom->ntypes+1, cutsq, lj1, lj2, lj3, lj4, offset, force->special_lj, atom->nlocal, atom->nlocal+atom->nghost, 300, maxspecial, cell_size, gpu_mode, screen); if (!init_ok) error->one("Insufficient memory on accelerator (or no fix gpu).\n"); if (force->newton_pair) error->all("Cannot use newton pair with GPU LJ pair style"); if (gpu_mode != GPU_NEIGH) { int irequest = neighbor->request(this); neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->full = 1; } } /* ---------------------------------------------------------------------- */ double PairLJCutGPU::memory_usage() { double bytes = Pair::memory_usage(); return bytes + ljl_gpu_bytes(); } /* ---------------------------------------------------------------------- */ void PairLJCutGPU::cpu_compute(int start, 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; double **x = atom->x; double **f = atom->f; int *type = atom->type; int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; double *special_lj = force->special_lj; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // loop over neighbors of my atoms for (ii = start; 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]; - - if (j < nall) factor_lj = 1.0; - else { - factor_lj = special_lj[j/nall]; - j %= nall; - } + 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 (eflag) { evdwl = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]) - offset[itype][jtype]; evdwl *= factor_lj; } if (evflag) ev_tally_full(i,evdwl,0.0,fpair,delx,dely,delz); } } } } /* ---------------------------------------------------------------------- */ void PairLJCutGPU::cpu_compute(int *nbors, int start, int eflag, int vflag) { int i,j,itype,jtype; int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; int stride = nlocal-start; double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair; double rsq,r2inv,r6inv,forcelj,factor_lj; double *special_lj = force->special_lj; double **x = atom->x; double **f = atom->f; int *type = atom->type; // loop over neighbors of my atoms for (i = start; i < nlocal; i++) { xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; int *nbor = nbors + i - start; int jnum = *nbor; nbor += stride; int *nbor_end = nbor + stride * jnum; for (; nbor (b) ? (a) : (b)) /* ---------------------------------------------------------------------- */ PairGranHertzHistory::PairGranHertzHistory(LAMMPS *lmp) : PairGranHookeHistory(lmp) {} /* ---------------------------------------------------------------------- */ void PairGranHertzHistory::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; 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 meff,damp,ccel,tor1,tor2,tor3; double fn,fs,fs1,fs2,fs3; double shrmag,rsht,polyhertz; 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 = 0; if (update->ntimestep > laststep) shearupdate = 1; 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; double *mass = atom->mass; int *type = atom->type; int *mask = atom->mask; int nlocal = atom->nlocal; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; firsttouch = list->listgranhistory->firstneigh; firstshear = list->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; // normal force = Hertzian contact + normal velocity damping if (rmass) { meff = rmass[i]*rmass[j] / (rmass[i]+rmass[j]); if (mask[i] & freeze_group_bit) meff = rmass[j]; if (mask[j] & freeze_group_bit) meff = rmass[i]; } else { itype = type[i]; jtype = type[j]; meff = mass[itype]*mass[jtype] / (mass[itype]+mass[jtype]); if (mask[i] & freeze_group_bit) meff = mass[jtype]; if (mask[j] & freeze_group_bit) meff = mass[itype]; } damp = meff*gamman*vnnr*rsqinv; ccel = kn*(radsum-r)*rinv - damp; polyhertz = sqrt((radsum-r)*radi*radj / radsum); ccel *= polyhertz; // 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 = -polyhertz * (kt*shear[0] + meff*gammat*vtr1); fs2 = -polyhertz * (kt*shear[1] + meff*gammat*vtr2); fs3 = -polyhertz * (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 (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,0, 0.0,0.0,fx,fy,fz,delx,dely,delz); } } } laststep = update->ntimestep; } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairGranHertzHistory::settings(int narg, char **arg) { if (narg != 6) error->all("Illegal pair_style command"); kn = force->numeric(arg[0]); if (strcmp(arg[1],"NULL") == 0) kt = kn * 2.0/7.0; else kt = force->numeric(arg[1]); gamman = force->numeric(arg[2]); if (strcmp(arg[3],"NULL") == 0) gammat = 0.5 * gamman; else gammat = force->numeric(arg[3]); xmu = force->numeric(arg[4]); dampflag = force->inumeric(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 > 1.0 || dampflag < 0 || dampflag > 1) error->all("Illegal pair_style command"); // convert Kn and Kt from pressure units to force/distance^2 kn /= force->nktv2p; kt /= force->nktv2p; } diff --git a/src/GRANULAR/pair_gran_hooke.cpp b/src/GRANULAR/pair_gran_hooke.cpp index aab8ae115..1df164fa9 100644 --- a/src/GRANULAR/pair_gran_hooke.cpp +++ b/src/GRANULAR/pair_gran_hooke.cpp @@ -1,195 +1,196 @@ /* ---------------------------------------------------------------------- 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 "math.h" #include "stdio.h" #include "string.h" #include "pair_gran_hooke.h" #include "atom.h" #include "force.h" #include "neigh_list.h" using namespace LAMMPS_NS; #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) /* ---------------------------------------------------------------------- */ PairGranHooke::PairGranHooke(LAMMPS *lmp) : PairGranHookeHistory(lmp) { no_virial_compute = 0; history = 0; } /* ---------------------------------------------------------------------- */ void PairGranHooke::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; 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 meff,damp,ccel,tor1,tor2,tor3; double fn,fs,ft,fs1,fs2,fs3; int *ilist,*jlist,*numneigh,**firstneigh; 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; double *rmass = atom->rmass; double *mass = atom->mass; int *type = atom->type; 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; // 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]; 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) { 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; // normal forces = Hookian contact + normal velocity damping if (rmass) { meff = rmass[i]*rmass[j] / (rmass[i]+rmass[j]); if (mask[i] & freeze_group_bit) meff = rmass[j]; if (mask[j] & freeze_group_bit) meff = rmass[i]; } else { itype = type[i]; jtype = type[j]; meff = mass[itype]*mass[jtype] / (mass[itype]+mass[jtype]); if (mask[i] & freeze_group_bit) meff = mass[jtype]; if (mask[j] & freeze_group_bit) meff = mass[itype]; } 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); // force normalization fn = xmu * fabs(ccel*r); fs = meff*gammat*vrel; if (vrel != 0.0) ft = MIN(fn,fs) / vrel; else ft = 0.0; // tangential force due to tangential velocity damping fs1 = -ft*vtr1; fs2 = -ft*vtr2; fs3 = -ft*vtr3; // 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_compute(); } diff --git a/src/GRANULAR/pair_gran_hooke_history.cpp b/src/GRANULAR/pair_gran_hooke_history.cpp index 087ffb4e7..cd4f8e4eb 100644 --- a/src/GRANULAR/pair_gran_hooke_history.cpp +++ b/src/GRANULAR/pair_gran_hooke_history.cpp @@ -1,547 +1,548 @@ /* ---------------------------------------------------------------------- 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 "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #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_pour.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; #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) /* ---------------------------------------------------------------------- */ PairGranHookeHistory::PairGranHookeHistory(LAMMPS *lmp) : Pair(lmp) { single_enable = 0; no_virial_compute = 1; history = 1; fix_history = NULL; laststep = -1; } /* ---------------------------------------------------------------------- */ PairGranHookeHistory::~PairGranHookeHistory() { 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; } } /* ---------------------------------------------------------------------- */ void PairGranHookeHistory::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; 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 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 = 0; if (update->ntimestep > laststep) shearupdate = 1; 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; double *mass = atom->mass; int *type = atom->type; int *mask = atom->mask; int nlocal = atom->nlocal; 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; // normal forces = Hookian contact + normal velocity damping if (rmass) { meff = rmass[i]*rmass[j] / (rmass[i]+rmass[j]); if (mask[i] & freeze_group_bit) meff = rmass[j]; if (mask[j] & freeze_group_bit) meff = rmass[i]; } else { itype = type[i]; jtype = type[j]; meff = mass[itype]*mass[jtype] / (mass[itype]+mass[jtype]); if (mask[i] & freeze_group_bit) meff = mass[jtype]; if (mask[j] & freeze_group_bit) meff = mass[itype]; } 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 (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,0, 0.0,0.0,fx,fy,fz,delx,dely,delz); } } } laststep = update->ntimestep; } /* ---------------------------------------------------------------------- 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("Illegal pair_style command"); kn = force->numeric(arg[0]); if (strcmp(arg[1],"NULL") == 0) kt = kn * 2.0/7.0; else kt = force->numeric(arg[1]); gamman = force->numeric(arg[2]); if (strcmp(arg[3],"NULL") == 0) gammat = 0.5 * gamman; else gammat = force->numeric(arg[3]); xmu = force->numeric(arg[4]); dampflag = force->inumeric(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 > 1.0 || dampflag < 0 || dampflag > 1) error->all("Illegal pair_style command"); } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairGranHookeHistory::coeff(int narg, char **arg) { if (narg > 2) error->all("Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { setflag[i][j] = 1; count++; } } if (count == 0) error->all("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->omega_flag || !atom->torque_flag) error->all("Pair granular requires atom attributes radius, omega, torque"); if (comm->ghost_velocity == 0) error->all("Pair granular requires ghost atoms store velocity"); // need a half neigh list and optionally a granular history neigh list int irequest = neighbor->request(this); neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->gran = 1; if (history) { irequest = neighbor->request(this); 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: // check if newton flag is valid // if first init, create Fix needed for storing shear history if (history && force->newton_pair == 1) error->all("Pair granular with shear history requires newton pair off"); if (history && fix_history == NULL) { char **fixarg = new char*[3]; fixarg[0] = (char *) "SHEAR_HISTORY"; fixarg[1] = (char *) "all"; fixarg[2] = (char *) "SHEAR_HISTORY"; modify->add_fix(3,fixarg); delete [] fixarg; fix_history = (FixShearHistory *) modify->fix[modify->nfix-1]; fix_history->pair = this; } // check for Fix freeze 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 Fix pour and set pour_type and pour_maxdiam int pour_type = 0; double pour_maxrad = 0.0; for (i = 0; i < modify->nfix; i++) if (strcmp(modify->fix[i]->style,"pour") == 0) break; if (i < modify->nfix) { pour_type = ((FixPour *) modify->fix[i])->ntype; pour_maxrad = ((FixPour *) modify->fix[i])->radius_hi; } // 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; if (pour_type) onerad_dynamic[pour_type] = pour_maxrad; 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); } /* ---------------------------------------------------------------------- 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; } diff --git a/src/KSPACE/pair_born_coul_long.cpp b/src/KSPACE/pair_born_coul_long.cpp index 493071bcb..b4c3bd7e0 100644 --- a/src/KSPACE/pair_born_coul_long.cpp +++ b/src/KSPACE/pair_born_coul_long.cpp @@ -1,505 +1,500 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author: Ahmed Ismail (SNL) ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "pair_born_coul_long.h" #include "atom.h" #include "comm.h" #include "force.h" #include "kspace.h" #include "neighbor.h" #include "neigh_list.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define EWALD_F 1.12837917 #define EWALD_P 0.3275911 #define A1 0.254829592 #define A2 -0.284496736 #define A3 1.421413741 #define A4 -1.453152027 #define A5 1.061405429 /* ---------------------------------------------------------------------- */ PairBornCoulLong::PairBornCoulLong(LAMMPS *lmp) : Pair(lmp) {} /* ---------------------------------------------------------------------- */ PairBornCoulLong::~PairBornCoulLong() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut_lj); memory->destroy(cut_ljsq); memory->destroy(a); memory->destroy(rho); memory->destroy(sigma); memory->destroy(c); memory->destroy(d); memory->destroy(rhoinv); memory->destroy(born1); memory->destroy(born2); memory->destroy(born3); memory->destroy(offset); } } /* ---------------------------------------------------------------------- */ void PairBornCoulLong::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair; double rsq,r2inv,r6inv,forcecoul,forceborn,factor_coul,factor_lj; double grij,expm2,prefactor,t,erfc; double r,rexp; int *ilist,*jlist,*numneigh,**firstneigh; evdwl = ecoul = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; double **x = atom->x; double **f = atom->f; double *q = atom->q; int *type = atom->type; int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; 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]; - - if (j < nall) factor_coul = factor_lj = 1.0; - else { - factor_coul = special_coul[j/nall]; - factor_lj = special_lj[j/nall]; - j %= nall; - } + factor_lj = special_lj[sbmask(j)]; + factor_coul = special_coul[sbmask(j)]; + j &= NEIGHMASK; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; jtype = type[j]; if (rsq < cutsq[itype][jtype]) { r2inv = 1.0/rsq; if (rsq < cut_coulsq) { r = sqrt(rsq); grij = g_ewald * r; expm2 = exp(-grij*grij); t = 1.0 / (1.0 + EWALD_P*grij); erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2; prefactor = qqrd2e * qtmp*q[j]/r; forcecoul = prefactor * (erfc + EWALD_F*grij*expm2); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor; } else forcecoul = 0.0; if (rsq < cut_ljsq[itype][jtype]) { 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 = prefactor*erfc; if (factor_coul < 1.0) ecoul -= (1.0-factor_coul)*prefactor; } else ecoul = 0.0; if (rsq < cut_ljsq[itype][jtype]) { evdwl = a[itype][jtype]*rexp - c[itype][jtype]*r6inv + d[itype][jtype]*r6inv*r2inv - offset[itype][jtype]; evdwl *= factor_lj; } else evdwl = 0.0; } if (evflag) ev_tally(i,j,nlocal,newton_pair, evdwl,ecoul,fpair,delx,dely,delz); } } } if (vflag_fdotr) virial_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("Illegal pair_style command"); cut_lj_global = force->numeric(arg[0]); if (narg == 1) cut_coul = cut_lj_global; else cut_coul = force->numeric(arg[1]); // reset cutoffs that have been explicitly set if (allocated) { int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i+1; j <= atom->ntypes; j++) if (setflag[i][j]) cut_lj[i][j] = cut_lj_global; } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairBornCoulLong::coeff(int narg, char **arg) { if (narg < 7 || narg > 8) error->all("Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); double a_one = force->numeric(arg[2]); double rho_one = force->numeric(arg[3]); double sigma_one = force->numeric(arg[4]); if (rho_one <= 0) error->all("Incorrect args for pair coefficients"); double c_one = force->numeric(arg[5]); double d_one = force->numeric(arg[6]); double cut_lj_one = cut_lj_global; if (narg == 8) cut_lj_one = force->numeric(arg[7]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { a[i][j] = a_one; rho[i][j] = rho_one; sigma[i][j] = sigma_one; c[i][j] = c_one; d[i][j] = d_one; cut_lj[i][j] = cut_lj_one; setflag[i][j] = 1; count++; } } if (count == 0) error->all("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("All pair coeffs are not set"); double cut = MAX(cut_lj[i][j],cut_coul); cut_ljsq[i][j] = cut_lj[i][j] * cut_lj[i][j]; rhoinv[i][j] = 1.0/rho[i][j]; born1[i][j] = a[i][j]/rho[i][j]; born2[i][j] = 6.0*c[i][j]; born3[i][j] = 8.0*d[i][j]; if (offset_flag) { double rexp = exp(-cut_lj[i][j]*rhoinv[i][j]); offset[i][j] = a[i][j]*rexp - c[i][j]/pow(cut_lj[i][j],6.0) + d[i][j]/pow(cut_lj[i][j],8.0); } else offset[i][j] = 0.0; cut_ljsq[j][i] = cut_ljsq[i][j]; a[j][i] = a[i][j]; c[j][i] = c[i][j]; d[j][i] = d[i][j]; rhoinv[j][i] = rhoinv[i][j]; sigma[j][i] = sigma[i][j]; born1[j][i] = born1[i][j]; born2[j][i] = born2[i][j]; born3[j][i] = born3[i][j]; offset[j][i] = offset[i][j]; // compute I,J contribution to long-range tail correction // count total # of atoms of type I and J via Allreduce if (tail_flag) { int *type = atom->type; int nlocal = atom->nlocal; double count[2],all[2]; count[0] = count[1] = 0.0; for (int k = 0; k < nlocal; k++) { if (type[k] == i) count[0] += 1.0; if (type[k] == j) count[1] += 1.0; } MPI_Allreduce(count,all,2,MPI_DOUBLE,MPI_SUM,world); double PI = 4.0*atan(1.0); 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*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*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("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("Pair style is incompatible with KSpace style"); g_ewald = force->kspace->g_ewald; int irequest = neighbor->request(this); } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairBornCoulLong::write_restart(FILE *fp) { write_restart_settings(fp); int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { fwrite(&setflag[i][j],sizeof(int),1,fp); if (setflag[i][j]) { fwrite(&a[i][j],sizeof(double),1,fp); fwrite(&rho[i][j],sizeof(double),1,fp); fwrite(&sigma[i][j],sizeof(double),1,fp); fwrite(&c[i][j],sizeof(double),1,fp); fwrite(&d[i][j],sizeof(double),1,fp); fwrite(&cut_lj[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairBornCoulLong::read_restart(FILE *fp) { read_restart_settings(fp); allocate(); int i,j; int me = comm->me; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp); MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world); if (setflag[i][j]) { if (me == 0) { fread(&a[i][j],sizeof(double),1,fp); fread(&rho[i][j],sizeof(double),1,fp); fread(&sigma[i][j],sizeof(double),1,fp); fread(&c[i][j],sizeof(double),1,fp); fread(&d[i][j],sizeof(double),1,fp); fread(&cut_lj[i][j],sizeof(double),1,fp); } MPI_Bcast(&a[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&rho[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&c[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&d[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_lj[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairBornCoulLong::write_restart_settings(FILE *fp) { fwrite(&cut_lj_global,sizeof(double),1,fp); fwrite(&cut_coul,sizeof(double),1,fp); fwrite(&offset_flag,sizeof(int),1,fp); fwrite(&mix_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairBornCoulLong::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&cut_lj_global,sizeof(double),1,fp); fread(&cut_coul,sizeof(double),1,fp); fread(&offset_flag,sizeof(int),1,fp); fread(&mix_flag,sizeof(int),1,fp); } MPI_Bcast(&cut_lj_global,1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_coul,1,MPI_DOUBLE,0,world); MPI_Bcast(&offset_flag,1,MPI_INT,0,world); MPI_Bcast(&mix_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- */ double PairBornCoulLong::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r2inv,r6inv,r,rexp,grij,expm2,t,erfc,prefactor; double forcecoul,forceborn,phicoul,phiborn; r2inv = 1.0/rsq; if (rsq < cut_coulsq) { r = sqrt(rsq); grij = g_ewald * r; expm2 = exp(-grij*grij); t = 1.0 / (1.0 + EWALD_P*grij); erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2; prefactor = force->qqrd2e * atom->q[i]*atom->q[j]/r; forcecoul = prefactor * (erfc + EWALD_F*grij*expm2); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor; } else forcecoul = 0.0; if (rsq < cut_ljsq[itype][jtype]) { r6inv = r2inv*r2inv*r2inv; r = sqrt(rsq); rexp = exp((sigma[itype][jtype]-r)*rhoinv[itype][jtype]); forceborn = born1[itype][jtype]*r*rexp - born2[itype][jtype]*r6inv + born3[itype][jtype]*r2inv*r6inv; } else forceborn = 0.0; fforce = (forcecoul + factor_lj*forceborn) * r2inv; double eng = 0.0; if (rsq < cut_coulsq) { phicoul = prefactor*erfc; if (factor_coul < 1.0) phicoul -= (1.0-factor_coul)*prefactor; eng += phicoul; } if (rsq < cut_ljsq[itype][jtype]) { phiborn = a[itype][jtype]*rexp - c[itype][jtype]*r6inv + d[itype][jtype]*r2inv*r6inv - offset[itype][jtype]; eng += factor_lj*phiborn; } return eng; } /* ---------------------------------------------------------------------- */ void *PairBornCoulLong::extract(char *str, int &dim) { 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 1cf9d0a49..cd65fb0c5 100644 --- a/src/KSPACE/pair_buck_coul_long.cpp +++ b/src/KSPACE/pair_buck_coul_long.cpp @@ -1,475 +1,470 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "pair_buck_coul_long.h" #include "atom.h" #include "comm.h" #include "force.h" #include "kspace.h" #include "neighbor.h" #include "neigh_list.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define EWALD_F 1.12837917 #define EWALD_P 0.3275911 #define A1 0.254829592 #define A2 -0.284496736 #define A3 1.421413741 #define A4 -1.453152027 #define A5 1.061405429 /* ---------------------------------------------------------------------- */ PairBuckCoulLong::PairBuckCoulLong(LAMMPS *lmp) : Pair(lmp) {} /* ---------------------------------------------------------------------- */ PairBuckCoulLong::~PairBuckCoulLong() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut_lj); memory->destroy(cut_ljsq); memory->destroy(a); memory->destroy(rho); memory->destroy(c); memory->destroy(rhoinv); memory->destroy(buck1); memory->destroy(buck2); memory->destroy(offset); } } /* ---------------------------------------------------------------------- */ void PairBuckCoulLong::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair; double rsq,r2inv,r6inv,forcecoul,forcebuck,factor_coul,factor_lj; double grij,expm2,prefactor,t,erfc; double r,rexp; int *ilist,*jlist,*numneigh,**firstneigh; evdwl = ecoul = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; double **x = atom->x; double **f = atom->f; double *q = atom->q; int *type = atom->type; int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; 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]; - - if (j < nall) factor_coul = factor_lj = 1.0; - else { - factor_coul = special_coul[j/nall]; - factor_lj = special_lj[j/nall]; - j %= nall; - } + factor_lj = special_lj[sbmask(j)]; + factor_coul = special_coul[sbmask(j)]; + j &= NEIGHMASK; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; jtype = type[j]; if (rsq < cutsq[itype][jtype]) { r2inv = 1.0/rsq; if (rsq < cut_coulsq) { r = sqrt(rsq); grij = g_ewald * r; expm2 = exp(-grij*grij); t = 1.0 / (1.0 + EWALD_P*grij); erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2; prefactor = qqrd2e * qtmp*q[j]/r; forcecoul = prefactor * (erfc + EWALD_F*grij*expm2); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor; } else forcecoul = 0.0; if (rsq < cut_ljsq[itype][jtype]) { 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; fpair = (forcecoul + factor_lj*forcebuck) * r2inv; f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; if (newton_pair || j < nlocal) { f[j][0] -= delx*fpair; f[j][1] -= dely*fpair; f[j][2] -= delz*fpair; } if (eflag) { if (rsq < cut_coulsq) { ecoul = prefactor*erfc; if (factor_coul < 1.0) ecoul -= (1.0-factor_coul)*prefactor; } else ecoul = 0.0; if (rsq < cut_ljsq[itype][jtype]) { evdwl = a[itype][jtype]*rexp - c[itype][jtype]*r6inv - offset[itype][jtype]; evdwl *= factor_lj; } else evdwl = 0.0; } if (evflag) ev_tally(i,j,nlocal,newton_pair, evdwl,ecoul,fpair,delx,dely,delz); } } } if (vflag_fdotr) virial_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("Illegal pair_style command"); cut_lj_global = force->numeric(arg[0]); if (narg == 1) cut_coul = cut_lj_global; else cut_coul = force->numeric(arg[1]); // reset cutoffs that have been explicitly set if (allocated) { int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i+1; j <= atom->ntypes; j++) if (setflag[i][j]) cut_lj[i][j] = cut_lj_global; } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairBuckCoulLong::coeff(int narg, char **arg) { if (narg < 5 || narg > 6) error->all("Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); double a_one = force->numeric(arg[2]); double rho_one = force->numeric(arg[3]); if (rho_one <= 0) error->all("Incorrect args for pair coefficients"); double c_one = force->numeric(arg[4]); double cut_lj_one = cut_lj_global; if (narg == 6) cut_lj_one = force->numeric(arg[5]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { a[i][j] = a_one; rho[i][j] = rho_one; c[i][j] = c_one; cut_lj[i][j] = cut_lj_one; setflag[i][j] = 1; count++; } } if (count == 0) error->all("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("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 PI = 4.0*atan(1.0); 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*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*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("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("Pair style is incompatible with KSpace style"); g_ewald = force->kspace->g_ewald; int irequest = neighbor->request(this); } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairBuckCoulLong::write_restart(FILE *fp) { write_restart_settings(fp); int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { fwrite(&setflag[i][j],sizeof(int),1,fp); if (setflag[i][j]) { fwrite(&a[i][j],sizeof(double),1,fp); fwrite(&rho[i][j],sizeof(double),1,fp); fwrite(&c[i][j],sizeof(double),1,fp); fwrite(&cut_lj[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairBuckCoulLong::read_restart(FILE *fp) { read_restart_settings(fp); allocate(); int i,j; int me = comm->me; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp); MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world); if (setflag[i][j]) { if (me == 0) { fread(&a[i][j],sizeof(double),1,fp); fread(&rho[i][j],sizeof(double),1,fp); fread(&c[i][j],sizeof(double),1,fp); fread(&cut_lj[i][j],sizeof(double),1,fp); } MPI_Bcast(&a[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&rho[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&c[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_lj[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairBuckCoulLong::write_restart_settings(FILE *fp) { fwrite(&cut_lj_global,sizeof(double),1,fp); fwrite(&cut_coul,sizeof(double),1,fp); fwrite(&offset_flag,sizeof(int),1,fp); fwrite(&mix_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairBuckCoulLong::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&cut_lj_global,sizeof(double),1,fp); fread(&cut_coul,sizeof(double),1,fp); fread(&offset_flag,sizeof(int),1,fp); fread(&mix_flag,sizeof(int),1,fp); } MPI_Bcast(&cut_lj_global,1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_coul,1,MPI_DOUBLE,0,world); MPI_Bcast(&offset_flag,1,MPI_INT,0,world); MPI_Bcast(&mix_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- */ double PairBuckCoulLong::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r2inv,r6inv,r,rexp,grij,expm2,t,erfc,prefactor; double forcecoul,forcebuck,phicoul,phibuck; r2inv = 1.0/rsq; if (rsq < cut_coulsq) { r = sqrt(rsq); grij = g_ewald * r; expm2 = exp(-grij*grij); t = 1.0 / (1.0 + EWALD_P*grij); erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2; prefactor = force->qqrd2e * atom->q[i]*atom->q[j]/r; forcecoul = prefactor * (erfc + EWALD_F*grij*expm2); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor; } else forcecoul = 0.0; if (rsq < cut_ljsq[itype][jtype]) { r6inv = r2inv*r2inv*r2inv; r = sqrt(rsq); rexp = exp(-r*rhoinv[itype][jtype]); forcebuck = buck1[itype][jtype]*r*rexp - buck2[itype][jtype]*r6inv; } else forcebuck = 0.0; fforce = (forcecoul + factor_lj*forcebuck) * r2inv; double eng = 0.0; if (rsq < cut_coulsq) { phicoul = prefactor*erfc; if (factor_coul < 1.0) phicoul -= (1.0-factor_coul)*prefactor; eng += phicoul; } if (rsq < cut_ljsq[itype][jtype]) { phibuck = a[itype][jtype]*rexp - c[itype][jtype]*r6inv - offset[itype][jtype]; eng += factor_lj*phibuck; } return eng; } /* ---------------------------------------------------------------------- */ void *PairBuckCoulLong::extract(char *str, int &dim) { dim = 0; if (strcmp(str,"cut_coul") == 0) return (void *) &cut_coul; return NULL; } diff --git a/src/KSPACE/pair_coul_long.cpp b/src/KSPACE/pair_coul_long.cpp index 20ad91641..1ddefad8e 100644 --- a/src/KSPACE/pair_coul_long.cpp +++ b/src/KSPACE/pair_coul_long.cpp @@ -1,580 +1,575 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author: Paul Crozier (SNL) ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "pair_coul_long.h" #include "atom.h" #include "comm.h" #include "force.h" #include "kspace.h" #include "neighbor.h" #include "neigh_list.h" #include "update.h" #include "integrate.h" #include "respa.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define EWALD_F 1.12837917 #define EWALD_P 0.3275911 #define A1 0.254829592 #define A2 -0.284496736 #define A3 1.421413741 #define A4 -1.453152027 #define A5 1.061405429 /* ---------------------------------------------------------------------- */ PairCoulLong::PairCoulLong(LAMMPS *lmp) : Pair(lmp) { ftable = NULL; } /* ---------------------------------------------------------------------- */ PairCoulLong::~PairCoulLong() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(scale); } if (ftable) free_tables(); } /* ---------------------------------------------------------------------- */ void PairCoulLong::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itable,itype,jtype; double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,ecoul,fpair; double fraction,table; double r,r2inv,forcecoul,factor_coul; double grij,expm2,prefactor,t,erfc; int *ilist,*jlist,*numneigh,**firstneigh; double rsq; ecoul = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; double **x = atom->x; double **f = atom->f; double *q = atom->q; int *type = atom->type; int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; 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]; - - if (j < nall) factor_coul = 1.0; - else { - factor_coul = special_coul[j/nall]; - j %= nall; - } + 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_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("Illegal pair_style command"); cut_coul = force->numeric(arg[0]); } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairCoulLong::coeff(int narg, char **arg) { if (narg != 2) error->all("Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { scale[i][j] = 1.0; setflag[i][j] = 1; count++; } } if (count == 0) error->all("Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairCoulLong::init_style() { int i,j; if (!atom->q_flag) error->all("Pair style lj/cut/coul/long requires atom attribute q"); int irequest = neighbor->request(this); cut_coulsq = cut_coul * cut_coul; // set & error check interior rRESPA cutoffs if (strcmp(update->integrate_style,"respa") == 0 && ((Respa *) update->integrate)->level_inner >= 0) { cut_respa = ((Respa *) update->integrate)->cutoff; if (cut_coul < cut_respa[3]) error->all("Pair cutoff < Respa interior cutoff"); } else cut_respa = NULL; // insure use of KSpace long-range solver, set g_ewald if (force->kspace == NULL) error->all("Pair style is incompatible with KSpace style"); g_ewald = force->kspace->g_ewald; // setup force tables if (ncoultablebits) init_tables(); } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairCoulLong::init_one(int i, int j) { scale[j][i] = scale[i][j]; return cut_coul; } /* ---------------------------------------------------------------------- setup force tables used in compute routines ------------------------------------------------------------------------- */ void PairCoulLong::init_tables() { int masklo,maskhi; double r,grij,expm2,derfc,rsw; double qqrd2e = force->qqrd2e; tabinnersq = tabinner*tabinner; init_bitmap(tabinner,cut_coul,ncoultablebits, masklo,maskhi,ncoulmask,ncoulshiftbits); int ntable = 1; for (int i = 0; i < ncoultablebits; i++) ntable *= 2; // linear lookup tables of length N = 2^ncoultablebits // stored value = value at lower edge of bin // d values = delta from lower edge to upper edge of bin if (ftable) free_tables(); memory->create(rtable,ntable,"pair:rtable"); memory->create(ftable,ntable,"pair:ftable"); memory->create(ctable,ntable,"pair:ctable"); memory->create(etable,ntable,"pair:etable"); memory->create(drtable,ntable,"pair:drtable"); memory->create(dftable,ntable,"pair:dftable"); memory->create(dctable,ntable,"pair:dctable"); memory->create(detable,ntable,"pair:detable"); if (cut_respa == NULL) { vtable = ptable = dvtable = dptable = NULL; } else { memory->create(vtable,ntable,"pair:vtable"); memory->create(ptable,ntable,"pair:ptable"); memory->create(dvtable,ntable,"pair:dvtable"); memory->create(dptable,ntable,"pair:dptable"); } union_int_float_t rsq_lookup; union_int_float_t minrsq_lookup; int itablemin; minrsq_lookup.i = 0 << ncoulshiftbits; minrsq_lookup.i |= maskhi; for (int i = 0; i < ntable; i++) { rsq_lookup.i = i << ncoulshiftbits; rsq_lookup.i |= masklo; if (rsq_lookup.f < tabinnersq) { rsq_lookup.i = i << ncoulshiftbits; rsq_lookup.i |= maskhi; } r = sqrtf(rsq_lookup.f); grij = g_ewald * r; expm2 = exp(-grij*grij); derfc = erfc(grij); if (cut_respa == NULL) { rtable[i] = rsq_lookup.f; ftable[i] = qqrd2e/r * (derfc + EWALD_F*grij*expm2); ctable[i] = qqrd2e/r; etable[i] = qqrd2e/r * derfc; } else { rtable[i] = rsq_lookup.f; ftable[i] = qqrd2e/r * (derfc + EWALD_F*grij*expm2 - 1.0); ctable[i] = 0.0; etable[i] = qqrd2e/r * derfc; ptable[i] = qqrd2e/r; vtable[i] = qqrd2e/r * (derfc + EWALD_F*grij*expm2); if (rsq_lookup.f > cut_respa[2]*cut_respa[2]) { if (rsq_lookup.f < cut_respa[3]*cut_respa[3]) { rsw = (r - cut_respa[2])/(cut_respa[3] - cut_respa[2]); ftable[i] += qqrd2e/r * rsw*rsw*(3.0 - 2.0*rsw); ctable[i] = qqrd2e/r * rsw*rsw*(3.0 - 2.0*rsw); } else { ftable[i] = qqrd2e/r * (derfc + EWALD_F*grij*expm2); ctable[i] = qqrd2e/r; } } } minrsq_lookup.f = MIN(minrsq_lookup.f,rsq_lookup.f); } tabinnersq = minrsq_lookup.f; int ntablem1 = ntable - 1; for (int i = 0; i < ntablem1; i++) { drtable[i] = 1.0/(rtable[i+1] - rtable[i]); dftable[i] = ftable[i+1] - ftable[i]; dctable[i] = ctable[i+1] - ctable[i]; detable[i] = etable[i+1] - etable[i]; } if (cut_respa) { for (int i = 0; i < ntablem1; i++) { dvtable[i] = vtable[i+1] - vtable[i]; dptable[i] = ptable[i+1] - ptable[i]; } } // get the delta values for the last table entries // tables are connected periodically between 0 and ntablem1 drtable[ntablem1] = 1.0/(rtable[0] - rtable[ntablem1]); dftable[ntablem1] = ftable[0] - ftable[ntablem1]; dctable[ntablem1] = ctable[0] - ctable[ntablem1]; detable[ntablem1] = etable[0] - etable[ntablem1]; if (cut_respa) { dvtable[ntablem1] = vtable[0] - vtable[ntablem1]; dptable[ntablem1] = ptable[0] - ptable[ntablem1]; } // get the correct delta values at itablemax // smallest r is in bin itablemin // largest r is in bin itablemax, which is itablemin-1, // or ntablem1 if itablemin=0 // deltas at itablemax only needed if corresponding rsq < cut*cut // if so, compute deltas between rsq and cut*cut double f_tmp,c_tmp,e_tmp,p_tmp,v_tmp; itablemin = minrsq_lookup.i & ncoulmask; itablemin >>= ncoulshiftbits; int itablemax = itablemin - 1; if (itablemin == 0) itablemax = ntablem1; rsq_lookup.i = itablemax << ncoulshiftbits; rsq_lookup.i |= maskhi; if (rsq_lookup.f < cut_coulsq) { rsq_lookup.f = cut_coulsq; r = sqrtf(rsq_lookup.f); grij = g_ewald * r; expm2 = exp(-grij*grij); derfc = erfc(grij); if (cut_respa == NULL) { f_tmp = qqrd2e/r * (derfc + EWALD_F*grij*expm2); c_tmp = qqrd2e/r; e_tmp = qqrd2e/r * derfc; } else { f_tmp = qqrd2e/r * (derfc + EWALD_F*grij*expm2 - 1.0); c_tmp = 0.0; e_tmp = qqrd2e/r * derfc; p_tmp = qqrd2e/r; v_tmp = qqrd2e/r * (derfc + EWALD_F*grij*expm2); if (rsq_lookup.f > cut_respa[2]*cut_respa[2]) { if (rsq_lookup.f < cut_respa[3]*cut_respa[3]) { rsw = (r - cut_respa[2])/(cut_respa[3] - cut_respa[2]); f_tmp += qqrd2e/r * rsw*rsw*(3.0 - 2.0*rsw); c_tmp = qqrd2e/r * rsw*rsw*(3.0 - 2.0*rsw); } else { f_tmp = qqrd2e/r * (derfc + EWALD_F*grij*expm2); c_tmp = qqrd2e/r; } } } drtable[itablemax] = 1.0/(rsq_lookup.f - rtable[itablemax]); dftable[itablemax] = f_tmp - ftable[itablemax]; dctable[itablemax] = c_tmp - ctable[itablemax]; detable[itablemax] = e_tmp - etable[itablemax]; if (cut_respa) { dvtable[itablemax] = v_tmp - vtable[itablemax]; dptable[itablemax] = p_tmp - ptable[itablemax]; } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairCoulLong::write_restart(FILE *fp) { write_restart_settings(fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairCoulLong::read_restart(FILE *fp) { read_restart_settings(fp); allocate(); } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairCoulLong::write_restart_settings(FILE *fp) { fwrite(&cut_coul,sizeof(double),1,fp); fwrite(&offset_flag,sizeof(int),1,fp); fwrite(&mix_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairCoulLong::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&cut_coul,sizeof(double),1,fp); fread(&offset_flag,sizeof(int),1,fp); fread(&mix_flag,sizeof(int),1,fp); } MPI_Bcast(&cut_coul,1,MPI_DOUBLE,0,world); MPI_Bcast(&offset_flag,1,MPI_INT,0,world); MPI_Bcast(&mix_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- free memory for tables used in pair computations ------------------------------------------------------------------------- */ void PairCoulLong::free_tables() { memory->destroy(rtable); memory->destroy(drtable); memory->destroy(ftable); memory->destroy(dftable); memory->destroy(ctable); memory->destroy(dctable); memory->destroy(etable); memory->destroy(detable); memory->destroy(vtable); memory->destroy(dvtable); memory->destroy(ptable); memory->destroy(dptable); } /* ---------------------------------------------------------------------- */ double PairCoulLong::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r2inv,r,grij,expm2,t,erfc,prefactor; double fraction,table,forcecoul,phicoul; int itable; r2inv = 1.0/rsq; if (!ncoultablebits || rsq <= tabinnersq) { r = sqrt(rsq); grij = g_ewald * r; expm2 = exp(-grij*grij); t = 1.0 / (1.0 + EWALD_P*grij); erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2; prefactor = force->qqrd2e * atom->q[i]*atom->q[j]/r; forcecoul = prefactor * (erfc + EWALD_F*grij*expm2); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor; } else { union_int_float_t rsq_lookup; rsq_lookup.f = rsq; itable = rsq_lookup.i & ncoulmask; itable >>= ncoulshiftbits; fraction = (rsq_lookup.f - rtable[itable]) * drtable[itable]; table = ftable[itable] + fraction*dftable[itable]; forcecoul = atom->q[i]*atom->q[j] * table; if (factor_coul < 1.0) { table = ctable[itable] + fraction*dctable[itable]; prefactor = atom->q[i]*atom->q[j] * table; forcecoul -= (1.0-factor_coul)*prefactor; } } fforce = forcecoul * r2inv; if (!ncoultablebits || rsq <= tabinnersq) phicoul = prefactor*erfc; else { table = etable[itable] + fraction*detable[itable]; phicoul = atom->q[i]*atom->q[j] * table; } if (factor_coul < 1.0) phicoul -= (1.0-factor_coul)*prefactor; return phicoul; } /* ---------------------------------------------------------------------- */ void *PairCoulLong::extract(char *str, int &dim) { 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 b4a78d39e..acedafe4b 100644 --- a/src/KSPACE/pair_lj_charmm_coul_long.cpp +++ b/src/KSPACE/pair_lj_charmm_coul_long.cpp @@ -1,1220 +1,1200 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author: Paul Crozier (SNL) ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "pair_lj_charmm_coul_long.h" #include "atom.h" #include "comm.h" #include "force.h" #include "kspace.h" #include "update.h" #include "integrate.h" #include "respa.h" #include "neighbor.h" #include "neigh_list.h" #include "neigh_request.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; enum{GEOMETRIC,ARITHMETIC,SIXTHPOWER}; // same as in pair.cpp #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define EWALD_F 1.12837917 #define EWALD_P 0.3275911 #define A1 0.254829592 #define A2 -0.284496736 #define A3 1.421413741 #define A4 -1.453152027 #define A5 1.061405429 /* ---------------------------------------------------------------------- */ PairLJCharmmCoulLong::PairLJCharmmCoulLong(LAMMPS *lmp) : Pair(lmp) { respa_enable = 1; ftable = NULL; implicit = 0; mix_flag = ARITHMETIC; } /* ---------------------------------------------------------------------- */ PairLJCharmmCoulLong::~PairLJCharmmCoulLong() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(epsilon); memory->destroy(sigma); memory->destroy(eps14); memory->destroy(sigma14); memory->destroy(lj1); memory->destroy(lj2); memory->destroy(lj3); memory->destroy(lj4); memory->destroy(lj14_1); memory->destroy(lj14_2); memory->destroy(lj14_3); memory->destroy(lj14_4); } if (ftable) free_tables(); } /* ---------------------------------------------------------------------- */ void PairLJCharmmCoulLong::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype,itable; double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair; double fraction,table; double r,r2inv,r6inv,forcecoul,forcelj,factor_coul,factor_lj; double grij,expm2,prefactor,t,erfc; double philj,switch1,switch2; int *ilist,*jlist,*numneigh,**firstneigh; double rsq; evdwl = ecoul = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; double **x = atom->x; double **f = atom->f; double *q = atom->q; int *type = atom->type; int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; 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]; - - if (j < nall) factor_coul = factor_lj = 1.0; - else { - factor_coul = special_coul[j/nall]; - factor_lj = special_lj[j/nall]; - j %= nall; - } + factor_lj = special_lj[sbmask(j)]; + factor_coul = special_coul[sbmask(j)]; + j &= NEIGHMASK; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; if (rsq < cut_bothsq) { r2inv = 1.0/rsq; if (rsq < cut_coulsq) { if (!ncoultablebits || rsq <= tabinnersq) { r = sqrt(rsq); grij = g_ewald * r; expm2 = exp(-grij*grij); t = 1.0 / (1.0 + EWALD_P*grij); erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2; prefactor = qqrd2e * qtmp*q[j]/r; forcecoul = prefactor * (erfc + EWALD_F*grij*expm2); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor; } else { union_int_float_t rsq_lookup; rsq_lookup.f = rsq; itable = rsq_lookup.i & ncoulmask; itable >>= ncoulshiftbits; fraction = (rsq_lookup.f - rtable[itable]) * drtable[itable]; table = ftable[itable] + fraction*dftable[itable]; forcecoul = qtmp*q[j] * table; if (factor_coul < 1.0) { table = ctable[itable] + fraction*dctable[itable]; prefactor = qtmp*q[j] * table; forcecoul -= (1.0-factor_coul)*prefactor; } } } else forcecoul = 0.0; if (rsq < cut_ljsq) { r6inv = r2inv*r2inv*r2inv; jtype = type[j]; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); if (rsq > cut_lj_innersq) { switch1 = (cut_ljsq-rsq) * (cut_ljsq-rsq) * (cut_ljsq + 2.0*rsq - 3.0*cut_lj_innersq) / denom_lj; switch2 = 12.0*rsq * (cut_ljsq-rsq) * (rsq-cut_lj_innersq) / denom_lj; philj = r6inv * (lj3[itype][jtype]*r6inv - lj4[itype][jtype]); forcelj = forcelj*switch1 + philj*switch2; } } else forcelj = 0.0; fpair = (forcecoul + factor_lj*forcelj) * r2inv; f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; if (newton_pair || j < nlocal) { f[j][0] -= delx*fpair; f[j][1] -= dely*fpair; f[j][2] -= delz*fpair; } if (eflag) { if (rsq < cut_coulsq) { if (!ncoultablebits || rsq <= tabinnersq) ecoul = prefactor*erfc; else { table = etable[itable] + fraction*detable[itable]; ecoul = qtmp*q[j] * table; } if (factor_coul < 1.0) ecoul -= (1.0-factor_coul)*prefactor; } else ecoul = 0.0; if (rsq < cut_ljsq) { evdwl = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]); if (rsq > cut_lj_innersq) { switch1 = (cut_ljsq-rsq) * (cut_ljsq-rsq) * (cut_ljsq + 2.0*rsq - 3.0*cut_lj_innersq) / denom_lj; evdwl *= switch1; } evdwl *= factor_lj; } else evdwl = 0.0; } if (evflag) ev_tally(i,j,nlocal,newton_pair, evdwl,ecoul,fpair,delx,dely,delz); } } } if (vflag_fdotr) virial_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; - int nall = nlocal + atom->nghost; 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]; - - if (j < nall) factor_coul = factor_lj = 1.0; - else { - factor_coul = special_coul[j/nall]; - factor_lj = special_lj[j/nall]; - j %= nall; - } + factor_lj = special_lj[sbmask(j)]; + factor_coul = special_coul[sbmask(j)]; + j &= NEIGHMASK; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; if (rsq < cut_out_off_sq) { r2inv = 1.0/rsq; forcecoul = qqrd2e * qtmp*q[j]*sqrt(r2inv); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*forcecoul; r6inv = r2inv*r2inv*r2inv; jtype = type[j]; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); fpair = (forcecoul + factor_lj*forcelj) * r2inv; if (rsq > cut_out_on_sq) { rsw = (sqrt(rsq) - cut_out_on)/cut_out_diff; fpair *= 1.0 + rsw*rsw*(2.0*rsw-3.0); } f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; if (newton_pair || j < nlocal) { f[j][0] -= delx*fpair; f[j][1] -= dely*fpair; f[j][2] -= delz*fpair; } } } } } /* ---------------------------------------------------------------------- */ void PairLJCharmmCoulLong::compute_middle() { int i,j,ii,jj,inum,jnum,itype,jtype; double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,fpair; double rsq,r2inv,r6inv,forcecoul,forcelj,factor_coul,factor_lj; double philj,switch1,switch2; double rsw; int *ilist,*jlist,*numneigh,**firstneigh; double **x = atom->x; double **f = atom->f; double *q = atom->q; int *type = atom->type; int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; 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; - if (j < nall) factor_coul = factor_lj = 1.0; - else { - factor_coul = special_coul[j/nall]; - factor_lj = special_lj[j/nall]; - j %= nall; - } - delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; if (rsq < cut_out_off_sq && rsq > cut_in_off_sq) { r2inv = 1.0/rsq; forcecoul = qqrd2e * qtmp*q[j]*sqrt(r2inv); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*forcecoul; r6inv = r2inv*r2inv*r2inv; jtype = type[j]; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); if (rsq > cut_lj_innersq) { switch1 = (cut_ljsq-rsq) * (cut_ljsq-rsq) * (cut_ljsq + 2.0*rsq - 3.0*cut_lj_innersq) / denom_lj; switch2 = 12.0*rsq * (cut_ljsq-rsq) * (rsq-cut_lj_innersq) / denom_lj; philj = r6inv * (lj3[itype][jtype]*r6inv - lj4[itype][jtype]); forcelj = forcelj*switch1 + philj*switch2; } fpair = (forcecoul + factor_lj*forcelj) * r2inv; if (rsq < cut_in_on_sq) { rsw = (sqrt(rsq) - cut_in_off)/cut_in_diff; fpair *= rsw*rsw*(3.0 - 2.0*rsw); } if (rsq > cut_out_on_sq) { rsw = (sqrt(rsq) - cut_out_on)/cut_out_diff; fpair *= 1.0 + rsw*rsw*(2.0*rsw - 3.0); } f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; if (newton_pair || j < nlocal) { f[j][0] -= delx*fpair; f[j][1] -= dely*fpair; f[j][2] -= delz*fpair; } } } } } /* ---------------------------------------------------------------------- */ void PairLJCharmmCoulLong::compute_outer(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype,itable; double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair; double fraction,table; double r,r2inv,r6inv,forcecoul,forcelj,factor_coul,factor_lj; double grij,expm2,prefactor,t,erfc; double philj,switch1,switch2; double rsw; int *ilist,*jlist,*numneigh,**firstneigh; double rsq; evdwl = ecoul = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; double *q = atom->q; int *type = atom->type; int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; 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]; - - if (j < nall) factor_coul = factor_lj = 1.0; - else { - factor_coul = special_coul[j/nall]; - factor_lj = special_lj[j/nall]; - j %= nall; - } + factor_lj = special_lj[sbmask(j)]; + factor_coul = special_coul[sbmask(j)]; + j &= NEIGHMASK; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; jtype = type[j]; if (rsq < cut_bothsq) { r2inv = 1.0/rsq; if (rsq < cut_coulsq) { if (!ncoultablebits || rsq <= tabinnersq) { r = sqrt(rsq); grij = g_ewald * r; expm2 = exp(-grij*grij); t = 1.0 / (1.0 + EWALD_P*grij); erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2; prefactor = qqrd2e * qtmp*q[j]/r; forcecoul = prefactor * (erfc + EWALD_F*grij*expm2 - 1.0); if (rsq > cut_in_off_sq) { if (rsq < cut_in_on_sq) { rsw = (r - cut_in_off)/cut_in_diff; forcecoul += prefactor*rsw*rsw*(3.0 - 2.0*rsw); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor*rsw*rsw*(3.0 - 2.0*rsw); } else { forcecoul += prefactor; if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor; } } } else { union_int_float_t rsq_lookup; rsq_lookup.f = rsq; itable = rsq_lookup.i & ncoulmask; itable >>= ncoulshiftbits; fraction = (rsq_lookup.f - rtable[itable]) * drtable[itable]; table = ftable[itable] + fraction*dftable[itable]; forcecoul = qtmp*q[j] * table; if (factor_coul < 1.0) { table = ctable[itable] + fraction*dctable[itable]; prefactor = qtmp*q[j] * table; forcecoul -= (1.0-factor_coul)*prefactor; } } } else forcecoul = 0.0; if (rsq < cut_ljsq && rsq > cut_in_off_sq) { r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); if (rsq > cut_lj_innersq) { switch1 = (cut_ljsq-rsq) * (cut_ljsq-rsq) * (cut_ljsq + 2.0*rsq - 3.0*cut_lj_innersq) / denom_lj; switch2 = 12.0*rsq * (cut_ljsq-rsq) * (rsq-cut_lj_innersq) / denom_lj; philj = r6inv * (lj3[itype][jtype]*r6inv - lj4[itype][jtype]); forcelj = forcelj*switch1 + philj*switch2; } if (rsq < cut_in_on_sq) { rsw = (sqrt(rsq) - cut_in_off)/cut_in_diff; forcelj *= rsw*rsw*(3.0 - 2.0*rsw); } } else forcelj = 0.0; fpair = (forcecoul + forcelj) * r2inv; f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; if (newton_pair || j < nlocal) { f[j][0] -= delx*fpair; f[j][1] -= dely*fpair; f[j][2] -= delz*fpair; } if (eflag) { if (rsq < cut_coulsq) { if (!ncoultablebits || rsq <= tabinnersq) { ecoul = prefactor*erfc; if (factor_coul < 1.0) ecoul -= (1.0-factor_coul)*prefactor; } else { table = etable[itable] + fraction*detable[itable]; ecoul = qtmp*q[j] * table; if (factor_coul < 1.0) { table = ptable[itable] + fraction*dptable[itable]; prefactor = qtmp*q[j] * table; ecoul -= (1.0-factor_coul)*prefactor; } } } else ecoul = 0.0; if (rsq < cut_ljsq) { r6inv = r2inv*r2inv*r2inv; evdwl = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]); if (rsq > cut_lj_innersq) { switch1 = (cut_ljsq-rsq) * (cut_ljsq-rsq) * (cut_ljsq + 2.0*rsq - 3.0*cut_lj_innersq) / denom_lj; evdwl *= switch1; } evdwl *= factor_lj; } else evdwl = 0.0; } if (vflag) { if (rsq < cut_coulsq) { if (!ncoultablebits || rsq <= tabinnersq) { forcecoul = prefactor * (erfc + EWALD_F*grij*expm2); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor; } else { table = vtable[itable] + fraction*dvtable[itable]; forcecoul = qtmp*q[j] * table; if (factor_coul < 1.0) { table = ptable[itable] + fraction*dptable[itable]; prefactor = qtmp*q[j] * table; forcecoul -= (1.0-factor_coul)*prefactor; } } } else forcecoul = 0.0; if (rsq <= cut_in_off_sq) { r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); if (rsq > cut_lj_innersq) { switch1 = (cut_ljsq-rsq) * (cut_ljsq-rsq) * (cut_ljsq + 2.0*rsq - 3.0*cut_lj_innersq) / denom_lj; switch2 = 12.0*rsq * (cut_ljsq-rsq) * (rsq-cut_lj_innersq) / denom_lj; philj = r6inv * (lj3[itype][jtype]*r6inv - lj4[itype][jtype]); forcelj = forcelj*switch1 + philj*switch2; } } else if (rsq <= cut_in_on_sq) { forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); if (rsq > cut_lj_innersq) { switch1 = (cut_ljsq-rsq) * (cut_ljsq-rsq) * (cut_ljsq + 2.0*rsq - 3.0*cut_lj_innersq) / denom_lj; switch2 = 12.0*rsq * (cut_ljsq-rsq) * (rsq-cut_lj_innersq) / denom_lj; philj = r6inv * (lj3[itype][jtype]*r6inv - lj4[itype][jtype]); forcelj = forcelj*switch1 + philj*switch2; } } fpair = (forcecoul + factor_lj*forcelj) * r2inv; } if (evflag) ev_tally(i,j,nlocal,newton_pair, evdwl,ecoul,fpair,delx,dely,delz); } } } } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairLJCharmmCoulLong::allocate() { allocated = 1; int n = atom->ntypes; memory->create(setflag,n+1,n+1,"pair:setflag"); for (int i = 1; i <= n; i++) for (int j = i; j <= n; j++) setflag[i][j] = 0; memory->create(cutsq,n+1,n+1,"pair:cutsq"); memory->create(epsilon,n+1,n+1,"pair:epsilon"); memory->create(sigma,n+1,n+1,"pair:sigma"); memory->create(eps14,n+1,n+1,"pair:eps14"); memory->create(sigma14,n+1,n+1,"pair:sigma14"); memory->create(lj1,n+1,n+1,"pair:lj1"); memory->create(lj2,n+1,n+1,"pair:lj2"); memory->create(lj3,n+1,n+1,"pair:lj3"); memory->create(lj4,n+1,n+1,"pair:lj4"); memory->create(lj14_1,n+1,n+1,"pair:lj14_1"); memory->create(lj14_2,n+1,n+1,"pair:lj14_2"); memory->create(lj14_3,n+1,n+1,"pair:lj14_3"); memory->create(lj14_4,n+1,n+1,"pair:lj14_4"); } /* ---------------------------------------------------------------------- global settings unlike other pair styles, there are no individual pair settings that these override ------------------------------------------------------------------------- */ void PairLJCharmmCoulLong::settings(int narg, char **arg) { if (narg != 2 && narg != 3) error->all("Illegal pair_style command"); cut_lj_inner = force->numeric(arg[0]); cut_lj = force->numeric(arg[1]); if (narg == 2) cut_coul = cut_lj; else cut_coul = force->numeric(arg[2]); } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairLJCharmmCoulLong::coeff(int narg, char **arg) { if (narg != 4 && narg != 6) error->all("Illegal pair_coeff command"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(arg[2]); double sigma_one = force->numeric(arg[3]); double eps14_one = epsilon_one; double sigma14_one = sigma_one; if (narg == 6) { eps14_one = force->numeric(arg[4]); sigma14_one = force->numeric(arg[5]); } int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { epsilon[i][j] = epsilon_one; sigma[i][j] = sigma_one; eps14[i][j] = eps14_one; sigma14[i][j] = sigma14_one; setflag[i][j] = 1; count++; } } if (count == 0) error->all("Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairLJCharmmCoulLong::init_style() { if (!atom->q_flag) error->all("Pair style lj/charmm/coul/long requires atom attribute q"); // request regular or rRESPA neighbor lists int irequest; if (update->whichflag == 1 && strcmp(update->integrate_style,"respa") == 0) { int respa = 0; if (((Respa *) update->integrate)->level_inner >= 0) respa = 1; if (((Respa *) update->integrate)->level_middle >= 0) respa = 2; if (respa == 0) irequest = neighbor->request(this); else if (respa == 1) { irequest = neighbor->request(this); neighbor->requests[irequest]->id = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respainner = 1; irequest = neighbor->request(this); neighbor->requests[irequest]->id = 3; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respaouter = 1; } else { irequest = neighbor->request(this); neighbor->requests[irequest]->id = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respainner = 1; irequest = neighbor->request(this); neighbor->requests[irequest]->id = 2; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respamiddle = 1; irequest = neighbor->request(this); neighbor->requests[irequest]->id = 3; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respaouter = 1; } } else irequest = neighbor->request(this); // require cut_lj_inner < cut_lj if (cut_lj_inner >= cut_lj) error->all("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 (strcmp(update->integrate_style,"respa") == 0 && ((Respa *) update->integrate)->level_inner >= 0) { cut_respa = ((Respa *) update->integrate)->cutoff; if (MIN(cut_lj,cut_coul) < cut_respa[3]) error->all("Pair cutoff < Respa interior cutoff"); if (cut_lj_inner < cut_respa[1]) error->all("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("Pair style is incompatible with KSpace style"); g_ewald = force->kspace->g_ewald; // setup force tables if (ncoultablebits) init_tables(); } /* ---------------------------------------------------------------------- neighbor callback to inform pair style of neighbor list to use regular or rRESPA ------------------------------------------------------------------------- */ void PairLJCharmmCoulLong::init_list(int id, NeighList *ptr) { if (id == 0) list = ptr; else if (id == 1) listinner = ptr; else if (id == 2) listmiddle = ptr; else if (id == 3) listouter = ptr; } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairLJCharmmCoulLong::init_one(int i, int j) { if (setflag[i][j] == 0) { epsilon[i][j] = mix_energy(epsilon[i][i],epsilon[j][j], sigma[i][i],sigma[j][j]); sigma[i][j] = mix_distance(sigma[i][i],sigma[j][j]); eps14[i][j] = mix_energy(eps14[i][i],eps14[j][j], sigma14[i][i],sigma14[j][j]); sigma14[i][j] = mix_distance(sigma14[i][i],sigma14[j][j]); } double cut = MAX(cut_lj,cut_coul); lj1[i][j] = 48.0 * epsilon[i][j] * pow(sigma[i][j],12.0); lj2[i][j] = 24.0 * epsilon[i][j] * pow(sigma[i][j],6.0); lj3[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],12.0); lj4[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],6.0); lj14_1[i][j] = 48.0 * eps14[i][j] * pow(sigma14[i][j],12.0); lj14_2[i][j] = 24.0 * eps14[i][j] * pow(sigma14[i][j],6.0); lj14_3[i][j] = 4.0 * eps14[i][j] * pow(sigma14[i][j],12.0); lj14_4[i][j] = 4.0 * eps14[i][j] * pow(sigma14[i][j],6.0); lj1[j][i] = lj1[i][j]; lj2[j][i] = lj2[i][j]; lj3[j][i] = lj3[i][j]; lj4[j][i] = lj4[i][j]; lj14_1[j][i] = lj14_1[i][j]; lj14_2[j][i] = lj14_2[i][j]; lj14_3[j][i] = lj14_3[i][j]; lj14_4[j][i] = lj14_4[i][j]; return cut; } /* ---------------------------------------------------------------------- setup force tables used in compute routines ------------------------------------------------------------------------- */ void PairLJCharmmCoulLong::init_tables() { int masklo,maskhi; double r,grij,expm2,derfc,rsw; double qqrd2e = force->qqrd2e; tabinnersq = tabinner*tabinner; init_bitmap(tabinner,cut_coul,ncoultablebits, masklo,maskhi,ncoulmask,ncoulshiftbits); int ntable = 1; for (int i = 0; i < ncoultablebits; i++) ntable *= 2; // linear lookup tables of length N = 2^ncoultablebits // stored value = value at lower edge of bin // d values = delta from lower edge to upper edge of bin if (ftable) free_tables(); memory->create(rtable,ntable,"pair:rtable"); memory->create(ftable,ntable,"pair:ftable"); memory->create(ctable,ntable,"pair:ctable"); memory->create(etable,ntable,"pair:etable"); memory->create(drtable,ntable,"pair:drtable"); memory->create(dftable,ntable,"pair:dftable"); memory->create(dctable,ntable,"pair:dctable"); memory->create(detable,ntable,"pair:detable"); if (cut_respa == NULL) { vtable = ptable = dvtable = dptable = NULL; } else { memory->create(vtable,ntable,"pair:vtable"); memory->create(ptable,ntable,"pair:ptable"); memory->create(dvtable,ntable,"pair:dvtable"); memory->create(dptable,ntable,"pair:dptable"); } union_int_float_t rsq_lookup; union_int_float_t minrsq_lookup; int itablemin; minrsq_lookup.i = 0 << ncoulshiftbits; minrsq_lookup.i |= maskhi; for (int i = 0; i < ntable; i++) { rsq_lookup.i = i << ncoulshiftbits; rsq_lookup.i |= masklo; if (rsq_lookup.f < tabinnersq) { rsq_lookup.i = i << ncoulshiftbits; rsq_lookup.i |= maskhi; } r = sqrtf(rsq_lookup.f); grij = g_ewald * r; expm2 = exp(-grij*grij); derfc = erfc(grij); if (cut_respa == NULL) { rtable[i] = rsq_lookup.f; ftable[i] = qqrd2e/r * (derfc + EWALD_F*grij*expm2); ctable[i] = qqrd2e/r; etable[i] = qqrd2e/r * derfc; } else { rtable[i] = rsq_lookup.f; ftable[i] = qqrd2e/r * (derfc + EWALD_F*grij*expm2 - 1.0); ctable[i] = 0.0; etable[i] = qqrd2e/r * derfc; ptable[i] = qqrd2e/r; vtable[i] = qqrd2e/r * (derfc + EWALD_F*grij*expm2); if (rsq_lookup.f > cut_respa[2]*cut_respa[2]) { if (rsq_lookup.f < cut_respa[3]*cut_respa[3]) { rsw = (r - cut_respa[2])/(cut_respa[3] - cut_respa[2]); ftable[i] += qqrd2e/r * rsw*rsw*(3.0 - 2.0*rsw); ctable[i] = qqrd2e/r * rsw*rsw*(3.0 - 2.0*rsw); } else { ftable[i] = qqrd2e/r * (derfc + EWALD_F*grij*expm2); ctable[i] = qqrd2e/r; } } } minrsq_lookup.f = MIN(minrsq_lookup.f,rsq_lookup.f); } tabinnersq = minrsq_lookup.f; int ntablem1 = ntable - 1; for (int i = 0; i < ntablem1; i++) { drtable[i] = 1.0/(rtable[i+1] - rtable[i]); dftable[i] = ftable[i+1] - ftable[i]; dctable[i] = ctable[i+1] - ctable[i]; detable[i] = etable[i+1] - etable[i]; } if (cut_respa) { for (int i = 0; i < ntablem1; i++) { dvtable[i] = vtable[i+1] - vtable[i]; dptable[i] = ptable[i+1] - ptable[i]; } } // get the delta values for the last table entries // tables are connected periodically between 0 and ntablem1 drtable[ntablem1] = 1.0/(rtable[0] - rtable[ntablem1]); dftable[ntablem1] = ftable[0] - ftable[ntablem1]; dctable[ntablem1] = ctable[0] - ctable[ntablem1]; detable[ntablem1] = etable[0] - etable[ntablem1]; if (cut_respa) { dvtable[ntablem1] = vtable[0] - vtable[ntablem1]; dptable[ntablem1] = ptable[0] - ptable[ntablem1]; } // get the correct delta values at itablemax // smallest r is in bin itablemin // largest r is in bin itablemax, which is itablemin-1, // or ntablem1 if itablemin=0 // deltas at itablemax only needed if corresponding rsq < cut*cut // if so, compute deltas between rsq and cut*cut double f_tmp,c_tmp,e_tmp,p_tmp,v_tmp; itablemin = minrsq_lookup.i & ncoulmask; itablemin >>= ncoulshiftbits; int itablemax = itablemin - 1; if (itablemin == 0) itablemax = ntablem1; rsq_lookup.i = itablemax << ncoulshiftbits; rsq_lookup.i |= maskhi; if (rsq_lookup.f < cut_coulsq) { rsq_lookup.f = cut_coulsq; r = sqrtf(rsq_lookup.f); grij = g_ewald * r; expm2 = exp(-grij*grij); derfc = erfc(grij); if (cut_respa == NULL) { f_tmp = qqrd2e/r * (derfc + EWALD_F*grij*expm2); c_tmp = qqrd2e/r; e_tmp = qqrd2e/r * derfc; } else { f_tmp = qqrd2e/r * (derfc + EWALD_F*grij*expm2 - 1.0); c_tmp = 0.0; e_tmp = qqrd2e/r * derfc; p_tmp = qqrd2e/r; v_tmp = qqrd2e/r * (derfc + EWALD_F*grij*expm2); if (rsq_lookup.f > cut_respa[2]*cut_respa[2]) { if (rsq_lookup.f < cut_respa[3]*cut_respa[3]) { rsw = (r - cut_respa[2])/(cut_respa[3] - cut_respa[2]); f_tmp += qqrd2e/r * rsw*rsw*(3.0 - 2.0*rsw); c_tmp = qqrd2e/r * rsw*rsw*(3.0 - 2.0*rsw); } else { f_tmp = qqrd2e/r * (derfc + EWALD_F*grij*expm2); c_tmp = qqrd2e/r; } } } drtable[itablemax] = 1.0/(rsq_lookup.f - rtable[itablemax]); dftable[itablemax] = f_tmp - ftable[itablemax]; dctable[itablemax] = c_tmp - ctable[itablemax]; detable[itablemax] = e_tmp - etable[itablemax]; if (cut_respa) { dvtable[itablemax] = v_tmp - vtable[itablemax]; dptable[itablemax] = p_tmp - ptable[itablemax]; } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJCharmmCoulLong::write_restart(FILE *fp) { write_restart_settings(fp); int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { fwrite(&setflag[i][j],sizeof(int),1,fp); if (setflag[i][j]) { fwrite(&epsilon[i][j],sizeof(double),1,fp); fwrite(&sigma[i][j],sizeof(double),1,fp); fwrite(&eps14[i][j],sizeof(double),1,fp); fwrite(&sigma14[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJCharmmCoulLong::read_restart(FILE *fp) { read_restart_settings(fp); allocate(); int i,j; int me = comm->me; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp); MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world); if (setflag[i][j]) { if (me == 0) { fread(&epsilon[i][j],sizeof(double),1,fp); fread(&sigma[i][j],sizeof(double),1,fp); fread(&eps14[i][j],sizeof(double),1,fp); fread(&sigma14[i][j],sizeof(double),1,fp); } MPI_Bcast(&epsilon[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&eps14[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&sigma14[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJCharmmCoulLong::write_restart_settings(FILE *fp) { fwrite(&cut_lj_inner,sizeof(double),1,fp); fwrite(&cut_lj,sizeof(double),1,fp); fwrite(&cut_coul,sizeof(double),1,fp); fwrite(&offset_flag,sizeof(int),1,fp); fwrite(&mix_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJCharmmCoulLong::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&cut_lj_inner,sizeof(double),1,fp); fread(&cut_lj,sizeof(double),1,fp); fread(&cut_coul,sizeof(double),1,fp); fread(&offset_flag,sizeof(int),1,fp); fread(&mix_flag,sizeof(int),1,fp); } MPI_Bcast(&cut_lj_inner,1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_lj,1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_coul,1,MPI_DOUBLE,0,world); MPI_Bcast(&offset_flag,1,MPI_INT,0,world); MPI_Bcast(&mix_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- free memory for tables used in pair computations ------------------------------------------------------------------------- */ void PairLJCharmmCoulLong::free_tables() { memory->destroy(rtable); memory->destroy(drtable); memory->destroy(ftable); memory->destroy(dftable); memory->destroy(ctable); memory->destroy(dctable); memory->destroy(etable); memory->destroy(detable); memory->destroy(vtable); memory->destroy(dvtable); memory->destroy(ptable); memory->destroy(dptable); } /* ---------------------------------------------------------------------- */ double PairLJCharmmCoulLong::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r2inv,r6inv,r,grij,expm2,t,erfc,prefactor; double switch1,switch2,fraction,table,forcecoul,forcelj,phicoul,philj; int itable; r2inv = 1.0/rsq; if (rsq < cut_coulsq) { if (!ncoultablebits || rsq <= tabinnersq) { r = sqrt(rsq); grij = g_ewald * r; expm2 = exp(-grij*grij); t = 1.0 / (1.0 + EWALD_P*grij); erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2; prefactor = force->qqrd2e * atom->q[i]*atom->q[j]/r; forcecoul = prefactor * (erfc + EWALD_F*grij*expm2); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor; } else { union_int_float_t rsq_lookup; rsq_lookup.f = rsq; itable = rsq_lookup.i & ncoulmask; itable >>= ncoulshiftbits; fraction = (rsq_lookup.f - rtable[itable]) * drtable[itable]; table = ftable[itable] + fraction*dftable[itable]; forcecoul = atom->q[i]*atom->q[j] * table; if (factor_coul < 1.0) { table = ctable[itable] + fraction*dctable[itable]; prefactor = atom->q[i]*atom->q[j] * table; forcecoul -= (1.0-factor_coul)*prefactor; } } } else forcecoul = 0.0; if (rsq < cut_ljsq) { r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); if (rsq > cut_lj_innersq) { switch1 = (cut_ljsq-rsq) * (cut_ljsq-rsq) * (cut_ljsq + 2.0*rsq - 3.0*cut_lj_innersq) / denom_lj; switch2 = 12.0*rsq * (cut_ljsq-rsq) * (rsq-cut_lj_innersq) / denom_lj; philj = r6inv * (lj3[itype][jtype]*r6inv - lj4[itype][jtype]); forcelj = forcelj*switch1 + philj*switch2; } } else forcelj = 0.0; fforce = (forcecoul + factor_lj*forcelj) * r2inv; double eng = 0.0; if (rsq < cut_coulsq) { if (!ncoultablebits || rsq <= tabinnersq) phicoul = prefactor*erfc; else { table = etable[itable] + fraction*detable[itable]; phicoul = atom->q[i]*atom->q[j] * table; } if (factor_coul < 1.0) phicoul -= (1.0-factor_coul)*prefactor; eng += phicoul; } if (rsq < cut_ljsq) { philj = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]); if (rsq > cut_lj_innersq) { switch1 = (cut_ljsq-rsq) * (cut_ljsq-rsq) * (cut_ljsq + 2.0*rsq - 3.0*cut_lj_innersq) / denom_lj; philj *= switch1; } eng += factor_lj*philj; } return eng; } /* ---------------------------------------------------------------------- */ void *PairLJCharmmCoulLong::extract(char *str, int &dim) { 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 527329357..26c8cb8ce 100644 --- a/src/KSPACE/pair_lj_cut_coul_long.cpp +++ b/src/KSPACE/pair_lj_cut_coul_long.cpp @@ -1,1152 +1,1132 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author: Paul Crozier (SNL) ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "pair_lj_cut_coul_long.h" #include "atom.h" #include "comm.h" #include "force.h" #include "kspace.h" #include "update.h" #include "integrate.h" #include "respa.h" #include "neighbor.h" #include "neigh_list.h" #include "neigh_request.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define EWALD_F 1.12837917 #define EWALD_P 0.3275911 #define A1 0.254829592 #define A2 -0.284496736 #define A3 1.421413741 #define A4 -1.453152027 #define A5 1.061405429 /* ---------------------------------------------------------------------- */ PairLJCutCoulLong::PairLJCutCoulLong(LAMMPS *lmp) : Pair(lmp) { respa_enable = 1; ftable = NULL; } /* ---------------------------------------------------------------------- */ PairLJCutCoulLong::~PairLJCutCoulLong() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut_lj); memory->destroy(cut_ljsq); memory->destroy(epsilon); memory->destroy(sigma); memory->destroy(lj1); memory->destroy(lj2); memory->destroy(lj3); memory->destroy(lj4); memory->destroy(offset); } if (ftable) free_tables(); } /* ---------------------------------------------------------------------- */ void PairLJCutCoulLong::compute(int eflag, int vflag) { - int i,j,ii,jj,inum,jnum,itype,jtype,itable; + 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; - int nall = nlocal + atom->nghost; 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]; - - if (j < nall) factor_coul = factor_lj = 1.0; - else { - factor_coul = special_coul[j/nall]; - factor_lj = special_lj[j/nall]; - j %= nall; - } + 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_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; - int nall = nlocal + atom->nghost; 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]; - - if (j < nall) factor_coul = factor_lj = 1.0; - else { - factor_coul = special_coul[j/nall]; - factor_lj = special_lj[j/nall]; - j %= nall; - } + 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; - int nall = nlocal + atom->nghost; 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]; - - if (j < nall) factor_coul = factor_lj = 1.0; - else { - factor_coul = special_coul[j/nall]; - factor_lj = special_lj[j/nall]; - j %= nall; - } + 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; - int nall = nlocal + atom->nghost; 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]; - - if (j < nall) factor_coul = factor_lj = 1.0; - else { - factor_coul = special_coul[j/nall]; - factor_lj = special_lj[j/nall]; - j %= nall; - } + factor_lj = special_lj[sbmask(j)]; + factor_coul = special_coul[sbmask(j)]; + j &= NEIGHMASK; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; jtype = type[j]; if (rsq < cutsq[itype][jtype]) { r2inv = 1.0/rsq; if (rsq < cut_coulsq) { if (!ncoultablebits || rsq <= tabinnersq) { r = sqrt(rsq); grij = g_ewald * r; expm2 = exp(-grij*grij); t = 1.0 / (1.0 + EWALD_P*grij); erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2; prefactor = qqrd2e * qtmp*q[j]/r; forcecoul = prefactor * (erfc + EWALD_F*grij*expm2 - 1.0); if (rsq > cut_in_off_sq) { if (rsq < cut_in_on_sq) { rsw = (r - cut_in_off)/cut_in_diff; forcecoul += prefactor*rsw*rsw*(3.0 - 2.0*rsw); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor*rsw*rsw*(3.0 - 2.0*rsw); } else { forcecoul += prefactor; if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor; } } } else { union_int_float_t rsq_lookup; rsq_lookup.f = rsq; itable = rsq_lookup.i & ncoulmask; itable >>= ncoulshiftbits; fraction = (rsq_lookup.f - rtable[itable]) * drtable[itable]; table = ftable[itable] + fraction*dftable[itable]; forcecoul = qtmp*q[j] * table; if (factor_coul < 1.0) { table = ctable[itable] + fraction*dctable[itable]; prefactor = qtmp*q[j] * table; forcecoul -= (1.0-factor_coul)*prefactor; } } } else forcecoul = 0.0; if (rsq < cut_ljsq[itype][jtype] && rsq > cut_in_off_sq) { r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); if (rsq < cut_in_on_sq) { rsw = (sqrt(rsq) - cut_in_off)/cut_in_diff; forcelj *= rsw*rsw*(3.0 - 2.0*rsw); } } else forcelj = 0.0; fpair = (forcecoul + forcelj) * r2inv; f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; if (newton_pair || j < nlocal) { f[j][0] -= delx*fpair; f[j][1] -= dely*fpair; f[j][2] -= delz*fpair; } if (eflag) { if (rsq < cut_coulsq) { if (!ncoultablebits || rsq <= tabinnersq) { ecoul = prefactor*erfc; if (factor_coul < 1.0) ecoul -= (1.0-factor_coul)*prefactor; } else { table = etable[itable] + fraction*detable[itable]; ecoul = qtmp*q[j] * table; if (factor_coul < 1.0) { table = ptable[itable] + fraction*dptable[itable]; prefactor = qtmp*q[j] * table; ecoul -= (1.0-factor_coul)*prefactor; } } } else ecoul = 0.0; if (rsq < cut_ljsq[itype][jtype]) { r6inv = r2inv*r2inv*r2inv; evdwl = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]) - offset[itype][jtype]; evdwl *= factor_lj; } else evdwl = 0.0; } if (vflag) { if (rsq < cut_coulsq) { if (!ncoultablebits || rsq <= tabinnersq) { forcecoul = prefactor * (erfc + EWALD_F*grij*expm2); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor; } else { table = vtable[itable] + fraction*dvtable[itable]; forcecoul = qtmp*q[j] * table; if (factor_coul < 1.0) { table = ptable[itable] + fraction*dptable[itable]; prefactor = qtmp*q[j] * table; forcecoul -= (1.0-factor_coul)*prefactor; } } } else forcecoul = 0.0; if (rsq <= cut_in_off_sq) { r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); } else if (rsq <= cut_in_on_sq) forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); fpair = (forcecoul + factor_lj*forcelj) * r2inv; } if (evflag) ev_tally(i,j,nlocal,newton_pair, evdwl,ecoul,fpair,delx,dely,delz); } } } } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairLJCutCoulLong::allocate() { allocated = 1; int n = atom->ntypes; memory->create(setflag,n+1,n+1,"pair:setflag"); for (int i = 1; i <= n; i++) for (int j = i; j <= n; j++) setflag[i][j] = 0; memory->create(cutsq,n+1,n+1,"pair:cutsq"); memory->create(cut_lj,n+1,n+1,"pair:cut_lj"); memory->create(cut_ljsq,n+1,n+1,"pair:cut_ljsq"); memory->create(epsilon,n+1,n+1,"pair:epsilon"); memory->create(sigma,n+1,n+1,"pair:sigma"); memory->create(lj1,n+1,n+1,"pair:lj1"); memory->create(lj2,n+1,n+1,"pair:lj2"); memory->create(lj3,n+1,n+1,"pair:lj3"); memory->create(lj4,n+1,n+1,"pair:lj4"); memory->create(offset,n+1,n+1,"pair:offset"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairLJCutCoulLong::settings(int narg, char **arg) { if (narg < 1 || narg > 2) error->all("Illegal pair_style command"); cut_lj_global = force->numeric(arg[0]); if (narg == 1) cut_coul = cut_lj_global; else cut_coul = force->numeric(arg[1]); // reset cutoffs that have been explicitly set if (allocated) { int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i+1; j <= atom->ntypes; j++) if (setflag[i][j]) cut_lj[i][j] = cut_lj_global; } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairLJCutCoulLong::coeff(int narg, char **arg) { if (narg < 4 || narg > 5) error->all("Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(arg[2]); double sigma_one = force->numeric(arg[3]); double cut_lj_one = cut_lj_global; if (narg == 5) cut_lj_one = force->numeric(arg[4]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { epsilon[i][j] = epsilon_one; sigma[i][j] = sigma_one; cut_lj[i][j] = cut_lj_one; setflag[i][j] = 1; count++; } } if (count == 0) error->all("Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairLJCutCoulLong::init_style() { if (!atom->q_flag) error->all("Pair style lj/cut/coul/long requires atom attribute q"); // request regular or rRESPA neighbor lists int irequest; if (update->whichflag == 1 && strcmp(update->integrate_style,"respa") == 0) { int respa = 0; if (((Respa *) update->integrate)->level_inner >= 0) respa = 1; if (((Respa *) update->integrate)->level_middle >= 0) respa = 2; if (respa == 0) irequest = neighbor->request(this); else if (respa == 1) { irequest = neighbor->request(this); neighbor->requests[irequest]->id = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respainner = 1; irequest = neighbor->request(this); neighbor->requests[irequest]->id = 3; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respaouter = 1; } else { irequest = neighbor->request(this); neighbor->requests[irequest]->id = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respainner = 1; irequest = neighbor->request(this); neighbor->requests[irequest]->id = 2; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respamiddle = 1; irequest = neighbor->request(this); neighbor->requests[irequest]->id = 3; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respaouter = 1; } } else irequest = neighbor->request(this); cut_coulsq = cut_coul * cut_coul; // set rRESPA cutoffs if (strcmp(update->integrate_style,"respa") == 0 && ((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("Pair style is incompatible with KSpace style"); g_ewald = force->kspace->g_ewald; // setup force tables if (ncoultablebits) init_tables(); } /* ---------------------------------------------------------------------- neighbor callback to inform pair style of neighbor list to use regular or rRESPA ------------------------------------------------------------------------- */ void PairLJCutCoulLong::init_list(int id, NeighList *ptr) { if (id == 0) list = ptr; else if (id == 1) listinner = ptr; else if (id == 2) listmiddle = ptr; else if (id == 3) listouter = ptr; } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairLJCutCoulLong::init_one(int i, int j) { if (setflag[i][j] == 0) { epsilon[i][j] = mix_energy(epsilon[i][i],epsilon[j][j], sigma[i][i],sigma[j][j]); sigma[i][j] = mix_distance(sigma[i][i],sigma[j][j]); cut_lj[i][j] = mix_distance(cut_lj[i][i],cut_lj[j][j]); } double cut = MAX(cut_lj[i][j],cut_coul); cut_ljsq[i][j] = cut_lj[i][j] * cut_lj[i][j]; lj1[i][j] = 48.0 * epsilon[i][j] * pow(sigma[i][j],12.0); lj2[i][j] = 24.0 * epsilon[i][j] * pow(sigma[i][j],6.0); lj3[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],12.0); lj4[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],6.0); if (offset_flag) { double ratio = sigma[i][j] / cut_lj[i][j]; offset[i][j] = 4.0 * epsilon[i][j] * (pow(ratio,12.0) - pow(ratio,6.0)); } else offset[i][j] = 0.0; cut_ljsq[j][i] = cut_ljsq[i][j]; lj1[j][i] = lj1[i][j]; lj2[j][i] = lj2[i][j]; lj3[j][i] = lj3[i][j]; lj4[j][i] = lj4[i][j]; offset[j][i] = offset[i][j]; // check interior rRESPA cutoff if (cut_respa && MIN(cut_lj[i][j],cut_coul) < cut_respa[3]) error->all("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 PI = 4.0*atan(1.0); 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*PI*all[0]*all[1]*epsilon[i][j] * sig6 * (sig6 - 3.0*rc6) / (9.0*rc9); ptail_ij = 16.0*PI*all[0]*all[1]*epsilon[i][j] * sig6 * (2.0*sig6 - 3.0*rc6) / (9.0*rc9); } return cut; } /* ---------------------------------------------------------------------- setup force tables used in compute routines ------------------------------------------------------------------------- */ void PairLJCutCoulLong::init_tables() { int masklo,maskhi; double r,grij,expm2,derfc,rsw; double qqrd2e = force->qqrd2e; tabinnersq = tabinner*tabinner; init_bitmap(tabinner,cut_coul,ncoultablebits, masklo,maskhi,ncoulmask,ncoulshiftbits); int ntable = 1; for (int i = 0; i < ncoultablebits; i++) ntable *= 2; // linear lookup tables of length N = 2^ncoultablebits // stored value = value at lower edge of bin // d values = delta from lower edge to upper edge of bin if (ftable) free_tables(); memory->create(rtable,ntable,"pair:rtable"); memory->create(ftable,ntable,"pair:ftable"); memory->create(ctable,ntable,"pair:ctable"); memory->create(etable,ntable,"pair:etable"); memory->create(drtable,ntable,"pair:drtable"); memory->create(dftable,ntable,"pair:dftable"); memory->create(dctable,ntable,"pair:dctable"); memory->create(detable,ntable,"pair:detable"); if (cut_respa == NULL) { vtable = ptable = dvtable = dptable = NULL; } else { memory->create(vtable,ntable*sizeof(double),"pair:vtable"); memory->create(ptable,ntable*sizeof(double),"pair:ptable"); memory->create(dvtable,ntable*sizeof(double),"pair:dvtable"); memory->create(dptable,ntable*sizeof(double),"pair:dptable"); } union_int_float_t rsq_lookup; union_int_float_t minrsq_lookup; int itablemin; minrsq_lookup.i = 0 << ncoulshiftbits; minrsq_lookup.i |= maskhi; for (int i = 0; i < ntable; i++) { rsq_lookup.i = i << ncoulshiftbits; rsq_lookup.i |= masklo; if (rsq_lookup.f < tabinnersq) { rsq_lookup.i = i << ncoulshiftbits; rsq_lookup.i |= maskhi; } r = sqrtf(rsq_lookup.f); grij = g_ewald * r; expm2 = exp(-grij*grij); derfc = erfc(grij); if (cut_respa == NULL) { rtable[i] = rsq_lookup.f; ftable[i] = qqrd2e/r * (derfc + EWALD_F*grij*expm2); ctable[i] = qqrd2e/r; etable[i] = qqrd2e/r * derfc; } else { rtable[i] = rsq_lookup.f; ftable[i] = qqrd2e/r * (derfc + EWALD_F*grij*expm2 - 1.0); ctable[i] = 0.0; etable[i] = qqrd2e/r * derfc; ptable[i] = qqrd2e/r; vtable[i] = qqrd2e/r * (derfc + EWALD_F*grij*expm2); if (rsq_lookup.f > cut_respa[2]*cut_respa[2]) { if (rsq_lookup.f < cut_respa[3]*cut_respa[3]) { rsw = (r - cut_respa[2])/(cut_respa[3] - cut_respa[2]); ftable[i] += qqrd2e/r * rsw*rsw*(3.0 - 2.0*rsw); ctable[i] = qqrd2e/r * rsw*rsw*(3.0 - 2.0*rsw); } else { ftable[i] = qqrd2e/r * (derfc + EWALD_F*grij*expm2); ctable[i] = qqrd2e/r; } } } minrsq_lookup.f = MIN(minrsq_lookup.f,rsq_lookup.f); } tabinnersq = minrsq_lookup.f; int ntablem1 = ntable - 1; for (int i = 0; i < ntablem1; i++) { drtable[i] = 1.0/(rtable[i+1] - rtable[i]); dftable[i] = ftable[i+1] - ftable[i]; dctable[i] = ctable[i+1] - ctable[i]; detable[i] = etable[i+1] - etable[i]; } if (cut_respa) { for (int i = 0; i < ntablem1; i++) { dvtable[i] = vtable[i+1] - vtable[i]; dptable[i] = ptable[i+1] - ptable[i]; } } // get the delta values for the last table entries // tables are connected periodically between 0 and ntablem1 drtable[ntablem1] = 1.0/(rtable[0] - rtable[ntablem1]); dftable[ntablem1] = ftable[0] - ftable[ntablem1]; dctable[ntablem1] = ctable[0] - ctable[ntablem1]; detable[ntablem1] = etable[0] - etable[ntablem1]; if (cut_respa) { dvtable[ntablem1] = vtable[0] - vtable[ntablem1]; dptable[ntablem1] = ptable[0] - ptable[ntablem1]; } // get the correct delta values at itablemax // smallest r is in bin itablemin // largest r is in bin itablemax, which is itablemin-1, // or ntablem1 if itablemin=0 // deltas at itablemax only needed if corresponding rsq < cut*cut // if so, compute deltas between rsq and cut*cut double f_tmp,c_tmp,e_tmp,p_tmp,v_tmp; itablemin = minrsq_lookup.i & ncoulmask; itablemin >>= ncoulshiftbits; int itablemax = itablemin - 1; if (itablemin == 0) itablemax = ntablem1; rsq_lookup.i = itablemax << ncoulshiftbits; rsq_lookup.i |= maskhi; if (rsq_lookup.f < cut_coulsq) { rsq_lookup.f = cut_coulsq; r = sqrtf(rsq_lookup.f); grij = g_ewald * r; expm2 = exp(-grij*grij); derfc = erfc(grij); if (cut_respa == NULL) { f_tmp = qqrd2e/r * (derfc + EWALD_F*grij*expm2); c_tmp = qqrd2e/r; e_tmp = qqrd2e/r * derfc; } else { f_tmp = qqrd2e/r * (derfc + EWALD_F*grij*expm2 - 1.0); c_tmp = 0.0; e_tmp = qqrd2e/r * derfc; p_tmp = qqrd2e/r; v_tmp = qqrd2e/r * (derfc + EWALD_F*grij*expm2); if (rsq_lookup.f > cut_respa[2]*cut_respa[2]) { if (rsq_lookup.f < cut_respa[3]*cut_respa[3]) { rsw = (r - cut_respa[2])/(cut_respa[3] - cut_respa[2]); f_tmp += qqrd2e/r * rsw*rsw*(3.0 - 2.0*rsw); c_tmp = qqrd2e/r * rsw*rsw*(3.0 - 2.0*rsw); } else { f_tmp = qqrd2e/r * (derfc + EWALD_F*grij*expm2); c_tmp = qqrd2e/r; } } } drtable[itablemax] = 1.0/(rsq_lookup.f - rtable[itablemax]); dftable[itablemax] = f_tmp - ftable[itablemax]; dctable[itablemax] = c_tmp - ctable[itablemax]; detable[itablemax] = e_tmp - etable[itablemax]; if (cut_respa) { dvtable[itablemax] = v_tmp - vtable[itablemax]; dptable[itablemax] = p_tmp - ptable[itablemax]; } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJCutCoulLong::write_restart(FILE *fp) { write_restart_settings(fp); int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { fwrite(&setflag[i][j],sizeof(int),1,fp); if (setflag[i][j]) { fwrite(&epsilon[i][j],sizeof(double),1,fp); fwrite(&sigma[i][j],sizeof(double),1,fp); fwrite(&cut_lj[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJCutCoulLong::read_restart(FILE *fp) { read_restart_settings(fp); allocate(); int i,j; int me = comm->me; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp); MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world); if (setflag[i][j]) { if (me == 0) { fread(&epsilon[i][j],sizeof(double),1,fp); fread(&sigma[i][j],sizeof(double),1,fp); fread(&cut_lj[i][j],sizeof(double),1,fp); } MPI_Bcast(&epsilon[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_lj[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJCutCoulLong::write_restart_settings(FILE *fp) { fwrite(&cut_lj_global,sizeof(double),1,fp); fwrite(&cut_coul,sizeof(double),1,fp); fwrite(&offset_flag,sizeof(int),1,fp); fwrite(&mix_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJCutCoulLong::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&cut_lj_global,sizeof(double),1,fp); fread(&cut_coul,sizeof(double),1,fp); fread(&offset_flag,sizeof(int),1,fp); fread(&mix_flag,sizeof(int),1,fp); } MPI_Bcast(&cut_lj_global,1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_coul,1,MPI_DOUBLE,0,world); MPI_Bcast(&offset_flag,1,MPI_INT,0,world); MPI_Bcast(&mix_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- free memory for tables used in pair computations ------------------------------------------------------------------------- */ void PairLJCutCoulLong::free_tables() { memory->destroy(rtable); memory->destroy(drtable); memory->destroy(ftable); memory->destroy(dftable); memory->destroy(ctable); memory->destroy(dctable); memory->destroy(etable); memory->destroy(detable); memory->destroy(vtable); memory->destroy(dvtable); memory->destroy(ptable); memory->destroy(dptable); } /* ---------------------------------------------------------------------- */ double PairLJCutCoulLong::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r2inv,r6inv,r,grij,expm2,t,erfc,prefactor; double fraction,table,forcecoul,forcelj,phicoul,philj; int itable; r2inv = 1.0/rsq; if (rsq < cut_coulsq) { if (!ncoultablebits || rsq <= tabinnersq) { r = sqrt(rsq); grij = g_ewald * r; expm2 = exp(-grij*grij); t = 1.0 / (1.0 + EWALD_P*grij); erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2; prefactor = force->qqrd2e * atom->q[i]*atom->q[j]/r; forcecoul = prefactor * (erfc + EWALD_F*grij*expm2); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor; } else { union_int_float_t rsq_lookup_single; rsq_lookup_single.f = rsq; itable = rsq_lookup_single.i & ncoulmask; itable >>= ncoulshiftbits; fraction = (rsq_lookup_single.f - rtable[itable]) * drtable[itable]; table = ftable[itable] + fraction*dftable[itable]; forcecoul = atom->q[i]*atom->q[j] * table; if (factor_coul < 1.0) { table = ctable[itable] + fraction*dctable[itable]; prefactor = atom->q[i]*atom->q[j] * table; forcecoul -= (1.0-factor_coul)*prefactor; } } } else forcecoul = 0.0; if (rsq < cut_ljsq[itype][jtype]) { r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); } else forcelj = 0.0; fforce = (forcecoul + factor_lj*forcelj) * r2inv; double eng = 0.0; if (rsq < cut_coulsq) { if (!ncoultablebits || rsq <= tabinnersq) phicoul = prefactor*erfc; else { table = etable[itable] + fraction*detable[itable]; phicoul = atom->q[i]*atom->q[j] * table; } if (factor_coul < 1.0) phicoul -= (1.0-factor_coul)*prefactor; eng += phicoul; } if (rsq < cut_ljsq[itype][jtype]) { philj = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]) - offset[itype][jtype]; eng += factor_lj*philj; } return eng; } /* ---------------------------------------------------------------------- */ void *PairLJCutCoulLong::extract(char *str, int &dim) { dim = 0; if (strcmp(str,"cut_coul") == 0) return (void *) &cut_coul; return NULL; } diff --git a/src/KSPACE/pair_lj_cut_coul_long_tip4p.cpp b/src/KSPACE/pair_lj_cut_coul_long_tip4p.cpp index 73c180b79..1aab94395 100644 --- a/src/KSPACE/pair_lj_cut_coul_long_tip4p.cpp +++ b/src/KSPACE/pair_lj_cut_coul_long_tip4p.cpp @@ -1,509 +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. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing authors: Amalie Frischknecht and Ahmed Ismail (SNL) ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "pair_lj_cut_coul_long_tip4p.h" #include "angle.h" #include "atom.h" #include "bond.h" #include "comm.h" #include "domain.h" #include "force.h" #include "kspace.h" #include "update.h" #include "respa.h" #include "neighbor.h" #include "neigh_list.h" #include "neigh_request.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define EWALD_F 1.12837917 #define EWALD_P 0.3275911 #define A1 0.254829592 #define A2 -0.284496736 #define A3 1.421413741 #define A4 -1.453152027 #define A5 1.061405429 /* ---------------------------------------------------------------------- */ PairLJCutCoulLongTIP4P::PairLJCutCoulLongTIP4P(LAMMPS *lmp) : PairLJCutCoulLong(lmp) { single_enable = 0; // TIP4P cannot compute virial as F dot r // due to find_M() finding bonded H atoms which are not near O atom no_virial_compute = 1; } /* ---------------------------------------------------------------------- */ void PairLJCutCoulLongTIP4P::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype,itable; int n,vlist[6]; int iH1,iH2,jH1,jH2; double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul; double fraction,table; double delx1,dely1,delz1,delx2,dely2,delz2,delx3,dely3,delz3; double r,r2inv,r6inv,forcecoul,forcelj,cforce,negforce; double factor_coul,factor_lj; double grij,expm2,prefactor,t,erfc; double xiM[3],xjM[3],fO[3],fH[3],v[6]; double *x1,*x2; int *ilist,*jlist,*numneigh,**firstneigh; double rsq; evdwl = ecoul = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; double **f = atom->f; double **x = atom->x; double *q = atom->q; int *type = atom->type; int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; double *special_coul = force->special_coul; double *special_lj = force->special_lj; int newton_pair = force->newton_pair; double qqrd2e = force->qqrd2e; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // loop over neighbors of my atoms for (ii = 0; ii < inum; ii++) { i = ilist[ii]; qtmp = q[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; if (itype == typeO) { find_M(i,iH1,iH2,xiM); x1 = xiM; } else x1 = x[i]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; - - if (j < nall) factor_coul = factor_lj = 1.0; - else { - factor_coul = special_coul[j/nall]; - factor_lj = special_lj[j/nall]; - j %= nall; - } + factor_lj = special_lj[sbmask(j)]; + factor_coul = special_coul[sbmask(j)]; + j &= NEIGHMASK; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; jtype = type[j]; if (rsq < cutsq[itype][jtype]) { r2inv = 1.0/rsq; if (rsq < cut_ljsq[itype][jtype]) { r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); forcelj *= factor_lj * r2inv; f[i][0] += delx*forcelj; f[i][1] += dely*forcelj; f[i][2] += delz*forcelj; f[j][0] -= delx*forcelj; f[j][1] -= dely*forcelj; f[j][2] -= delz*forcelj; if (eflag) { evdwl = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]) - offset[itype][jtype]; evdwl *= factor_lj; } else evdwl = 0.0; if (evflag) ev_tally(i,j,nlocal,newton_pair, evdwl,0.0,forcelj,delx,dely,delz); } // adjust rsq for off-site O charge(s) if (itype == typeO || jtype == typeO) { if (jtype == typeO) { find_M(j,jH1,jH2,xjM); x2 = xjM; } else x2 = x[j]; delx = x1[0] - x2[0]; dely = x1[1] - x2[1]; delz = x1[2] - x2[2]; rsq = delx*delx + dely*dely + delz*delz; } // test current rsq against cutoff and compute Coulombic force if (rsq < cut_coulsq) { r2inv = 1 / rsq; if (!ncoultablebits || rsq <= tabinnersq) { r = sqrt(rsq); grij = g_ewald * r; expm2 = exp(-grij*grij); t = 1.0 / (1.0 + EWALD_P*grij); erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2; prefactor = qqrd2e * qtmp*q[j]/r; forcecoul = prefactor * (erfc + EWALD_F*grij*expm2); if (factor_coul < 1.0) { forcecoul -= (1.0-factor_coul)*prefactor; } } else { union_int_float_t rsq_lookup; rsq_lookup.f = rsq; itable = rsq_lookup.i & ncoulmask; itable >>= ncoulshiftbits; fraction = (rsq_lookup.f - rtable[itable]) * drtable[itable]; table = ftable[itable] + fraction*dftable[itable]; forcecoul = qtmp*q[j] * table; if (factor_coul < 1.0) { table = ctable[itable] + fraction*dctable[itable]; prefactor = qtmp*q[j] * table; forcecoul -= (1.0-factor_coul)*prefactor; } } cforce = forcecoul * r2inv; // if i,j are not O atoms, force is applied directly // if i or j are O atoms, force is on fictitious atom // 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 // all virial terms are computed as distances to x2 // vlist stores 2,4,6 atoms whose forces contribute to virial n = 0; if (itype != typeO) { f[i][0] += delx * cforce; f[i][1] += dely * cforce; f[i][2] += delz * cforce; if (vflag) { v[0] = delx * delx * cforce; v[1] = dely * dely * cforce; v[2] = delz * delz * cforce; v[3] = delx * dely * cforce; v[4] = delx * delz * cforce; v[5] = dely * delz * cforce; vlist[n++] = i; } } else { fO[0] = delx*cforce*(1.0-2.0*alpha); fO[1] = dely*cforce*(1.0-2.0*alpha); fO[2] = delz*cforce*(1.0-2.0*alpha); fH[0] = alpha * (delx*cforce); fH[1] = alpha * (dely*cforce); fH[2] = alpha * (delz*cforce); 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) { delx1 = x[i][0] - x2[0]; dely1 = x[i][1] - x2[1]; delz1 = x[i][2] - x2[2]; domain->minimum_image(delx1,dely1,delz1); delx2 = x[iH1][0] - x2[0]; dely2 = x[iH1][1] - x2[1]; delz2 = x[iH1][2] - x2[2]; domain->minimum_image(delx2,dely2,delz2); delx3 = x[iH2][0] - x2[0]; dely3 = x[iH2][1] - x2[1]; delz3 = x[iH2][2] - x2[2]; domain->minimum_image(delx3,dely3,delz3); v[0] = delx1 * fO[0] + (delx2 + delx3) * fH[0]; v[1] = dely1 * fO[1] + (dely2 + dely3) * fH[1]; v[2] = delz1 * fO[2] + (delz2 + delz3) * fH[2]; v[3] = delx1 * fO[1] + (delx2 + delx3) * fH[1]; v[4] = delx1 * fO[2] + (delx2 + delx3) * fH[2]; v[5] = dely1 * fO[2] + (dely2 + dely3) * 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) vlist[n++] = j; } else { negforce = -cforce; fO[0] = delx*negforce*(1.0-2.0*alpha); fO[1] = dely*negforce*(1.0-2.0*alpha); fO[2] = delz*negforce*(1.0-2.0*alpha); fH[0] = alpha * (delx*negforce); fH[1] = alpha * (dely*negforce); fH[2] = alpha * (delz*negforce); 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) { delx1 = x[j][0] - x2[0]; dely1 = x[j][1] - x2[1]; delz1 = x[j][2] - x2[2]; domain->minimum_image(delx1,dely1,delz1); delx2 = x[jH1][0] - x2[0]; dely2 = x[jH1][1] - x2[1]; delz2 = x[jH1][2] - x2[2]; domain->minimum_image(delx2,dely2,delz2); delx3 = x[jH2][0] - x2[0]; dely3 = x[jH2][1] - x2[1]; delz3 = x[jH2][2] - x2[2]; domain->minimum_image(delx3,dely3,delz3); v[0] += delx1 * fO[0] + (delx2 + delx3) * fH[0]; v[1] += dely1 * fO[1] + (dely2 + dely3) * fH[1]; v[2] += delz1 * fO[2] + (delz2 + delz3) * fH[2]; v[3] += delx1 * fO[1] + (delx2 + delx3) * fH[1]; v[4] += delx1 * fO[2] + (delx2 + delx3) * fH[2]; v[5] += dely1 * fO[2] + (dely2 + dely3) * fH[2]; vlist[n++] = j; vlist[n++] = jH1; vlist[n++] = jH2; } } if (eflag) { if (!ncoultablebits || rsq <= tabinnersq) ecoul = prefactor*erfc; else { table = etable[itable] + fraction*detable[itable]; ecoul = qtmp*q[j] * table; } if (factor_coul < 1.0) ecoul -= (1.0-factor_coul)*prefactor; } else ecoul = 0.0; if (evflag) ev_tally_list(n,vlist,ecoul,v); } } } } } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairLJCutCoulLongTIP4P::settings(int narg, char **arg) { if (narg < 6 || narg > 7) error->all("Illegal pair_style command"); typeO = force->inumeric(arg[0]); typeH = force->inumeric(arg[1]); typeB = force->inumeric(arg[2]); typeA = force->inumeric(arg[3]); qdist = force->numeric(arg[4]); cut_lj_global = force->numeric(arg[5]); if (narg == 6) cut_coul = cut_lj_global; else cut_coul = force->numeric(arg[6]); // reset cutoffs that have been explicitly set if (allocated) { int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i+1; j <= atom->ntypes; j++) if (setflag[i][j]) cut_lj[i][j] = cut_lj_global; } } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairLJCutCoulLongTIP4P::init_style() { if (atom->tag_enable == 0) error->all("Pair style lj/cut/coul/long/tip4p requires atom IDs"); if (!force->newton_pair) error->all("Pair style lj/cut/coul/long/tip4p requires newton pair on"); if (!atom->q_flag) error->all("Pair style lj/cut/coul/long/tip4p requires atom attribute q"); if (strcmp(force->kspace_style,"pppm/tip4p") != 0) error->all("Pair style is incompatible with KSpace style"); if (force->bond == NULL) error->all("Must use a bond style with TIP4P potential"); if (force->angle == NULL) error->all("Must use an angle style with TIP4P potential"); PairLJCutCoulLong::init_style(); // set alpha parameter double theta = force->angle->equilibrium_angle(typeA); double blen = force->bond->equilibrium_distance(typeB); alpha = qdist / (2.0 * cos(0.5*theta) * blen); } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJCutCoulLongTIP4P::write_restart_settings(FILE *fp) { fwrite(&typeO,sizeof(int),1,fp); fwrite(&typeH,sizeof(int),1,fp); fwrite(&typeB,sizeof(int),1,fp); fwrite(&typeA,sizeof(int),1,fp); fwrite(&qdist,sizeof(double),1,fp); fwrite(&cut_lj_global,sizeof(double),1,fp); fwrite(&cut_coul,sizeof(double),1,fp); fwrite(&offset_flag,sizeof(int),1,fp); fwrite(&mix_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJCutCoulLongTIP4P::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&typeO,sizeof(int),1,fp); fread(&typeH,sizeof(int),1,fp); fread(&typeB,sizeof(int),1,fp); fread(&typeA,sizeof(int),1,fp); fread(&qdist,sizeof(double),1,fp); fread(&cut_lj_global,sizeof(double),1,fp); fread(&cut_coul,sizeof(double),1,fp); fread(&offset_flag,sizeof(int),1,fp); fread(&mix_flag,sizeof(int),1,fp); } MPI_Bcast(&typeO,1,MPI_INT,0,world); MPI_Bcast(&typeH,1,MPI_INT,0,world); MPI_Bcast(&typeB,1,MPI_INT,0,world); MPI_Bcast(&typeA,1,MPI_INT,0,world); MPI_Bcast(&qdist,1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_lj_global,1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_coul,1,MPI_DOUBLE,0,world); MPI_Bcast(&offset_flag,1,MPI_INT,0,world); MPI_Bcast(&mix_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- find 2 H atoms bonded to O atom i compute position xM of fictitious charge site for O atom also return local indices iH1,iH2 of H atoms ------------------------------------------------------------------------- */ void PairLJCutCoulLongTIP4P::find_M(int i, int &iH1, int &iH2, double *xM) { // test that O is correctly bonded to 2 succesive H atoms iH1 = atom->map(atom->tag[i] + 1); iH2 = atom->map(atom->tag[i] + 2); if (iH1 == -1 || iH2 == -1) error->one("TIP4P hydrogen is missing"); if (atom->type[iH1] != typeH || atom->type[iH2] != typeH) error->one("TIP4P hydrogen has incorrect atom type"); double **x = atom->x; double delx1 = x[iH1][0] - x[i][0]; double dely1 = x[iH1][1] - x[i][1]; double delz1 = x[iH1][2] - x[i][2]; domain->minimum_image(delx1,dely1,delz1); double delx2 = x[iH2][0] - x[i][0]; double dely2 = x[iH2][1] - x[i][1]; double delz2 = x[iH2][2] - x[i][2]; domain->minimum_image(delx2,dely2,delz2); xM[0] = x[i][0] + alpha * (delx1 + delx2); xM[1] = x[i][1] + alpha * (dely1 + dely2); xM[2] = x[i][2] + alpha * (delz1 + delz2); } /* ---------------------------------------------------------------------- */ void *PairLJCutCoulLongTIP4P::extract(char *str, int &dim) { dim = 0; if (strcmp(str,"qdist") == 0) return (void *) &qdist; if (strcmp(str,"typeO") == 0) return (void *) &typeO; if (strcmp(str,"typeH") == 0) return (void *) &typeH; if (strcmp(str,"typeA") == 0) return (void *) &typeA; if (strcmp(str,"typeB") == 0) return (void *) &typeB; if (strcmp(str,"cut_coul") == 0) return (void *) &cut_coul; return NULL; } diff --git a/src/MANYBODY/pair_airebo.cpp b/src/MANYBODY/pair_airebo.cpp index 96ef31bbb..168c9d713 100644 --- a/src/MANYBODY/pair_airebo.cpp +++ b/src/MANYBODY/pair_airebo.cpp @@ -1,4253 +1,4255 @@ /* ---------------------------------------------------------------------- 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: Ase Henry (MIT) ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "mpi.h" #include "pair_airebo.h" #include "atom.h" #include "neighbor.h" #include "neigh_request.h" #include "force.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 MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define MAXLINE 1024 #define TOL 1.0e-9 #define PGDELTA 1 /* ---------------------------------------------------------------------- */ PairAIREBO::PairAIREBO(LAMMPS *lmp) : Pair(lmp) { single_enable = 0; one_coeff = 1; ghostneigh = 1; maxlocal = 0; REBO_numneigh = NULL; REBO_firstneigh = NULL; maxpage = 0; pages = NULL; nC = nH = NULL; PI = 4.0*atan(1.0); } /* ---------------------------------------------------------------------- check if allocated, since class can be destructed when incomplete ------------------------------------------------------------------------- */ PairAIREBO::~PairAIREBO() { memory->destroy(REBO_numneigh); memory->sfree(REBO_firstneigh); for (int i = 0; i < maxpage; i++) memory->destroy(pages[i]); memory->sfree(pages); memory->destroy(nC); memory->destroy(nH); if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cutghost); memory->destroy(cutljsq); memory->destroy(lj1); memory->destroy(lj2); memory->destroy(lj3); memory->destroy(lj4); delete [] map; } } /* ---------------------------------------------------------------------- */ void PairAIREBO::compute(int eflag, int vflag) { if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = vflag_atom = 0; REBO_neigh(); FREBO(eflag,vflag); if (ljflag) FLJ(eflag,vflag); if (torflag) TORSION(eflag,vflag); if (vflag_fdotr) virial_compute(); } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairAIREBO::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"); // only sized by C,H = 2 types memory->create(cutljsq,2,2,"pair:cutljsq"); memory->create(lj1,2,2,"pair:lj1"); memory->create(lj2,2,2,"pair:lj2"); memory->create(lj3,2,2,"pair:lj3"); memory->create(lj4,2,2,"pair:lj4"); map = new int[n+1]; } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairAIREBO::settings(int narg, char **arg) { if (narg != 1 && narg != 3) error->all("Illegal pair_style command"); cutlj = force->numeric(arg[0]); ljflag = torflag = 1; if (narg == 3) { ljflag = force->inumeric(arg[1]); torflag = force->inumeric(arg[2]); } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairAIREBO::coeff(int narg, char **arg) { if (!allocated) allocate(); if (narg != 3 + atom->ntypes) error->all("Incorrect args for pair coefficients"); // insure I,J args are * * if (strcmp(arg[0],"*") != 0 || strcmp(arg[1],"*") != 0) error->all("Incorrect args for pair coefficients"); // read args that map atom types to C and H // map[i] = which element (0,1) the Ith atom type is, -1 if NULL for (int i = 3; i < narg; i++) { if (strcmp(arg[i],"NULL") == 0) { map[i-2] = -1; continue; } else if (strcmp(arg[i],"C") == 0) { map[i-2] = 0; } else if (strcmp(arg[i],"H") == 0) { map[i-2] = 1; } else error->all("Incorrect args for pair coefficients"); } // read potential file and initialize fitting splines read_file(arg[2]); spline_init(); // clear setflag since coeff() called once with I,J = * * int n = atom->ntypes; for (int i = 1; i <= n; i++) for (int j = i; j <= n; j++) setflag[i][j] = 0; // set setflag i,j for type pairs where both are mapped to elements int count = 0; for (int i = 1; i <= n; i++) for (int j = i; j <= n; j++) if (map[i] >= 0 && map[j] >= 0) { setflag[i][j] = 1; count++; } if (count == 0) error->all("Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairAIREBO::init_style() { if (atom->tag_enable == 0) error->all("Pair style AIREBO requires atom IDs"); if (force->newton_pair == 0) error->all("Pair style AIREBO requires newton pair on"); // need a full neighbor list, including neighbors of ghosts int irequest = neighbor->request(this); neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->full = 1; neighbor->requests[irequest]->ghost = 1; // local REBO neighbor list memory pgsize = neighbor->pgsize; oneatom = neighbor->oneatom; if (maxpage == 0) add_pages(0); } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairAIREBO::init_one(int i, int j) { if (setflag[i][j] == 0) error->all("All pair coeffs are not set"); // convert to C,H types int ii = map[i]; int jj = map[j]; // use C-C values for these cutoffs since C atoms are biggest // cut3rebo = 3 REBO distances cut3rebo = 3.0 * rcmax[0][0]; // cutljrebosq = furthest distance from an owned atom a ghost atom can be // to need its REBO neighs computed // interaction = M-K-I-J-L-N with I = owned and J = ghost // this insures N is in the REBO neigh list of L // since I-J < rcLJmax and J-L < rmax double cutljrebo = rcLJmax[0][0] + rcmax[0][0]; cutljrebosq = cutljrebo * cutljrebo; // cutmax = furthest distance from an owned atom // at which another atom will feel force, i.e. the ghost cutoff // for REBO term in potential: // interaction = M-K-I-J-L-N with I = owned and J = ghost // I to N is max distance = 3 REBO distances // for LJ term in potential: // short interaction = M-K-I-J-L-N with I = owned, J = ghost, I-J < rcLJmax // rcLJmax + 2*rcmax, since I-J < rcLJmax and J-L,L-N = REBO distances // long interaction = I-J with I = owned and J = ghost // cutlj*sigma, since I-J < LJ cutoff // cutghost = REBO cutoff used in REBO_neigh() for neighbors of ghosts double cutmax = cut3rebo; if (ljflag) { cutmax = MAX(cutmax,rcLJmax[0][0] + 2.0*rcmax[0][0]); cutmax = MAX(cutmax,cutlj*sigma[0][0]); } cutghost[i][j] = rcmax[ii][jj]; cutljsq[ii][jj] = cutlj*sigma[ii][jj] * cutlj*sigma[ii][jj]; lj1[ii][jj] = 48.0 * epsilon[ii][jj] * pow(sigma[ii][jj],12.0); lj2[ii][jj] = 24.0 * epsilon[ii][jj] * pow(sigma[ii][jj],6.0); lj3[ii][jj] = 4.0 * epsilon[ii][jj] * pow(sigma[ii][jj],12.0); lj4[ii][jj] = 4.0 * epsilon[ii][jj] * pow(sigma[ii][jj],6.0); cutghost[j][i] = cutghost[i][j]; cutljsq[jj][ii] = cutljsq[ii][jj]; lj1[jj][ii] = lj1[ii][jj]; lj2[jj][ii] = lj2[ii][jj]; lj3[jj][ii] = lj3[ii][jj]; lj4[jj][ii] = lj4[ii][jj]; return cutmax; } /* ---------------------------------------------------------------------- create REBO neighbor list from main neighbor list REBO neighbor list stores neighbors of ghost atoms ------------------------------------------------------------------------- */ void PairAIREBO::REBO_neigh() { int i,j,ii,jj,m,n,allnum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,rsq,dS; int *ilist,*jlist,*numneigh,**firstneigh; int *neighptr; double **x = atom->x; int *type = atom->type; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; if (nall > maxlocal) { maxlocal = atom->nmax; memory->destroy(REBO_numneigh); memory->sfree(REBO_firstneigh); memory->destroy(nC); memory->destroy(nH); memory->create(REBO_numneigh,maxlocal,"AIREBO:numneigh"); REBO_firstneigh = (int **) memory->smalloc(maxlocal*sizeof(int *), "AIREBO:firstneigh"); memory->create(nC,maxlocal,"AIREBO:nC"); memory->create(nH,maxlocal,"AIREBO:nH"); } allnum = list->inum + list->gnum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // store all REBO neighs of owned and ghost atoms // scan full neighbor list of I npage = 0; int npnt = 0; for (ii = 0; ii < allnum; ii++) { i = ilist[ii]; if (pgsize - npnt < oneatom) { npnt = 0; npage++; if (npage == maxpage) add_pages(npage); } neighptr = &pages[npage][npnt]; n = 0; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = map[type[i]]; nC[i] = nH[i] = 0.0; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; + j &= NEIGHMASK; jtype = map[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 < rcmaxsq[itype][jtype]) { neighptr[n++] = j; if (jtype == 0) nC[i] += Sp(sqrt(rsq),rcmin[itype][jtype],rcmax[itype][jtype],dS); else nH[i] += Sp(sqrt(rsq),rcmin[itype][jtype],rcmax[itype][jtype],dS); } } REBO_firstneigh[i] = neighptr; REBO_numneigh[i] = n; npnt += n; if (npnt >= pgsize) error->one("Neighbor list overflow, boost neigh_modify one or page"); } } /* ---------------------------------------------------------------------- REBO forces and energy ------------------------------------------------------------------------- */ void PairAIREBO::FREBO(int eflag, int vflag) { int i,j,k,m,ii,inum,itype,jtype,itag,jtag; double delx,dely,delz,evdwl,fpair,xtmp,ytmp,ztmp; double rsq,rij,wij; double Qij,Aij,alphaij,VR,pre,dVRdi,VA,term,bij,dVAdi,dVA; double dwij,del[3]; int *ilist,*REBO_neighs; evdwl = 0.0; double **x = atom->x; double **f = atom->f; int *type = atom->type; int *tag = atom->tag; int nlocal = atom->nlocal; int newton_pair = force->newton_pair; inum = list->inum; ilist = list->ilist; // two-body interactions from REBO neighbor list, skip half of them for (ii = 0; ii < inum; ii++) { i = ilist[ii]; itag = tag[i]; itype = map[type[i]]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; REBO_neighs = REBO_firstneigh[i]; for (k = 0; k < REBO_numneigh[i]; k++) { j = REBO_neighs[k]; jtag = tag[j]; if (itag > jtag) { if ((itag+jtag) % 2 == 0) continue; } else if (itag < jtag) { if ((itag+jtag) % 2 == 1) continue; } else { if (x[j][2] < ztmp) continue; if (x[j][2] == ztmp && x[j][1] < ytmp) continue; if (x[j][2] == ztmp && x[j][1] == ytmp && x[j][0] < xtmp) continue; } jtype = map[type[j]]; 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; rij = sqrt(rsq); wij = Sp(rij,rcmin[itype][jtype],rcmax[itype][jtype],dwij); if (wij <= TOL) continue; Qij = Q[itype][jtype]; Aij = A[itype][jtype]; alphaij = alpha[itype][jtype]; VR = wij*(1.0+(Qij/rij)) * Aij*exp(-alphaij*rij); pre = wij*Aij * exp(-alphaij*rij); dVRdi = pre * ((-alphaij)-(Qij/rsq)-(Qij*alphaij/rij)); dVRdi += VR/wij * dwij; VA = dVA = 0.0; for (m = 0; m < 3; m++) { term = -wij * BIJc[itype][jtype][m] * exp(-Beta[itype][jtype][m]*rij); VA += term; dVA += -Beta[itype][jtype][m] * term; } dVA += VA/wij * dwij; del[0] = delx; del[1] = dely; del[2] = delz; bij = bondorder(i,j,del,rij,VA,f,vflag_atom); dVAdi = bij*dVA; fpair = -(dVRdi+dVAdi) / rij; f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; f[j][0] -= delx*fpair; f[j][1] -= dely*fpair; f[j][2] -= delz*fpair; if (eflag) evdwl = VR + bij*VA; if (evflag) ev_tally(i,j,nlocal,newton_pair, evdwl,0.0,fpair,delx,dely,delz); } } } /* ---------------------------------------------------------------------- compute LJ forces and energy find 3- and 4-step paths between atoms I,J via REBO neighbor lists ------------------------------------------------------------------------- */ void PairAIREBO::FLJ(int eflag, int vflag) { int i,j,k,m,ii,jj,kk,mm,inum,jnum,itype,jtype,ktype,mtype,itag,jtag; int atomi,atomj,atomk,atomm; int testpath,npath,done; double evdwl,fpair,xtmp,ytmp,ztmp; double rsq,best,wik,wkm,cij,rij,dwij,dwik,dwkj,dwkm,dwmj; double delij[3],rijsq,delik[3],rik,deljk[3]; double rkj,wkj,dC,VLJ,dVLJ,VA,Str,dStr,Stb; double vdw,slw,dvdw,dslw,drij,swidth,tee,tee2; double rljmin,rljmax,sigcut,sigmin,sigwid; double delkm[3],rkm,deljm[3],rmj,wmj,r2inv,r6inv,scale,delscale[3]; int *ilist,*jlist,*numneigh,**firstneigh; int *REBO_neighs_i,*REBO_neighs_k; double delikS[3],deljkS[3],delkmS[3],deljmS[3],delimS[3]; double rikS,rkjS,rkmS,rmjS,wikS,dwikS; double wkjS,dwkjS,wkmS,dwkmS,wmjS,dwmjS; double fpair1,fpair2,fpair3; double fi[3],fj[3],fk[3],fm[3]; // I-J interaction from full neighbor list // skip 1/2 of interactions since only consider each pair once evdwl = 0.0; rljmin = 0.0; rljmax = 0.0; sigcut = 0.0; sigmin = 0.0; sigwid = 0.0; double **x = atom->x; double **f = atom->f; int *tag = atom->tag; 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]; itag = tag[i]; itype = map[type[i]]; atomi = i; 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; jtag = tag[j]; if (itag > jtag) { if ((itag+jtag) % 2 == 0) continue; } else if (itag < jtag) { if ((itag+jtag) % 2 == 1) continue; } else { if (x[j][2] < ztmp) continue; if (x[j][2] == ztmp && x[j][1] < ytmp) continue; if (x[j][2] == ztmp && x[j][1] == ytmp && x[j][0] < xtmp) continue; } jtype = map[type[j]]; atomj = j; delij[0] = xtmp - x[j][0]; delij[1] = ytmp - x[j][1]; delij[2] = ztmp - x[j][2]; rijsq = delij[0]*delij[0] + delij[1]*delij[1] + delij[2]*delij[2]; // if outside of LJ cutoff, skip // if outside of 4-path cutoff, best = 0.0, no need to test paths // if outside of 2-path cutoff but inside 4-path cutoff, // best = 0.0, test 3-,4-paths // if inside 2-path cutoff, best = wij, only test 3-,4-paths if best < 1 if (rijsq >= cutljsq[itype][jtype]) continue; rij = sqrt(rijsq); if (rij >= cut3rebo) { best = 0.0; testpath = 0; } else if (rij >= rcmax[itype][jtype]) { best = 0.0; testpath = 1; } else { best = Sp(rij,rcmin[itype][jtype],rcmax[itype][jtype],dwij); npath = 2; if (best < 1.0) testpath = 1; else testpath = 0; } done = 0; if (testpath) { // test all 3-body paths = I-K-J // I-K interactions come from atom I's REBO neighbors // if wik > current best, compute wkj // if best = 1.0, done REBO_neighs_i = REBO_firstneigh[i]; for (kk = 0; kk < REBO_numneigh[i] && done==0; kk++) { k = REBO_neighs_i[kk]; if (k == j) continue; ktype = map[type[k]]; delik[0] = x[i][0] - x[k][0]; delik[1] = x[i][1] - x[k][1]; delik[2] = x[i][2] - x[k][2]; rsq = delik[0]*delik[0] + delik[1]*delik[1] + delik[2]*delik[2]; if (rsq < rcmaxsq[itype][ktype]) { rik = sqrt(rsq); wik = Sp(rik,rcmin[itype][ktype],rcmax[itype][ktype],dwik); } else wik = 0.0; if (wik > best) { deljk[0] = x[j][0] - x[k][0]; deljk[1] = x[j][1] - x[k][1]; deljk[2] = x[j][2] - x[k][2]; rsq = deljk[0]*deljk[0] + deljk[1]*deljk[1] + deljk[2]*deljk[2]; if (rsq < rcmaxsq[ktype][jtype]) { rkj = sqrt(rsq); wkj = Sp(rkj,rcmin[ktype][jtype],rcmax[ktype][jtype],dwkj); if (wik*wkj > best) { best = wik*wkj; npath = 3; atomk = k; delikS[0] = delik[0]; delikS[1] = delik[1]; delikS[2] = delik[2]; rikS = rik; wikS = wik; dwikS = dwik; deljkS[0] = deljk[0]; deljkS[1] = deljk[1]; deljkS[2] = deljk[2]; rkjS = rkj; wkjS = wkj; dwkjS = dwkj; if (best == 1.0) { done = 1; break; } } } // test all 4-body paths = I-K-M-J // K-M interactions come from atom K's REBO neighbors // if wik*wkm > current best, compute wmj // if best = 1.0, done REBO_neighs_k = REBO_firstneigh[k]; for (mm = 0; mm < REBO_numneigh[k] && done==0; mm++) { m = REBO_neighs_k[mm]; if (m == i || m == j) continue; mtype = map[type[m]]; delkm[0] = x[k][0] - x[m][0]; delkm[1] = x[k][1] - x[m][1]; delkm[2] = x[k][2] - x[m][2]; rsq = delkm[0]*delkm[0] + delkm[1]*delkm[1] + delkm[2]*delkm[2]; if (rsq < rcmaxsq[ktype][mtype]) { rkm = sqrt(rsq); wkm = Sp(rkm,rcmin[ktype][mtype],rcmax[ktype][mtype],dwkm); } else wkm = 0.0; if (wik*wkm > best) { deljm[0] = x[j][0] - x[m][0]; deljm[1] = x[j][1] - x[m][1]; deljm[2] = x[j][2] - x[m][2]; rsq = deljm[0]*deljm[0] + deljm[1]*deljm[1] + deljm[2]*deljm[2]; if (rsq < rcmaxsq[mtype][jtype]) { rmj = sqrt(rsq); wmj = Sp(rmj,rcmin[mtype][jtype],rcmax[mtype][jtype],dwmj); if (wik*wkm*wmj > best) { best = wik*wkm*wmj; npath = 4; atomk = k; delikS[0] = delik[0]; delikS[1] = delik[1]; delikS[2] = delik[2]; rikS = rik; wikS = wik; dwikS = dwik; atomm = m; delkmS[0] = delkm[0]; delkmS[1] = delkm[1]; delkmS[2] = delkm[2]; rkmS = rkm; wkmS = wkm; dwkmS = dwkm; deljmS[0] = deljm[0]; deljmS[1] = deljm[1]; deljmS[2] = deljm[2]; rmjS = rmj; wmjS = wmj; dwmjS = dwmj; if (best == 1.0) { done = 1; break; } } } } } } } } cij = 1.0 - best; if (cij == 0.0) continue; // compute LJ forces and energy sigwid = 0.84; sigcut = 3.0; sigmin = sigcut - sigwid; rljmin = sigma[itype][jtype]; rljmax = sigcut * rljmin; rljmin = sigmin * rljmin; if (rij > rljmax){ slw = 0.0; dslw = 0.0;} else if (rij > rljmin){ drij = rij - rljmin; swidth = rljmax - rljmin; tee = drij / swidth; tee2 = pow (tee,2); slw = 1.0 - tee2 * (3.0 - 2.0 * tee); dslw = 6.0 * tee * (1.0 - tee) / rij / swidth; } else slw = 1.0; dslw = 0.0; r2inv = 1.0/rijsq; r6inv = r2inv*r2inv*r2inv; vdw = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]); dvdw = -r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]) / rij; // VLJ now becomes vdw * slw, derivaties, etc. VLJ = vdw * slw; dVLJ = dvdw * slw + vdw * dslw; Str = Sp2(rij,rcLJmin[itype][jtype],rcLJmax[itype][jtype],dStr); VA = Str*cij*VLJ; if (Str > 0.0) { scale = rcmin[itype][jtype] / rij; delscale[0] = scale * delij[0]; delscale[1] = scale * delij[1]; delscale[2] = scale * delij[2]; Stb = bondorderLJ(i,j,delscale,rcmin[itype][jtype],VA, delij,rij,f,vflag_atom); } else Stb = 0.0; fpair = -(dStr * (Stb*cij*VLJ - cij*VLJ) + dVLJ * (Str*Stb*cij + cij - Str*cij)) / rij; f[i][0] += delij[0]*fpair; f[i][1] += delij[1]*fpair; f[i][2] += delij[2]*fpair; f[j][0] -= delij[0]*fpair; f[j][1] -= delij[1]*fpair; f[j][2] -= delij[2]*fpair; if (eflag) evdwl = VA*Stb + (1.0-Str)*cij*VLJ; if (evflag) ev_tally(i,j,nlocal,newton_pair, evdwl,0.0,fpair,delij[0],delij[1],delij[2]); if (cij < 1.0) { dC = Str*Stb*VLJ + (1.0-Str)*VLJ; if (npath == 2) { fpair = dC*dwij / rij; f[atomi][0] += delij[0]*fpair; f[atomi][1] += delij[1]*fpair; f[atomi][2] += delij[2]*fpair; f[atomj][0] -= delij[0]*fpair; f[atomj][1] -= delij[1]*fpair; f[atomj][2] -= delij[2]*fpair; if (vflag_atom) v_tally2(atomi,atomj,fpair,delij); } else if (npath == 3) { fpair1 = dC*dwikS*wkjS / rikS; fi[0] = delikS[0]*fpair1; fi[1] = delikS[1]*fpair1; fi[2] = delikS[2]*fpair1; fpair2 = dC*wikS*dwkjS / rkjS; fj[0] = deljkS[0]*fpair2; fj[1] = deljkS[1]*fpair2; fj[2] = deljkS[2]*fpair2; f[atomi][0] += fi[0]; f[atomi][1] += fi[1]; f[atomi][2] += fi[2]; f[atomj][0] += fj[0]; f[atomj][1] += fj[1]; f[atomj][2] += fj[2]; f[atomk][0] -= fi[0] + fj[0]; f[atomk][1] -= fi[1] + fj[1]; f[atomk][2] -= fi[2] + fj[2]; if (vflag_atom) v_tally3(atomi,atomj,atomk,fi,fj,delikS,deljkS); } else { fpair1 = dC*dwikS*wkmS*wmjS / rikS; fi[0] = delikS[0]*fpair1; fi[1] = delikS[1]*fpair1; fi[2] = delikS[2]*fpair1; fpair2 = dC*wikS*dwkmS*wmjS / rkmS; fk[0] = delkmS[0]*fpair2 - fi[0]; fk[1] = delkmS[1]*fpair2 - fi[1]; fk[2] = delkmS[2]*fpair2 - fi[2]; fpair3 = dC*wikS*wkmS*dwmjS / rmjS; fj[0] = deljmS[0]*fpair3; fj[1] = deljmS[1]*fpair3; fj[2] = deljmS[2]*fpair3; fm[0] = -delkmS[0]*fpair2 - fj[0]; fm[1] = -delkmS[1]*fpair2 - fj[1]; fm[2] = -delkmS[2]*fpair2 - fj[2]; f[atomi][0] += fi[0]; f[atomi][1] += fi[1]; f[atomi][2] += fi[2]; f[atomj][0] += fj[0]; f[atomj][1] += fj[1]; f[atomj][2] += fj[2]; f[atomk][0] += fk[0]; f[atomk][1] += fk[1]; f[atomk][2] += fk[2]; f[atomm][0] += fm[0]; f[atomm][1] += fm[1]; f[atomm][2] += fm[2]; if (vflag_atom) { delimS[0] = delikS[0] + delkmS[0]; delimS[1] = delikS[1] + delkmS[1]; delimS[2] = delikS[2] + delkmS[2]; v_tally4(atomi,atomj,atomk,atomm,fi,fj,fk,delimS,deljmS,delkmS); } } } } } } /* ---------------------------------------------------------------------- torsional forces and energy ------------------------------------------------------------------------- */ void PairAIREBO::TORSION(int eflag, int vflag) { int i,j,k,l,ii,inum,itag,jtag; double evdwl,fpair,xtmp,ytmp,ztmp; double cos321; double w21,dw21,cos234,w34,dw34; double cross321[3],cross321mag,cross234[3],cross234mag; double w23,dw23,cw2,ekijl,Ec; double cw,cwnum,cwnom; double rij,rij2,rik,rjl,tspjik,dtsjik,tspijl,dtsijl,costmp,fcpc; double sin321,sin234,rjk2,rik2,ril2,rjl2; double rjk,ril; double Vtors; double dndij[3],tmpvec[3],dndik[3],dndjl[3]; double dcidij,dcidik,dcidjk,dcjdji,dcjdjl,dcjdil; double dsidij,dsidik,dsidjk,dsjdji,dsjdjl,dsjdil; double dxidij,dxidik,dxidjk,dxjdji,dxjdjl,dxjdil; double ddndij,ddndik,ddndjk,ddndjl,ddndil,dcwddn,dcwdn,dvpdcw,Ftmp[3]; double del32[3],rsq,r32,del23[3],del21[3],r21; double deljk[3],del34[3],delil[3],delkl[3],r23,r34; double fi[3],fj[3],fk[3],fl[3]; int itype,jtype,ktype,ltype,kk,ll,jj; int *ilist,*REBO_neighs_i,*REBO_neighs_j; double **x = atom->x; double **f = atom->f; int *type = atom->type; int *tag = atom->tag; inum = list->inum; ilist = list->ilist; for (ii = 0; ii < inum; ii++) { i = ilist[ii]; itag = tag[i]; itype = map[type[i]]; if (itype != 0) continue; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; REBO_neighs_i = REBO_firstneigh[i]; for (jj = 0; jj < REBO_numneigh[i]; jj++) { j = REBO_neighs_i[jj]; jtag = tag[j]; if (itag > jtag) { if ((itag+jtag) % 2 == 0) continue; } else if (itag < jtag) { if ((itag+jtag) % 2 == 1) continue; } else { if (x[j][2] < ztmp) continue; if (x[j][2] == ztmp && x[j][1] < ytmp) continue; if (x[j][2] == ztmp && x[j][1] == ytmp && x[j][0] < xtmp) continue; } jtype = map[type[j]]; if (jtype != 0) continue; del32[0] = x[j][0]-x[i][0]; del32[1] = x[j][1]-x[i][1]; del32[2] = x[j][2]-x[i][2]; rsq = del32[0]*del32[0] + del32[1]*del32[1] + del32[2]*del32[2]; r32 = sqrt(rsq); del23[0] = -del32[0]; del23[1] = -del32[1]; del23[2] = -del32[2]; r23 = r32; w23 = Sp(r23,rcmin[itype][jtype],rcmax[itype][jtype],dw23); for (kk = 0; kk < REBO_numneigh[i]; kk++) { k = REBO_neighs_i[kk]; ktype = map[type[k]]; if (k == j) continue; del21[0] = x[i][0]-x[k][0]; del21[1] = x[i][1]-x[k][1]; del21[2] = x[i][2]-x[k][2]; rsq = del21[0]*del21[0] + del21[1]*del21[1] + del21[2]*del21[2]; r21 = sqrt(rsq); cos321 = - ((del21[0]*del32[0]) + (del21[1]*del32[1]) + (del21[2]*del32[2])) / (r21*r32); cos321 = MIN(cos321,1.0); cos321 = MAX(cos321,-1.0); sin321 = sqrt(1.0 - cos321*cos321); if (sin321 < TOL) continue; deljk[0] = del21[0]-del23[0]; deljk[1] = del21[1]-del23[1]; deljk[2] = del21[2]-del23[2]; rjk2 = deljk[0]*deljk[0] + deljk[1]*deljk[1] + deljk[2]*deljk[2]; rjk=sqrt(rjk2); rik2 = r21*r21; w21 = Sp(r21,rcmin[itype][ktype],rcmax[itype][ktype],dw21); rij = r32; rik = r21; rij2 = r32*r32; rik2 = r21*r21; costmp = 0.5*(rij2+rik2-rjk2)/rij/rik; tspjik = Sp2(costmp,thmin,thmax,dtsjik); dtsjik = -dtsjik; REBO_neighs_j = REBO_firstneigh[j]; for (ll = 0; ll < REBO_numneigh[j]; ll++) { l = REBO_neighs_j[ll]; ltype = map[type[l]]; if (l == i || l == k) continue; del34[0] = x[j][0]-x[l][0]; del34[1] = x[j][1]-x[l][1]; del34[2] = x[j][2]-x[l][2]; rsq = del34[0]*del34[0] + del34[1]*del34[1] + del34[2]*del34[2]; r34 = sqrt(rsq); cos234 = (del32[0]*del34[0] + del32[1]*del34[1] + del32[2]*del34[2]) / (r32*r34); cos234 = MIN(cos234,1.0); cos234 = MAX(cos234,-1.0); sin234 = sqrt(1.0 - cos234*cos234); if (sin234 < TOL) continue; w34 = Sp(r34,rcmin[jtype][ltype],rcmax[jtype][ltype],dw34); delil[0] = del23[0] + del34[0]; delil[1] = del23[1] + del34[1]; delil[2] = del23[2] + del34[2]; ril2 = delil[0]*delil[0] + delil[1]*delil[1] + delil[2]*delil[2]; ril=sqrt(ril2); rjl2 = r34*r34; rjl = r34; rjl2 = r34*r34; costmp = 0.5*(rij2+rjl2-ril2)/rij/rjl; tspijl = Sp2(costmp,thmin,thmax,dtsijl); dtsijl = -dtsijl; //need minus sign cross321[0] = (del32[1]*del21[2])-(del32[2]*del21[1]); cross321[1] = (del32[2]*del21[0])-(del32[0]*del21[2]); cross321[2] = (del32[0]*del21[1])-(del32[1]*del21[0]); cross321mag = sqrt(cross321[0]*cross321[0]+ cross321[1]*cross321[1]+ cross321[2]*cross321[2]); cross234[0] = (del23[1]*del34[2])-(del23[2]*del34[1]); cross234[1] = (del23[2]*del34[0])-(del23[0]*del34[2]); cross234[2] = (del23[0]*del34[1])-(del23[1]*del34[0]); cross234mag = sqrt(cross234[0]*cross234[0]+ cross234[1]*cross234[1]+ cross234[2]*cross234[2]); cwnum = (cross321[0]*cross234[0]) + (cross321[1]*cross234[1])+(cross321[2]*cross234[2]); cwnom = r21*r34*r32*r32*sin321*sin234; cw = cwnum/cwnom; cw2 = (.5*(1.0-cw)); ekijl = epsilonT[ktype][ltype]; Ec = 256.0*ekijl/405.0; Vtors = (Ec*(pow(cw2,5.0)))-(ekijl/10.0); if (eflag) evdwl = Vtors*w21*w23*w34*(1.0-tspjik)*(1.0-tspijl); dndij[0] = (cross234[1]*del21[2])-(cross234[2]*del21[1]); dndij[1] = (cross234[2]*del21[0])-(cross234[0]*del21[2]); dndij[2] = (cross234[0]*del21[1])-(cross234[1]*del21[0]); tmpvec[0] = (del34[1]*cross321[2])-(del34[2]*cross321[1]); tmpvec[1] = (del34[2]*cross321[0])-(del34[0]*cross321[2]); tmpvec[2] = (del34[0]*cross321[1])-(del34[1]*cross321[0]); dndij[0] = dndij[0]+tmpvec[0]; dndij[1] = dndij[1]+tmpvec[1]; dndij[2] = dndij[2]+tmpvec[2]; dndik[0] = (del23[1]*cross234[2])-(del23[2]*cross234[1]); dndik[1] = (del23[2]*cross234[0])-(del23[0]*cross234[2]); dndik[2] = (del23[0]*cross234[1])-(del23[1]*cross234[0]); dndjl[0] = (cross321[1]*del23[2])-(cross321[2]*del23[1]); dndjl[1] = (cross321[2]*del23[0])-(cross321[0]*del23[2]); dndjl[2] = (cross321[0]*del23[1])-(cross321[1]*del23[0]); dcidij = ((r23*r23)-(r21*r21)+(rjk*rjk))/(2.0*r23*r23*r21); dcidik = ((r21*r21)-(r23*r23)+(rjk*rjk))/(2.0*r23*r21*r21); dcidjk = (-rjk)/(r23*r21); dcjdji = ((r23*r23)-(r34*r34)+(ril*ril))/(2.0*r23*r23*r34); dcjdjl = ((r34*r34)-(r23*r23)+(ril*ril))/(2.0*r23*r34*r34); dcjdil = (-ril)/(r23*r34); dsidij = (-cos321/sin321)*dcidij; dsidik = (-cos321/sin321)*dcidik; dsidjk = (-cos321/sin321)*dcidjk; dsjdji = (-cos234/sin234)*dcjdji; dsjdjl = (-cos234/sin234)*dcjdjl; dsjdil = (-cos234/sin234)*dcjdil; dxidij = (r21*sin321)+(r23*r21*dsidij); dxidik = (r23*sin321)+(r23*r21*dsidik); dxidjk = (r23*r21*dsidjk); dxjdji = (r34*sin234)+(r23*r34*dsjdji); dxjdjl = (r23*sin234)+(r23*r34*dsjdjl); dxjdil = (r23*r34*dsjdil); ddndij = (dxidij*cross234mag)+(cross321mag*dxjdji); ddndik = dxidik*cross234mag; ddndjk = dxidjk*cross234mag; ddndjl = cross321mag*dxjdjl; ddndil = cross321mag*dxjdil; dcwddn = -cwnum/(cwnom*cwnom); dcwdn = 1.0/cwnom; dvpdcw = (-1.0)*Ec*(-.5)*5.0*pow(cw2,4.0) * w23*w21*w34*(1.0-tspjik)*(1.0-tspijl); Ftmp[0] = dvpdcw*((dcwdn*dndij[0])+(dcwddn*ddndij*del23[0]/r23)); Ftmp[1] = dvpdcw*((dcwdn*dndij[1])+(dcwddn*ddndij*del23[1]/r23)); Ftmp[2] = dvpdcw*((dcwdn*dndij[2])+(dcwddn*ddndij*del23[2]/r23)); fi[0] = Ftmp[0]; fi[1] = Ftmp[1]; fi[2] = Ftmp[2]; fj[0] = -Ftmp[0]; fj[1] = -Ftmp[1]; fj[2] = -Ftmp[2]; Ftmp[0] = dvpdcw*((dcwdn*dndik[0])+(dcwddn*ddndik*del21[0]/r21)); Ftmp[1] = dvpdcw*((dcwdn*dndik[1])+(dcwddn*ddndik*del21[1]/r21)); Ftmp[2] = dvpdcw*((dcwdn*dndik[2])+(dcwddn*ddndik*del21[2]/r21)); fi[0] += Ftmp[0]; fi[1] += Ftmp[1]; fi[2] += Ftmp[2]; fk[0] = -Ftmp[0]; fk[1] = -Ftmp[1]; fk[2] = -Ftmp[2]; Ftmp[0] = (dvpdcw*dcwddn*ddndjk*deljk[0])/rjk; Ftmp[1] = (dvpdcw*dcwddn*ddndjk*deljk[1])/rjk; Ftmp[2] = (dvpdcw*dcwddn*ddndjk*deljk[2])/rjk; fj[0] += Ftmp[0]; fj[1] += Ftmp[1]; fj[2] += Ftmp[2]; fk[0] -= Ftmp[0]; fk[1] -= Ftmp[1]; fk[2] -= Ftmp[2]; Ftmp[0] = dvpdcw*((dcwdn*dndjl[0])+(dcwddn*ddndjl*del34[0]/r34)); Ftmp[1] = dvpdcw*((dcwdn*dndjl[1])+(dcwddn*ddndjl*del34[1]/r34)); Ftmp[2] = dvpdcw*((dcwdn*dndjl[2])+(dcwddn*ddndjl*del34[2]/r34)); fj[0] += Ftmp[0]; fj[1] += Ftmp[1]; fj[2] += Ftmp[2]; fl[0] = -Ftmp[0]; fl[1] = -Ftmp[1]; fl[2] = -Ftmp[2]; Ftmp[0] = (dvpdcw*dcwddn*ddndil*delil[0])/ril; Ftmp[1] = (dvpdcw*dcwddn*ddndil*delil[1])/ril; Ftmp[2] = (dvpdcw*dcwddn*ddndil*delil[2])/ril; fi[0] += Ftmp[0]; fi[1] += Ftmp[1]; fi[2] += Ftmp[2]; fl[0] -= Ftmp[0]; fl[1] -= Ftmp[1]; fl[2] -= Ftmp[2]; // coordination forces fpair = Vtors*dw21*w23*w34*(1.0-tspjik)*(1.0-tspijl) / r21; fi[0] -= del21[0]*fpair; fi[1] -= del21[1]*fpair; fi[2] -= del21[2]*fpair; fk[0] += del21[0]*fpair; fk[1] += del21[1]*fpair; fk[2] += del21[2]*fpair; fpair = Vtors*w21*dw23*w34*(1.0-tspjik)*(1.0-tspijl) / r23; fi[0] -= del23[0]*fpair; fi[1] -= del23[1]*fpair; fi[2] -= del23[2]*fpair; fj[0] += del23[0]*fpair; fj[1] += del23[1]*fpair; fj[2] += del23[2]*fpair; fpair = Vtors*w21*w23*dw34*(1.0-tspjik)*(1.0-tspijl) / r34; fj[0] -= del34[0]*fpair; fj[1] -= del34[1]*fpair; fj[2] -= del34[2]*fpair; fl[0] += del34[0]*fpair; fl[1] += del34[1]*fpair; fl[2] += del34[2]*fpair; // additional cut off function forces fcpc = -Vtors*w21*w23*w34*dtsjik*(1.0-tspijl); fpair = fcpc*dcidij/rij; fi[0] += fpair*del23[0]; fi[1] += fpair*del23[1]; fi[2] += fpair*del23[2]; fj[0] -= fpair*del23[0]; fj[1] -= fpair*del23[1]; fj[2] -= fpair*del23[2]; fpair = fcpc*dcidik/rik; fi[0] += fpair*del21[0]; fi[1] += fpair*del21[1]; fi[2] += fpair*del21[2]; fk[0] -= fpair*del21[0]; fk[1] -= fpair*del21[1]; fk[2] -= fpair*del21[2]; fpair = fcpc*dcidjk/rjk; fj[0] += fpair*deljk[0]; fj[1] += fpair*deljk[1]; fj[2] += fpair*deljk[2]; fk[0] -= fpair*deljk[0]; fk[1] -= fpair*deljk[1]; fk[2] -= fpair*deljk[2]; fcpc = -Vtors*w21*w23*w34*(1.0-tspjik)*dtsijl; fpair = fcpc*dcjdji/rij; fi[0] += fpair*del23[0]; fi[1] += fpair*del23[1]; fi[2] += fpair*del23[2]; fj[0] -= fpair*del23[0]; fj[1] -= fpair*del23[1]; fj[2] -= fpair*del23[2]; fpair = fcpc*dcjdjl/rjl; fj[0] += fpair*del34[0]; fj[1] += fpair*del34[1]; fj[2] += fpair*del34[2]; fl[0] -= fpair*del34[0]; fl[1] -= fpair*del34[1]; fl[2] -= fpair*del34[2]; fpair = fcpc*dcjdil/ril; fi[0] += fpair*delil[0]; fi[1] += fpair*delil[1]; fi[2] += fpair*delil[2]; fl[0] -= fpair*delil[0]; fl[1] -= fpair*delil[1]; fl[2] -= fpair*delil[2]; // sum per-atom forces into atom force array 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] += fk[0]; f[k][1] += fk[1]; f[k][2] += fk[2]; f[l][0] += fl[0]; f[l][1] += fl[1]; f[l][2] += fl[2]; if (evflag) { delkl[0] = delil[0] - del21[0]; delkl[1] = delil[1] - del21[1]; delkl[2] = delil[2] - del21[2]; ev_tally4(i,j,k,l,evdwl,fi,fj,fk,delil,del34,delkl); } } } } } } // ---------------------------------------------------------------------- // S'(t) and S(t) cutoff functions // ---------------------------------------------------------------------- /* ---------------------------------------------------------------------- cutoff function Sprime return cutoff and dX = derivative ------------------------------------------------------------------------- */ double PairAIREBO::Sp(double Xij, double Xmin, double Xmax, double &dX) { double cutoff; double t = (Xij-Xmin) / (Xmax-Xmin); if (t <= 0.0) { cutoff = 1.0; dX = 0.0; } else if (t >= 1.0) { cutoff = 0.0; dX = 0.0; } else { cutoff = 0.5 * (1.0+cos(PI*t)); dX = (-0.5*PI*sin(PI*t)) / (Xmax-Xmin); } return cutoff; } /* ---------------------------------------------------------------------- LJ cutoff function Sp2 return cutoff and dX = derivative ------------------------------------------------------------------------- */ double PairAIREBO::Sp2(double Xij, double Xmin, double Xmax, double &dX) { double cutoff; double t = (Xij-Xmin) / (Xmax-Xmin); if (t <= 0.0) { cutoff = 1.0; dX = 0.0; } if (t >= 1.0) { cutoff = 0.0; dX = 0.0; } if (t>0.0 && t<1.0) { cutoff = (1.0-(t*t*(3.0-2.0*t))); dX = 6.0*(t*t-t) / (Xmax-Xmin); } return cutoff; } /* ---------------------------------------------------------------------- Bij function ------------------------------------------------------------------------- */ double PairAIREBO::bondorder(int i, int j, double rij[3], double rijmag, double VA, double **f, int vflag_atom) { int atomi,atomj,k,n,l,atomk,atoml,atomn,atom1,atom2,atom3,atom4; int itype,jtype,ktype,ltype,ntype; double rik[3],rjl[3],rkn[3],rji[3],rki[3],rlj[3],rknmag,dNki,dwjl,bij; double NijC,NijH,NjiC,NjiH,wik,dwik,dwkn,wjl; double rikmag,rjlmag,cosjik,cosijl,g,tmp2,tmp3; double Etmp,pij,tmp,wij,dwij,NconjtmpI,NconjtmpJ,Nki,Nlj,dS; double lamdajik,lamdaijl,dgdc,dgdN,pji,Nijconj,piRC; double dcosjikdri[3],dcosijldri[3],dcosjikdrk[3]; double dN2[2],dN3[3]; double dcosjikdrj[3],dcosijldrj[3],dcosijldrl[3]; double Tij; double r32[3],r32mag,cos321,r43[3],r13[3]; double dNlj; double om1234,rln[3]; double rlnmag,dwln,r23[3],r23mag,r21[3],r21mag; double w21,dw21,r34[3],r34mag,cos234,w34,dw34; double cross321[3],cross234[3],prefactor,SpN; double fcijpc,fcikpc,fcjlpc,fcjkpc,fcilpc; double dt2dik[3],dt2djl[3],dt2dij[3],aa,aaa1,aaa2,at2,cw,cwnum,cwnom; double sin321,sin234,rr,rijrik,rijrjl,rjk2,rik2,ril2,rjl2; double dctik,dctjk,dctjl,dctij,dctji,dctil,rik2i,rjl2i,sink2i,sinl2i; double rjk[3],ril[3],dt1dik,dt1djk,dt1djl,dt1dil,dt1dij; double F23[3],F12[3],F34[3],F31[3],F24[3],fi[3],fj[3],fk[3],fl[3]; double f1[3],f2[3],f3[3],f4[4]; double dcut321,PijS,PjiS; double rij2,tspjik,dtsjik,tspijl,dtsijl,costmp; int *REBO_neighs,*REBO_neighs_i,*REBO_neighs_j,*REBO_neighs_k,*REBO_neighs_l; double **x = atom->x; int *type = atom->type; atomi = i; atomj = j; itype = map[type[i]]; jtype = map[type[j]]; wij = Sp(rijmag,rcmin[itype][jtype],rcmax[itype][jtype],dwij); NijC = nC[i]-(wij*kronecker(jtype,0)); NijH = nH[i]-(wij*kronecker(jtype,1)); NjiC = nC[j]-(wij*kronecker(itype,0)); NjiH = nH[j]-(wij*kronecker(itype,1)); bij = 0.0; tmp = 0.0; tmp2 = 0.0; tmp3 = 0.0; dgdc = 0.0; dgdN = 0.0; NconjtmpI = 0.0; NconjtmpJ = 0.0; Etmp = 0.0; REBO_neighs = REBO_firstneigh[i]; for (k = 0; k < REBO_numneigh[i]; k++) { atomk = REBO_neighs[k]; if (atomk != atomj) { ktype = map[type[atomk]]; rik[0] = x[atomi][0]-x[atomk][0]; rik[1] = x[atomi][1]-x[atomk][1]; rik[2] = x[atomi][2]-x[atomk][2]; rikmag = sqrt((rik[0]*rik[0])+(rik[1]*rik[1])+(rik[2]*rik[2])); lamdajik = 4.0*kronecker(itype,1) * ((rho[ktype][1]-rikmag)-(rho[jtype][1]-rijmag)); wik = Sp(rikmag,rcmin[itype][ktype],rcmax[itype][ktype],dS); Nki = nC[atomk]-(wik*kronecker(itype,0))+nH[atomk] - (wik*kronecker(itype,1)); cosjik = ((rij[0]*rik[0])+(rij[1]*rik[1])+(rij[2]*rik[2])) / (rijmag*rikmag); cosjik = MIN(cosjik,1.0); cosjik = MAX(cosjik,-1.0); // evaluate splines g and derivatives dg g = gSpline(cosjik,(NijC+NijH),itype,&dgdc,&dgdN); Etmp = Etmp+(wik*g*exp(lamdajik)); tmp3 = tmp3+(wik*dgdN*exp(lamdajik)); NconjtmpI = NconjtmpI+(kronecker(ktype,0)*wik*Sp(Nki,Nmin,Nmax,dS)); } } PijS = 0.0; dN2[0] = 0.0; dN2[1] = 0.0; PijS = PijSpline(NijC,NijH,itype,jtype,dN2); pij = pow(1.0+Etmp+PijS,-0.5); tmp = -0.5*pow(pij,3.0); // pij forces REBO_neighs = REBO_firstneigh[i]; for (k = 0; k < REBO_numneigh[i]; k++) { atomk = REBO_neighs[k]; if (atomk != atomj) { ktype = map[type[atomk]]; rik[0] = x[atomi][0]-x[atomk][0]; rik[1] = x[atomi][1]-x[atomk][1]; rik[2] = x[atomi][2]-x[atomk][2]; rikmag = sqrt((rik[0]*rik[0])+(rik[1]*rik[1])+(rik[2]*rik[2])); lamdajik = 4.0*kronecker(itype,1) * ((rho[ktype][1]-rikmag)-(rho[jtype][1]-rijmag)); wik = Sp(rikmag,rcmin[itype][ktype],rcmax[itype][ktype],dwik); cosjik = (rij[0]*rik[0] + rij[1]*rik[1] + rij[2]*rik[2]) / (rijmag*rikmag); cosjik = MIN(cosjik,1.0); cosjik = MAX(cosjik,-1.0); dcosjikdri[0] = ((rij[0]+rik[0])/(rijmag*rikmag)) - (cosjik*((rij[0]/(rijmag*rijmag))+(rik[0]/(rikmag*rikmag)))); dcosjikdri[1] = ((rij[1]+rik[1])/(rijmag*rikmag)) - (cosjik*((rij[1]/(rijmag*rijmag))+(rik[1]/(rikmag*rikmag)))); dcosjikdri[2] = ((rij[2]+rik[2])/(rijmag*rikmag)) - (cosjik*((rij[2]/(rijmag*rijmag))+(rik[2]/(rikmag*rikmag)))); dcosjikdrk[0] = (-rij[0]/(rijmag*rikmag)) + (cosjik*(rik[0]/(rikmag*rikmag))); dcosjikdrk[1] = (-rij[1]/(rijmag*rikmag)) + (cosjik*(rik[1]/(rikmag*rikmag))); dcosjikdrk[2] = (-rij[2]/(rijmag*rikmag)) + (cosjik*(rik[2]/(rikmag*rikmag))); dcosjikdrj[0] = (-rik[0]/(rijmag*rikmag)) + (cosjik*(rij[0]/(rijmag*rijmag))); dcosjikdrj[1] = (-rik[1]/(rijmag*rikmag)) + (cosjik*(rij[1]/(rijmag*rijmag))); dcosjikdrj[2] = (-rik[2]/(rijmag*rikmag)) + (cosjik*(rij[2]/(rijmag*rijmag))); g = gSpline(cosjik,(NijC+NijH),itype,&dgdc,&dgdN); tmp2 = VA*.5*(tmp*wik*dgdc*exp(lamdajik)); fj[0] = -tmp2*dcosjikdrj[0]; fj[1] = -tmp2*dcosjikdrj[1]; fj[2] = -tmp2*dcosjikdrj[2]; fi[0] = -tmp2*dcosjikdri[0]; fi[1] = -tmp2*dcosjikdri[1]; fi[2] = -tmp2*dcosjikdri[2]; fk[0] = -tmp2*dcosjikdrk[0]; fk[1] = -tmp2*dcosjikdrk[1]; fk[2] = -tmp2*dcosjikdrk[2]; tmp2 = VA*.5*(tmp*wik*g*exp(lamdajik)*4.0*kronecker(itype,1)); fj[0] -= tmp2*(-rij[0]/rijmag); fj[1] -= tmp2*(-rij[1]/rijmag); fj[2] -= tmp2*(-rij[2]/rijmag); fi[0] -= tmp2*((-rik[0]/rikmag)+(rij[0]/rijmag)); fi[1] -= tmp2*((-rik[1]/rikmag)+(rij[1]/rijmag)); fi[2] -= tmp2*((-rik[2]/rikmag)+(rij[2]/rijmag)); fk[0] -= tmp2*(rik[0]/rikmag); fk[1] -= tmp2*(rik[1]/rikmag); fk[2] -= tmp2*(rik[2]/rikmag); // coordination forces // dwik forces tmp2 = VA*.5*(tmp*dwik*g*exp(lamdajik))/rikmag; fi[0] -= tmp2*rik[0]; fi[1] -= tmp2*rik[1]; fi[2] -= tmp2*rik[2]; fk[0] += tmp2*rik[0]; fk[1] += tmp2*rik[1]; fk[2] += tmp2*rik[2]; // PIJ forces tmp2 = VA*.5*(tmp*dN2[ktype]*dwik)/rikmag; fi[0] -= tmp2*rik[0]; fi[1] -= tmp2*rik[1]; fi[2] -= tmp2*rik[2]; fk[0] += tmp2*rik[0]; fk[1] += tmp2*rik[1]; fk[2] += tmp2*rik[2]; // dgdN forces tmp2 = VA*.5*(tmp*tmp3*dwik)/rikmag; fi[0] -= tmp2*rik[0]; fi[1] -= tmp2*rik[1]; fi[2] -= tmp2*rik[2]; fk[0] += tmp2*rik[0]; fk[1] += tmp2*rik[1]; fk[2] += tmp2*rik[2]; f[atomi][0] += fi[0]; f[atomi][1] += fi[1]; f[atomi][2] += fi[2]; f[atomj][0] += fj[0]; f[atomj][1] += fj[1]; f[atomj][2] += fj[2]; f[atomk][0] += fk[0]; f[atomk][1] += fk[1]; f[atomk][2] += fk[2]; if (vflag_atom) { rji[0] = -rij[0]; rji[1] = -rij[1]; rji[2] = -rij[2]; rki[0] = -rik[0]; rki[1] = -rik[1]; rki[2] = -rik[2]; v_tally3(atomi,atomj,atomk,fj,fk,rji,rki); } } } tmp = 0.0; tmp2 = 0.0; tmp3 = 0.0; Etmp = 0.0; REBO_neighs = REBO_firstneigh[j]; for (l = 0; l < REBO_numneigh[j]; l++) { atoml = REBO_neighs[l]; if (atoml != atomi) { ltype = map[type[atoml]]; rjl[0] = x[atomj][0]-x[atoml][0]; rjl[1] = x[atomj][1]-x[atoml][1]; rjl[2] = x[atomj][2]-x[atoml][2]; rjlmag = sqrt((rjl[0]*rjl[0])+(rjl[1]*rjl[1])+(rjl[2]*rjl[2])); lamdaijl = 4.0*kronecker(jtype,1) * ((rho[ltype][1]-rjlmag)-(rho[itype][1]-rijmag)); wjl = Sp(rjlmag,rcmin[jtype][ltype],rcmax[jtype][ltype],dS); Nlj = nC[atoml]-(wjl*kronecker(jtype,0)) + nH[atoml]-(wjl*kronecker(jtype,1)); cosijl = -1.0*((rij[0]*rjl[0])+(rij[1]*rjl[1])+(rij[2]*rjl[2])) / (rijmag*rjlmag); cosijl = MIN(cosijl,1.0); cosijl = MAX(cosijl,-1.0); // evaluate splines g and derivatives dg g = gSpline(cosijl,NjiC+NjiH,jtype,&dgdc,&dgdN); Etmp = Etmp+(wjl*g*exp(lamdaijl)); tmp3 = tmp3+(wjl*dgdN*exp(lamdaijl)); NconjtmpJ = NconjtmpJ+(kronecker(ltype,0)*wjl*Sp(Nlj,Nmin,Nmax,dS)); } } PjiS = 0.0; dN2[0] = 0.0; dN2[1] = 0.0; PjiS = PijSpline(NjiC,NjiH,jtype,itype,dN2); pji = pow(1.0+Etmp+PjiS,-0.5); tmp = -0.5*pow(pji,3.0); REBO_neighs = REBO_firstneigh[j]; for (l = 0; l < REBO_numneigh[j]; l++) { atoml = REBO_neighs[l]; if (atoml != atomi) { ltype = map[type[atoml]]; rjl[0] = x[atomj][0]-x[atoml][0]; rjl[1] = x[atomj][1]-x[atoml][1]; rjl[2] = x[atomj][2]-x[atoml][2]; rjlmag = sqrt((rjl[0]*rjl[0])+(rjl[1]*rjl[1])+(rjl[2]*rjl[2])); lamdaijl = 4.0*kronecker(jtype,1) * ((rho[ltype][1]-rjlmag)-(rho[itype][1]-rijmag)); wjl = Sp(rjlmag,rcmin[jtype][ltype],rcmax[jtype][ltype],dwjl); cosijl = (-1.0*((rij[0]*rjl[0])+(rij[1]*rjl[1])+(rij[2]*rjl[2]))) / (rijmag*rjlmag); cosijl = MIN(cosijl,1.0); cosijl = MAX(cosijl,-1.0); dcosijldri[0] = (-rjl[0]/(rijmag*rjlmag)) - (cosijl*rij[0]/(rijmag*rijmag)); dcosijldri[1] = (-rjl[1]/(rijmag*rjlmag)) - (cosijl*rij[1]/(rijmag*rijmag)); dcosijldri[2] = (-rjl[2]/(rijmag*rjlmag)) - (cosijl*rij[2]/(rijmag*rijmag)); dcosijldrj[0] = ((-rij[0]+rjl[0])/(rijmag*rjlmag)) + (cosijl*((rij[0]/pow(rijmag,2.0))-(rjl[0]/(rjlmag*rjlmag)))); dcosijldrj[1] = ((-rij[1]+rjl[1])/(rijmag*rjlmag)) + (cosijl*((rij[1]/pow(rijmag,2.0))-(rjl[1]/(rjlmag*rjlmag)))); dcosijldrj[2] = ((-rij[2]+rjl[2])/(rijmag*rjlmag)) + (cosijl*((rij[2]/pow(rijmag,2.0))-(rjl[2]/(rjlmag*rjlmag)))); dcosijldrl[0] = (rij[0]/(rijmag*rjlmag))+(cosijl*rjl[0]/(rjlmag*rjlmag)); dcosijldrl[1] = (rij[1]/(rijmag*rjlmag))+(cosijl*rjl[1]/(rjlmag*rjlmag)); dcosijldrl[2] = (rij[2]/(rijmag*rjlmag))+(cosijl*rjl[2]/(rjlmag*rjlmag)); // evaluate splines g and derivatives dg g = gSpline(cosijl,NjiC+NjiH,jtype,&dgdc,&dgdN); tmp2 = VA*.5*(tmp*wjl*dgdc*exp(lamdaijl)); fi[0] = -tmp2*dcosijldri[0]; fi[1] = -tmp2*dcosijldri[1]; fi[2] = -tmp2*dcosijldri[2]; fj[0] = -tmp2*dcosijldrj[0]; fj[1] = -tmp2*dcosijldrj[1]; fj[2] = -tmp2*dcosijldrj[2]; fl[0] = -tmp2*dcosijldrl[0]; fl[1] = -tmp2*dcosijldrl[1]; fl[2] = -tmp2*dcosijldrl[2]; tmp2 = VA*.5*(tmp*wjl*g*exp(lamdaijl)*4.0*kronecker(jtype,1)); fi[0] -= tmp2*(rij[0]/rijmag); fi[1] -= tmp2*(rij[1]/rijmag); fi[2] -= tmp2*(rij[2]/rijmag); fj[0] -= tmp2*((-rjl[0]/rjlmag)-(rij[0]/rijmag)); fj[1] -= tmp2*((-rjl[1]/rjlmag)-(rij[1]/rijmag)); fj[2] -= tmp2*((-rjl[2]/rjlmag)-(rij[2]/rijmag)); fl[0] -= tmp2*(rjl[0]/rjlmag); fl[1] -= tmp2*(rjl[1]/rjlmag); fl[2] -= tmp2*(rjl[2]/rjlmag); // coordination forces // dwik forces tmp2 = VA*.5*(tmp*dwjl*g*exp(lamdaijl))/rjlmag; fj[0] -= tmp2*rjl[0]; fj[1] -= tmp2*rjl[1]; fj[2] -= tmp2*rjl[2]; fl[0] += tmp2*rjl[0]; fl[1] += tmp2*rjl[1]; fl[2] += tmp2*rjl[2]; // PIJ forces tmp2 = VA*.5*(tmp*dN2[ltype]*dwjl)/rjlmag; fj[0] -= tmp2*rjl[0]; fj[1] -= tmp2*rjl[1]; fj[2] -= tmp2*rjl[2]; fl[0] += tmp2*rjl[0]; fl[1] += tmp2*rjl[1]; fl[2] += tmp2*rjl[2]; // dgdN forces tmp2 = VA*.5*(tmp*tmp3*dwjl)/rjlmag; fj[0] -= tmp2*rjl[0]; fj[1] -= tmp2*rjl[1]; fj[2] -= tmp2*rjl[2]; fl[0] += tmp2*rjl[0]; fl[1] += tmp2*rjl[1]; fl[2] += tmp2*rjl[2]; f[atomi][0] += fi[0]; f[atomi][1] += fi[1]; f[atomi][2] += fi[2]; f[atomj][0] += fj[0]; f[atomj][1] += fj[1]; f[atomj][2] += fj[2]; f[atoml][0] += fl[0]; f[atoml][1] += fl[1]; f[atoml][2] += fl[2]; if (vflag_atom) { rlj[0] = -rjl[0]; rlj[1] = -rjl[1]; rlj[2] = -rjl[2]; v_tally3(atomi,atomj,atoml,fi,fl,rij,rlj); } } } // evaluate Nij conj Nijconj = 1.0+(NconjtmpI*NconjtmpI)+(NconjtmpJ*NconjtmpJ); piRC = piRCSpline(NijC+NijH,NjiC+NjiH,Nijconj,itype,jtype,dN3); // piRC forces REBO_neighs_i = REBO_firstneigh[i]; for (k = 0; k < REBO_numneigh[i]; k++) { atomk = REBO_neighs_i[k]; if (atomk !=atomj) { ktype = map[type[atomk]]; rik[0] = x[atomi][0]-x[atomk][0]; rik[1] = x[atomi][1]-x[atomk][1]; rik[2] = x[atomi][2]-x[atomk][2]; rikmag = sqrt((rik[0]*rik[0])+(rik[1]*rik[1])+(rik[2]*rik[2])); wik = Sp(rikmag,rcmin[itype][ktype],rcmax[itype][ktype],dwik); Nki = nC[atomk]-(wik*kronecker(itype,0))+nH[atomk] - (wik*kronecker(itype,1)); SpN = Sp(Nki,Nmin,Nmax,dNki); tmp2 = VA*dN3[0]*dwik/rikmag; f[atomi][0] -= tmp2*rik[0]; f[atomi][1] -= tmp2*rik[1]; f[atomi][2] -= tmp2*rik[2]; f[atomk][0] += tmp2*rik[0]; f[atomk][1] += tmp2*rik[1]; f[atomk][2] += tmp2*rik[2]; if (vflag_atom) v_tally2(atomi,atomk,-tmp2,rik); tmp2 = VA*dN3[2]*(2.0*NconjtmpI*dwik*SpN)/rikmag; f[atomi][0] -= tmp2*rik[0]; f[atomi][1] -= tmp2*rik[1]; f[atomi][2] -= tmp2*rik[2]; f[atomk][0] += tmp2*rik[0]; f[atomk][1] += tmp2*rik[1]; f[atomk][2] += tmp2*rik[2]; if (vflag_atom) v_tally2(atomi,atomk,-tmp2,rik); if (fabs(dNki) > TOL) { REBO_neighs_k = REBO_firstneigh[atomk]; for (n = 0; n < REBO_numneigh[atomk]; n++) { atomn = REBO_neighs_k[n]; if (atomn != atomi) { ntype = map[type[atomn]]; rkn[0] = x[atomk][0]-x[atomn][0]; rkn[1] = x[atomk][1]-x[atomn][1]; rkn[2] = x[atomk][2]-x[atomn][2]; rknmag = sqrt((rkn[0]*rkn[0])+(rkn[1]*rkn[1])+(rkn[2]*rkn[2])); Sp(rknmag,rcmin[ktype][ntype],rcmax[ktype][ntype],dwkn); tmp2 = VA*dN3[2]*(2.0*NconjtmpI*wik*dNki*dwkn)/rknmag; f[atomk][0] -= tmp2*rkn[0]; f[atomk][1] -= tmp2*rkn[1]; f[atomk][2] -= tmp2*rkn[2]; f[atomn][0] += tmp2*rkn[0]; f[atomn][1] += tmp2*rkn[1]; f[atomn][2] += tmp2*rkn[2]; if (vflag_atom) v_tally2(atomk,atomn,-tmp2,rkn); } } } } } // piRC forces REBO_neighs = REBO_firstneigh[atomj]; for (l = 0; l < REBO_numneigh[atomj]; l++) { atoml = REBO_neighs[l]; if (atoml !=atomi) { ltype = map[type[atoml]]; rjl[0] = x[atomj][0]-x[atoml][0]; rjl[1] = x[atomj][1]-x[atoml][1]; rjl[2] = x[atomj][2]-x[atoml][2]; rjlmag = sqrt((rjl[0]*rjl[0])+(rjl[1]*rjl[1])+(rjl[2]*rjl[2])); wjl = Sp(rjlmag,rcmin[jtype][ltype],rcmax[jtype][ltype],dwjl); Nlj = nC[atoml]-(wjl*kronecker(jtype,0))+nH[atoml] - (wjl*kronecker(jtype,1)); SpN = Sp(Nlj,Nmin,Nmax,dNlj); tmp2 = VA*dN3[1]*dwjl/rjlmag; f[atomj][0] -= tmp2*rjl[0]; f[atomj][1] -= tmp2*rjl[1]; f[atomj][2] -= tmp2*rjl[2]; f[atoml][0] += tmp2*rjl[0]; f[atoml][1] += tmp2*rjl[1]; f[atoml][2] += tmp2*rjl[2]; if (vflag_atom) v_tally2(atomj,atoml,-tmp2,rjl); tmp2 = VA*dN3[2]*(2.0*NconjtmpJ*dwjl*SpN)/rjlmag; f[atomj][0] -= tmp2*rjl[0]; f[atomj][1] -= tmp2*rjl[1]; f[atomj][2] -= tmp2*rjl[2]; f[atoml][0] += tmp2*rjl[0]; f[atoml][1] += tmp2*rjl[1]; f[atoml][2] += tmp2*rjl[2]; if (vflag_atom) v_tally2(atomj,atoml,-tmp2,rjl); if (fabs(dNlj) > TOL) { REBO_neighs_l = REBO_firstneigh[atoml]; for (n = 0; n < REBO_numneigh[atoml]; n++) { atomn = REBO_neighs_l[n]; if (atomn != atomj) { ntype = map[type[atomn]]; rln[0] = x[atoml][0]-x[atomn][0]; rln[1] = x[atoml][1]-x[atomn][1]; rln[2] = x[atoml][2]-x[atomn][2]; rlnmag = sqrt((rln[0]*rln[0])+(rln[1]*rln[1])+(rln[2]*rln[2])); Sp(rlnmag,rcmin[ltype][ntype],rcmax[ltype][ntype],dwln); tmp2 = VA*dN3[2]*(2.0*NconjtmpJ*wjl*dNlj*dwln)/rlnmag; f[atoml][0] -= tmp2*rln[0]; f[atoml][1] -= tmp2*rln[1]; f[atoml][2] -= tmp2*rln[2]; f[atomn][0] += tmp2*rln[0]; f[atomn][1] += tmp2*rln[1]; f[atomn][2] += tmp2*rln[2]; if (vflag_atom) v_tally2(atoml,atomn,-tmp2,rln); } } } } } Tij = 0.0; dN3[0] = 0.0; dN3[1] = 0.0; dN3[2] = 0.0; if (itype == 0 && jtype == 0) Tij=TijSpline((NijC+NijH),(NjiC+NjiH),Nijconj,dN3); Etmp = 0.0; if (fabs(Tij) > TOL) { atom2 = atomi; atom3 = atomj; r32[0] = x[atom3][0]-x[atom2][0]; r32[1] = x[atom3][1]-x[atom2][1]; r32[2] = x[atom3][2]-x[atom2][2]; r32mag = sqrt((r32[0]*r32[0])+(r32[1]*r32[1])+(r32[2]*r32[2])); r23[0] = -r32[0]; r23[1] = -r32[1]; r23[2] = -r32[2]; r23mag = r32mag; REBO_neighs_i = REBO_firstneigh[i]; for (k = 0; k < REBO_numneigh[i]; k++) { atomk = REBO_neighs_i[k]; atom1 = atomk; ktype = map[type[atomk]]; if (atomk != atomj) { r21[0] = x[atom2][0]-x[atom1][0]; r21[1] = x[atom2][1]-x[atom1][1]; r21[2] = x[atom2][2]-x[atom1][2]; r21mag = sqrt(r21[0]*r21[0] + r21[1]*r21[1] + r21[2]*r21[2]); cos321 = -1.0*((r21[0]*r32[0])+(r21[1]*r32[1])+(r21[2]*r32[2])) / (r21mag*r32mag); cos321 = MIN(cos321,1.0); cos321 = MAX(cos321,-1.0); Sp2(cos321,thmin,thmax,dcut321); sin321 = sqrt(1.0 - cos321*cos321); sink2i = 1.0/(sin321*sin321); rik2i = 1.0/(r21mag*r21mag); if (sin321 != 0.0) { rr = (r23mag*r23mag)-(r21mag*r21mag); rjk[0] = r21[0]-r23[0]; rjk[1] = r21[1]-r23[1]; rjk[2] = r21[2]-r23[2]; rjk2 = (rjk[0]*rjk[0])+(rjk[1]*rjk[1])+(rjk[2]*rjk[2]); rijrik = 2.0*r23mag*r21mag; rik2 = r21mag*r21mag; dctik = (-rr+rjk2)/(rijrik*rik2); dctij = (rr+rjk2)/(rijrik*r23mag*r23mag); dctjk = -2.0/rijrik; w21 = Sp(r21mag,rcmin[itype][ktype],rcmaxp[itype][ktype],dw21); rijmag = r32mag; rikmag = r21mag; rij2 = r32mag*r32mag; rik2 = r21mag*r21mag; costmp = 0.5*(rij2+rik2-rjk2)/rijmag/rikmag; tspjik = Sp2(costmp,thmin,thmax,dtsjik); dtsjik = -dtsjik; REBO_neighs_j = REBO_firstneigh[j]; for (l = 0; l < REBO_numneigh[j]; l++) { atoml = REBO_neighs_j[l]; atom4 = atoml; ltype = map[type[atoml]]; if (!(atoml == atomi || atoml == atomk)) { r34[0] = x[atom3][0]-x[atom4][0]; r34[1] = x[atom3][1]-x[atom4][1]; r34[2] = x[atom3][2]-x[atom4][2]; r34mag = sqrt((r34[0]*r34[0])+(r34[1]*r34[1])+(r34[2]*r34[2])); cos234 = (r32[0]*r34[0] + r32[1]*r34[1] + r32[2]*r34[2]) / (r32mag*r34mag); cos234 = MIN(cos234,1.0); cos234 = MAX(cos234,-1.0); sin234 = sqrt(1.0 - cos234*cos234); sinl2i = 1.0/(sin234*sin234); rjl2i = 1.0/(r34mag*r34mag); if (sin234 != 0.0) { w34 = Sp(r34mag,rcmin[jtype][ltype],rcmaxp[jtype][ltype],dw34); rr = (r23mag*r23mag)-(r34mag*r34mag); ril[0] = r23[0]+r34[0]; ril[1] = r23[1]+r34[1]; ril[2] = r23[2]+r34[2]; ril2 = (ril[0]*ril[0])+(ril[1]*ril[1])+(ril[2]*ril[2]); rijrjl = 2.0*r23mag*r34mag; rjl2 = r34mag*r34mag; dctjl = (-rr+ril2)/(rijrjl*rjl2); dctji = (rr+ril2)/(rijrjl*r23mag*r23mag); dctil = -2.0/rijrjl; rjlmag = r34mag; rjl2 = r34mag*r34mag; costmp = 0.5*(rij2+rjl2-ril2)/rijmag/rjlmag; tspijl = Sp2(costmp,thmin,thmax,dtsijl); dtsijl = -dtsijl; prefactor = VA*Tij; cross321[0] = (r32[1]*r21[2])-(r32[2]*r21[1]); cross321[1] = (r32[2]*r21[0])-(r32[0]*r21[2]); cross321[2] = (r32[0]*r21[1])-(r32[1]*r21[0]); cross234[0] = (r23[1]*r34[2])-(r23[2]*r34[1]); cross234[1] = (r23[2]*r34[0])-(r23[0]*r34[2]); cross234[2] = (r23[0]*r34[1])-(r23[1]*r34[0]); cwnum = (cross321[0]*cross234[0]) + (cross321[1]*cross234[1]) + (cross321[2]*cross234[2]); cwnom = r21mag*r34mag*r23mag*r23mag*sin321*sin234; om1234 = cwnum/cwnom; cw = om1234; Etmp += ((1.0-pow(om1234,2.0))*w21*w34) * (1.0-tspjik)*(1.0-tspijl); dt1dik = (rik2i)-(dctik*sink2i*cos321); dt1djk = (-dctjk*sink2i*cos321); dt1djl = (rjl2i)-(dctjl*sinl2i*cos234); dt1dil = (-dctil*sinl2i*cos234); dt1dij = (2.0/(r23mag*r23mag))-(dctij*sink2i*cos321) - (dctji*sinl2i*cos234); dt2dik[0] = (-r23[2]*cross234[1])+(r23[1]*cross234[2]); dt2dik[1] = (-r23[0]*cross234[2])+(r23[2]*cross234[0]); dt2dik[2] = (-r23[1]*cross234[0])+(r23[0]*cross234[1]); dt2djl[0] = (-r23[1]*cross321[2])+(r23[2]*cross321[1]); dt2djl[1] = (-r23[2]*cross321[0])+(r23[0]*cross321[2]); dt2djl[2] = (-r23[0]*cross321[1])+(r23[1]*cross321[0]); dt2dij[0] = (r21[2]*cross234[1])-(r34[2]*cross321[1]) - (r21[1]*cross234[2])+(r34[1]*cross321[2]); dt2dij[1] = (r21[0]*cross234[2])-(r34[0]*cross321[2]) - (r21[2]*cross234[0])+(r34[2]*cross321[0]); dt2dij[2] = (r21[1]*cross234[0])-(r34[1]*cross321[0]) - (r21[0]*cross234[1])+(r34[0]*cross321[1]); aa = (prefactor*2.0*cw/cwnom)*w21*w34 * (1.0-tspjik)*(1.0-tspijl); aaa1 = -prefactor*(1.0-pow(om1234,2.0)) * (1.0-tspjik)*(1.0-tspijl); aaa2 = aaa1*w21*w34; at2 = aa*cwnum; fcijpc = (-dt1dij*at2)+(aaa2*dtsjik*dctij*(1.0-tspijl)) + (aaa2*dtsijl*dctji*(1.0-tspjik)); fcikpc = (-dt1dik*at2)+(aaa2*dtsjik*dctik*(1.0-tspijl)); fcjlpc = (-dt1djl*at2)+(aaa2*dtsijl*dctjl*(1.0-tspjik)); fcjkpc = (-dt1djk*at2)+(aaa2*dtsjik*dctjk*(1.0-tspijl)); fcilpc = (-dt1dil*at2)+(aaa2*dtsijl*dctil*(1.0-tspjik)); F23[0] = (fcijpc*r23[0])+(aa*dt2dij[0]); F23[1] = (fcijpc*r23[1])+(aa*dt2dij[1]); F23[2] = (fcijpc*r23[2])+(aa*dt2dij[2]); F12[0] = (fcikpc*r21[0])+(aa*dt2dik[0]); F12[1] = (fcikpc*r21[1])+(aa*dt2dik[1]); F12[2] = (fcikpc*r21[2])+(aa*dt2dik[2]); F34[0] = (fcjlpc*r34[0])+(aa*dt2djl[0]); F34[1] = (fcjlpc*r34[1])+(aa*dt2djl[1]); F34[2] = (fcjlpc*r34[2])+(aa*dt2djl[2]); F31[0] = (fcjkpc*rjk[0]); F31[1] = (fcjkpc*rjk[1]); F31[2] = (fcjkpc*rjk[2]); F24[0] = (fcilpc*ril[0]); F24[1] = (fcilpc*ril[1]); F24[2] = (fcilpc*ril[2]); f1[0] = -F12[0]-F31[0]; f1[1] = -F12[1]-F31[1]; f1[2] = -F12[2]-F31[2]; f2[0] = F23[0]+F12[0]+F24[0]; f2[1] = F23[1]+F12[1]+F24[1]; f2[2] = F23[2]+F12[2]+F24[2]; f3[0] = -F23[0]+F34[0]+F31[0]; f3[1] = -F23[1]+F34[1]+F31[1]; f3[2] = -F23[2]+F34[2]+F31[2]; f4[0] = -F34[0]-F24[0]; f4[1] = -F34[1]-F24[1]; f4[2] = -F34[2]-F24[2]; // coordination forces tmp2 = VA*Tij*((1.0-(om1234*om1234))) * (1.0-tspjik)*(1.0-tspijl)*dw21*w34/r21mag; f2[0] -= tmp2*r21[0]; f2[1] -= tmp2*r21[1]; f2[2] -= tmp2*r21[2]; f1[0] += tmp2*r21[0]; f1[1] += tmp2*r21[1]; f1[2] += tmp2*r21[2]; tmp2 = VA*Tij*((1.0-(om1234*om1234))) * (1.0-tspjik)*(1.0-tspijl)*w21*dw34/r34mag; f3[0] -= tmp2*r34[0]; f3[1] -= tmp2*r34[1]; f3[2] -= tmp2*r34[2]; f4[0] += tmp2*r34[0]; f4[1] += tmp2*r34[1]; f4[2] += tmp2*r34[2]; f[atom1][0] += f1[0]; f[atom1][1] += f1[1]; f[atom1][2] += f1[2]; f[atom2][0] += f2[0]; f[atom2][1] += f2[1]; f[atom2][2] += f2[2]; f[atom3][0] += f3[0]; f[atom3][1] += f3[1]; f[atom3][2] += f3[2]; f[atom4][0] += f4[0]; f[atom4][1] += f4[1]; f[atom4][2] += f4[2]; if (vflag_atom) { r13[0] = -rjk[0]; r13[1] = -rjk[1]; r13[2] = -rjk[2]; r43[0] = -r34[0]; r43[1] = -r34[1]; r43[2] = -r34[2]; v_tally4(atom1,atom2,atom3,atom4,f1,f2,f4,r13,r23,r43); } } } } } } } // Tij forces now that we have Etmp REBO_neighs = REBO_firstneigh[i]; for (k = 0; k < REBO_numneigh[i]; k++) { atomk = REBO_neighs[k]; if (atomk != atomj) { ktype = map[type[atomk]]; rik[0] = x[atomi][0]-x[atomk][0]; rik[1] = x[atomi][1]-x[atomk][1]; rik[2] = x[atomi][2]-x[atomk][2]; rikmag = sqrt((rik[0]*rik[0])+(rik[1]*rik[1])+(rik[2]*rik[2])); wik = Sp(rikmag,rcmin[itype][ktype],rcmax[itype][ktype],dwik); Nki = nC[atomk]-(wik*kronecker(itype,0))+nH[atomk] - (wik*kronecker(itype,1)); SpN = Sp(Nki,Nmin,Nmax,dNki); tmp2 = VA*dN3[0]*dwik*Etmp/rikmag; f[atomi][0] -= tmp2*rik[0]; f[atomi][1] -= tmp2*rik[1]; f[atomi][2] -= tmp2*rik[2]; f[atomk][0] += tmp2*rik[0]; f[atomk][1] += tmp2*rik[1]; f[atomk][2] += tmp2*rik[2]; if (vflag_atom) v_tally2(atomi,atomk,-tmp2,rik); tmp2 = VA*dN3[2]*(2.0*NconjtmpI*dwik*SpN)*Etmp/rikmag; f[atomi][0] -= tmp2*rik[0]; f[atomi][1] -= tmp2*rik[1]; f[atomi][2] -= tmp2*rik[2]; f[atomk][0] += tmp2*rik[0]; f[atomk][1] += tmp2*rik[1]; f[atomk][2] += tmp2*rik[2]; if (vflag_atom) v_tally2(atomi,atomk,-tmp2,rik); if (fabs(dNki) > TOL) { REBO_neighs_k = REBO_firstneigh[atomk]; for (n = 0; n < REBO_numneigh[atomk]; n++) { atomn = REBO_neighs_k[n]; ntype = map[type[atomn]]; if (atomn != atomi) { rkn[0] = x[atomk][0]-x[atomn][0]; rkn[1] = x[atomk][1]-x[atomn][1]; rkn[2] = x[atomk][2]-x[atomn][2]; rknmag = sqrt((rkn[0]*rkn[0])+(rkn[1]*rkn[1])+(rkn[2]*rkn[2])); Sp(rknmag,rcmin[ktype][ntype],rcmax[ktype][ntype],dwkn); tmp2 = VA*dN3[2]*(2.0*NconjtmpI*wik*dNki*dwkn)*Etmp/rknmag; f[atomk][0] -= tmp2*rkn[0]; f[atomk][1] -= tmp2*rkn[1]; f[atomk][2] -= tmp2*rkn[2]; f[atomn][0] += tmp2*rkn[0]; f[atomn][1] += tmp2*rkn[1]; f[atomn][2] += tmp2*rkn[2]; if (vflag_atom) v_tally2(atomk,atomn,-tmp2,rkn); } } } } } // Tij forces REBO_neighs = REBO_firstneigh[j]; for (l = 0; l < REBO_numneigh[j]; l++) { atoml = REBO_neighs[l]; if (atoml != atomi) { ltype = map[type[atoml]]; rjl[0] = x[atomj][0]-x[atoml][0]; rjl[1] = x[atomj][1]-x[atoml][1]; rjl[2] = x[atomj][2]-x[atoml][2]; rjlmag = sqrt((rjl[0]*rjl[0])+(rjl[1]*rjl[1])+(rjl[2]*rjl[2])); wjl = Sp(rjlmag,rcmin[jtype][ltype],rcmax[jtype][ltype],dwjl); Nlj = nC[atoml]-(wjl*kronecker(jtype,0))+nH[atoml] - (wjl*kronecker(jtype,1)); SpN = Sp(Nlj,Nmin,Nmax,dNlj); tmp2 = VA*dN3[1]*dwjl*Etmp/rjlmag; f[atomj][0] -= tmp2*rjl[0]; f[atomj][1] -= tmp2*rjl[1]; f[atomj][2] -= tmp2*rjl[2]; f[atoml][0] += tmp2*rjl[0]; f[atoml][1] += tmp2*rjl[1]; f[atoml][2] += tmp2*rjl[2]; if (vflag_atom) v_tally2(atomj,atoml,-tmp2,rjl); tmp2 = VA*dN3[2]*(2.0*NconjtmpJ*dwjl*SpN)*Etmp/rjlmag; f[atomj][0] -= tmp2*rjl[0]; f[atomj][1] -= tmp2*rjl[1]; f[atomj][2] -= tmp2*rjl[2]; f[atoml][0] += tmp2*rjl[0]; f[atoml][1] += tmp2*rjl[1]; f[atoml][2] += tmp2*rjl[2]; if (vflag_atom) v_tally2(atomj,atoml,-tmp2,rjl); if (fabs(dNlj) > TOL) { REBO_neighs_l = REBO_firstneigh[atoml]; for (n = 0; n < REBO_numneigh[atoml]; n++) { atomn = REBO_neighs_l[n]; ntype = map[type[atomn]]; if (atomn !=atomj) { rln[0] = x[atoml][0]-x[atomn][0]; rln[1] = x[atoml][1]-x[atomn][1]; rln[2] = x[atoml][2]-x[atomn][2]; rlnmag = sqrt((rln[0]*rln[0])+(rln[1]*rln[1])+(rln[2]*rln[2])); Sp(rlnmag,rcmin[ltype][ntype],rcmax[ltype][ntype],dwln); tmp2 = VA*dN3[2]*(2.0*NconjtmpJ*wjl*dNlj*dwln)*Etmp/rlnmag; f[atoml][0] -= tmp2*rln[0]; f[atoml][1] -= tmp2*rln[1]; f[atoml][2] -= tmp2*rln[2]; f[atomn][0] += tmp2*rln[0]; f[atomn][1] += tmp2*rln[1]; f[atomn][2] += tmp2*rln[2]; if (vflag_atom) v_tally2(atoml,atomn,-tmp2,rln); } } } } } } bij = (0.5*(pij+pji))+piRC+(Tij*Etmp); return bij; } /* ---------------------------------------------------------------------- Bij* function ------------------------------------------------------------------------- */ double PairAIREBO::bondorderLJ(int i, int j, double rij[3], double rijmag, double VA, double rij0[3], double rij0mag, double **f, int vflag_atom) { int k,n,l,atomk,atoml,atomn,atom1,atom2,atom3,atom4; int atomi,atomj,itype,jtype,ktype,ltype,ntype; double rik[3], rjl[3], rkn[3],rknmag,dNki; double NijC,NijH,NjiC,NjiH,wik,dwik,dwkn,wjl; double rikmag,rjlmag,cosjik,cosijl,g,tmp2,tmp3; double Etmp,pij,tmp,wij,dwij,NconjtmpI,NconjtmpJ; double Nki,Nlj,dS,lamdajik,lamdaijl,dgdc,dgdN,pji,Nijconj,piRC; double dcosjikdri[3],dcosijldri[3],dcosjikdrk[3]; double dN2[2],dN3[3]; double dcosijldrj[3],dcosijldrl[3],dcosjikdrj[3],dwjl; double Tij,crosskij[3],crosskijmag; double crossijl[3],crossijlmag,omkijl; double tmppij,tmppji,dN2PIJ[2],dN2PJI[2],dN3piRC[3],dN3Tij[3]; double bij,tmp3pij,tmp3pji,Stb,dStb; double r32[3],r32mag,cos321; double om1234,rln[3]; double rlnmag,dwln,r23[3],r23mag,r21[3],r21mag; double w21,dw21,r34[3],r34mag,cos234,w34,dw34; double cross321[3],cross234[3],prefactor,SpN; double fcijpc,fcikpc,fcjlpc,fcjkpc,fcilpc; double dt2dik[3],dt2djl[3],dt2dij[3],aa,aaa1,aaa2,at2,cw,cwnum,cwnom; double sin321,sin234,rr,rijrik,rijrjl,rjk2,rik2,ril2,rjl2; double dctik,dctjk,dctjl,dctij,dctji,dctil,rik2i,rjl2i,sink2i,sinl2i; double rjk[3],ril[3],dt1dik,dt1djk,dt1djl,dt1dil,dt1dij; double dNlj; double PijS,PjiS; double rij2,tspjik,dtsjik,tspijl,dtsijl,costmp; int *REBO_neighs,*REBO_neighs_i,*REBO_neighs_j,*REBO_neighs_k,*REBO_neighs_l; double F12[3],F23[3],F34[3],F31[3],F24[3]; double fi[3],fj[3],fk[3],fl[3],f1[3],f2[3],f3[3],f4[4]; double rji[3],rki[3],rlj[3],r13[3],r43[3]; double **x = atom->x; int *type = atom->type; atomi = i; atomj = j; itype = map[type[atomi]]; jtype = map[type[atomj]]; wij = Sp(rij0mag,rcmin[itype][jtype],rcmax[itype][jtype],dwij); NijC = nC[atomi]-(wij*kronecker(jtype,0)); NijH = nH[atomi]-(wij*kronecker(jtype,1)); NjiC = nC[atomj]-(wij*kronecker(itype,0)); NjiH = nH[atomj]-(wij*kronecker(itype,1)); rij[0] = rij0[0]; rij[1] = rij0[1]; rij[2] = rij0[2]; rijmag = rij0mag; bij = 0.0; tmp = 0.0; tmp2 = 0.0; tmp3 = 0.0; dgdc = 0.0; dgdN = 0.0; NconjtmpI = 0.0; NconjtmpJ = 0.0; Etmp = 0.0; REBO_neighs = REBO_firstneigh[i]; for (k = 0; k < REBO_numneigh[i]; k++) { atomk = REBO_neighs[k]; if (atomk != atomj) { ktype = map[type[atomk]]; rik[0] = x[atomi][0]-x[atomk][0]; rik[1] = x[atomi][1]-x[atomk][1]; rik[2] = x[atomi][2]-x[atomk][2]; rikmag = sqrt((rik[0]*rik[0])+(rik[1]*rik[1])+(rik[2]*rik[2])); lamdajik = 4.0*kronecker(itype,1) * ((rho[ktype][1]-rikmag)-(rho[jtype][1]-rijmag)); wik = Sp(rikmag,rcmin[itype][ktype],rcmax[itype][ktype],dS); Nki = nC[atomk]-(wik*kronecker(itype,0)) + nH[atomk]-(wik*kronecker(itype,1)); cosjik = ((rij[0]*rik[0])+(rij[1]*rik[1])+(rij[2]*rik[2])) / (rijmag*rikmag); cosjik = MIN(cosjik,1.0); cosjik = MAX(cosjik,-1.0); // evaluate splines g and derivatives dg g = gSpline(cosjik,(NijC+NijH),itype,&dgdc,&dgdN); Etmp = Etmp+(wik*g*exp(lamdajik)); tmp3 = tmp3+(wik*dgdN*exp(lamdajik)); NconjtmpI = NconjtmpI+(kronecker(ktype,0)*wik*Sp(Nki,Nmin,Nmax,dS)); } } PijS = 0.0; dN2PIJ[0] = 0.0; dN2PIJ[1] = 0.0; PijS = PijSpline(NijC,NijH,itype,jtype,dN2PIJ); pij = pow(1.0+Etmp+PijS,-0.5); tmppij = -.5*pow(pij,3.0); tmp3pij = tmp3; tmp = 0.0; tmp2 = 0.0; tmp3 = 0.0; Etmp = 0.0; REBO_neighs = REBO_firstneigh[j]; for (l = 0; l < REBO_numneigh[j]; l++) { atoml = REBO_neighs[l]; if (atoml != atomi) { ltype = map[type[atoml]]; rjl[0] = x[atomj][0]-x[atoml][0]; rjl[1] = x[atomj][1]-x[atoml][1]; rjl[2] = x[atomj][2]-x[atoml][2]; rjlmag = sqrt((rjl[0]*rjl[0])+(rjl[1]*rjl[1])+(rjl[2]*rjl[2])); lamdaijl = 4.0*kronecker(jtype,1) * ((rho[ltype][1]-rjlmag)-(rho[itype][1]-rijmag)); wjl = Sp(rjlmag,rcmin[jtype][ltype],rcmax[jtype][ltype],dS); Nlj = nC[atoml]-(wjl*kronecker(jtype,0))+nH[atoml] - (wjl*kronecker(jtype,1)); cosijl = -1.0*((rij[0]*rjl[0])+(rij[1]*rjl[1])+(rij[2]*rjl[2])) / (rijmag*rjlmag); cosijl = MIN(cosijl,1.0); cosijl = MAX(cosijl,-1.0); // evaluate splines g and derivatives dg g = gSpline(cosijl,NjiC+NjiH,jtype,&dgdc,&dgdN); Etmp = Etmp+(wjl*g*exp(lamdaijl)); tmp3 = tmp3+(wjl*dgdN*exp(lamdaijl)); NconjtmpJ = NconjtmpJ+(kronecker(ltype,0)*wjl*Sp(Nlj,Nmin,Nmax,dS)); } } PjiS = 0.0; dN2PJI[0] = 0.0; dN2PJI[1] = 0.0; PjiS = PijSpline(NjiC,NjiH,jtype,itype,dN2PJI); pji = pow(1.0+Etmp+PjiS,-0.5); tmppji = -.5*pow(pji,3.0); tmp3pji = tmp3; // evaluate Nij conj Nijconj = 1.0+(NconjtmpI*NconjtmpI)+(NconjtmpJ*NconjtmpJ); piRC = piRCSpline(NijC+NijH,NjiC+NjiH,Nijconj,itype,jtype,dN3piRC); Tij = 0.0; dN3Tij[0] = 0.0; dN3Tij[1] = 0.0; dN3Tij[2] = 0.0; if (itype == 0 && jtype == 0) Tij=TijSpline((NijC+NijH),(NjiC+NjiH),Nijconj,dN3Tij); Etmp = 0.0; if (fabs(Tij) > TOL) { REBO_neighs_i = REBO_firstneigh[i]; for (k = 0; k < REBO_numneigh[i]; k++) { atomk = REBO_neighs_i[k]; ktype = map[type[atomk]]; if (atomk != atomj) { rik[0] = x[atomi][0]-x[atomk][0]; rik[1] = x[atomi][1]-x[atomk][1]; rik[2] = x[atomi][2]-x[atomk][2]; rikmag = sqrt((rik[0]*rik[0])+(rik[1]*rik[1])+(rik[2]*rik[2])); cos321 = ((rij[0]*rik[0])+(rij[1]*rik[1])+(rij[2]*rik[2])) / (rijmag*rikmag); cos321 = MIN(cos321,1.0); cos321 = MAX(cos321,-1.0); rjk[0] = rik[0]-rij[0]; rjk[1] = rik[1]-rij[1]; rjk[2] = rik[2]-rij[2]; rjk2 = (rjk[0]*rjk[0])+(rjk[1]*rjk[1])+(rjk[2]*rjk[2]); rij2 = rijmag*rijmag; rik2 = rikmag*rikmag; costmp = 0.5*(rij2+rik2-rjk2)/rijmag/rikmag; tspjik = Sp2(costmp,thmin,thmax,dtsjik); if (sqrt(1.0 - cos321*cos321) != 0.0) { wik = Sp(rikmag,rcmin[itype][ktype],rcmaxp[itype][ktype],dwik); REBO_neighs_j = REBO_firstneigh[j]; for (l = 0; l < REBO_numneigh[j]; l++) { atoml = REBO_neighs_j[l]; ltype = map[type[atoml]]; if (!(atoml == atomi || atoml == atomk)) { rjl[0] = x[atomj][0]-x[atoml][0]; rjl[1] = x[atomj][1]-x[atoml][1]; rjl[2] = x[atomj][2]-x[atoml][2]; rjlmag = sqrt(rjl[0]*rjl[0] + rjl[1]*rjl[1] + rjl[2]*rjl[2]); cos234 = -((rij[0]*rjl[0])+(rij[1]*rjl[1])+(rij[2]*rjl[2])) / (rijmag*rjlmag); cos234 = MIN(cos234,1.0); cos234 = MAX(cos234,-1.0); ril[0] = rij[0]+rjl[0]; ril[1] = rij[1]+rjl[1]; ril[2] = rij[2]+rjl[2]; ril2 = (ril[0]*ril[0])+(ril[1]*ril[1])+(ril[2]*ril[2]); rijrjl = 2.0*rijmag*rjlmag; rjl2 = rjlmag*rjlmag; costmp = 0.5*(rij2+rjl2-ril2)/rijmag/rjlmag; tspijl = Sp2(costmp,thmin,thmax,dtsijl); if (sqrt(1.0 - cos234*cos234) != 0.0) { wjl = Sp(rjlmag,rcmin[jtype][ltype],rcmaxp[jtype][ltype],dS); crosskij[0] = (rij[1]*rik[2]-rij[2]*rik[1]); crosskij[1] = (rij[2]*rik[0]-rij[0]*rik[2]); crosskij[2] = (rij[0]*rik[1]-rij[1]*rik[0]); crosskijmag = sqrt(crosskij[0]*crosskij[0] + crosskij[1]*crosskij[1] + crosskij[2]*crosskij[2]); crossijl[0] = (rij[1]*rjl[2]-rij[2]*rjl[1]); crossijl[1] = (rij[2]*rjl[0]-rij[0]*rjl[2]); crossijl[2] = (rij[0]*rjl[1]-rij[1]*rjl[0]); crossijlmag = sqrt(crossijl[0]*crossijl[0] + crossijl[1]*crossijl[1] + crossijl[2]*crossijl[2]); omkijl = -1.0*(((crosskij[0]*crossijl[0]) + (crosskij[1]*crossijl[1]) + (crosskij[2]*crossijl[2])) / (crosskijmag*crossijlmag)); Etmp += ((1.0-pow(omkijl,2.0))*wik*wjl) * (1.0-tspjik)*(1.0-tspijl); } } } } } } } bij = (.5*(pij+pji))+piRC+(Tij*Etmp); Stb = Sp2(bij,bLJmin[itype][jtype],bLJmax[itype][jtype],dStb); VA = VA*dStb; if (dStb != 0.0) { tmp = tmppij; dN2[0] = dN2PIJ[0]; dN2[1] = dN2PIJ[1]; tmp3 = tmp3pij; // pij forces REBO_neighs_i = REBO_firstneigh[i]; for (k = 0; k < REBO_numneigh[i]; k++) { atomk = REBO_neighs_i[k]; if (atomk != atomj) { lamdajik = 0.0; rik[0] = x[atomi][0]-x[atomk][0]; rik[1] = x[atomi][1]-x[atomk][1]; rik[2] = x[atomi][2]-x[atomk][2]; rikmag = sqrt(rik[0]*rik[0] + rik[1]*rik[1] + rik[2]*rik[2]); lamdajik = 4.0*kronecker(itype,1) * ((rho[ktype][1]-rikmag)-(rho[jtype][1]-rijmag)); wik = Sp(rikmag,rcmin[itype][ktype],rcmax[itype][ktype],dwik); cosjik = ((rij[0]*rik[0])+(rij[1]*rik[1])+(rij[2]*rik[2])) / (rijmag*rikmag); cosjik = MIN(cosjik,1.0); cosjik = MAX(cosjik,-1.0); dcosjikdri[0] = ((rij[0]+rik[0])/(rijmag*rikmag)) - (cosjik*((rij[0]/(rijmag*rijmag))+(rik[0]/(rikmag*rikmag)))); dcosjikdri[1] = ((rij[1]+rik[1])/(rijmag*rikmag)) - (cosjik*((rij[1]/(rijmag*rijmag))+(rik[1]/(rikmag*rikmag)))); dcosjikdri[2] = ((rij[2]+rik[2])/(rijmag*rikmag)) - (cosjik*((rij[2]/(rijmag*rijmag))+(rik[2]/(rikmag*rikmag)))); dcosjikdrk[0] = (-rij[0]/(rijmag*rikmag)) + (cosjik*(rik[0]/(rikmag*rikmag))); dcosjikdrk[1] = (-rij[1]/(rijmag*rikmag)) + (cosjik*(rik[1]/(rikmag*rikmag))); dcosjikdrk[2] = (-rij[2]/(rijmag*rikmag)) + (cosjik*(rik[2]/(rikmag*rikmag))); dcosjikdrj[0] = (-rik[0]/(rijmag*rikmag)) + (cosjik*(rij[0]/(rijmag*rijmag))); dcosjikdrj[1] = (-rik[1]/(rijmag*rikmag)) + (cosjik*(rij[1]/(rijmag*rijmag))); dcosjikdrj[2] = (-rik[2]/(rijmag*rikmag)) + (cosjik*(rij[2]/(rijmag*rijmag))); g = gSpline(cosjik,(NijC+NijH),itype,&dgdc,&dgdN); tmp2 = VA*.5*(tmp*wik*dgdc*exp(lamdajik)); fj[0] = -tmp2*dcosjikdrj[0]; fj[1] = -tmp2*dcosjikdrj[1]; fj[2] = -tmp2*dcosjikdrj[2]; fi[0] = -tmp2*dcosjikdri[0]; fi[1] = -tmp2*dcosjikdri[1]; fi[2] = -tmp2*dcosjikdri[2]; fk[0] = -tmp2*dcosjikdrk[0]; fk[1] = -tmp2*dcosjikdrk[1]; fk[2] = -tmp2*dcosjikdrk[2]; tmp2 = VA*.5*(tmp*wik*g*exp(lamdajik)*4.0*kronecker(itype,1)); fj[0] -= tmp2*(-rij[0]/rijmag); fj[1] -= tmp2*(-rij[1]/rijmag); fj[2] -= tmp2*(-rij[2]/rijmag); fi[0] -= tmp2*((-rik[0]/rikmag)+(rij[0]/rijmag)); fi[1] -= tmp2*((-rik[1]/rikmag)+(rij[1]/rijmag)); fi[2] -= tmp2*((-rik[2]/rikmag)+(rij[2]/rijmag)); fk[0] -= tmp2*(rik[0]/rikmag); fk[1] -= tmp2*(rik[1]/rikmag); fk[2] -= tmp2*(rik[2]/rikmag); // coordination forces // dwik forces tmp2 = VA*.5*(tmp*dwik*g*exp(lamdajik))/rikmag; fi[0] -= tmp2*rik[0]; fi[1] -= tmp2*rik[1]; fi[2] -= tmp2*rik[2]; fk[0] += tmp2*rik[0]; fk[1] += tmp2*rik[1]; fk[2] += tmp2*rik[2]; // PIJ forces tmp2 = VA*.5*(tmp*dN2[ktype]*dwik)/rikmag; fi[0] -= tmp2*rik[0]; fi[1] -= tmp2*rik[1]; fi[2] -= tmp2*rik[2]; fk[0] += tmp2*rik[0]; fk[1] += tmp2*rik[1]; fk[2] += tmp2*rik[2]; // dgdN forces tmp2 = VA*.5*(tmp*tmp3*dwik)/rikmag; fi[0] -= tmp2*rik[0]; fi[1] -= tmp2*rik[1]; fi[2] -= tmp2*rik[2]; fk[0] += tmp2*rik[0]; fk[1] += tmp2*rik[1]; fk[2] += tmp2*rik[2]; f[atomi][0] += fi[0]; f[atomi][1] += fi[1]; f[atomi][2] += fi[2]; f[atomj][0] += fj[0]; f[atomj][1] += fj[1]; f[atomj][2] += fj[2]; f[atomk][0] += fk[0]; f[atomk][1] += fk[1]; f[atomk][2] += fk[2]; if (vflag_atom) { rji[0] = -rij[0]; rji[1] = -rij[1]; rji[2] = -rij[2]; rki[0] = -rik[0]; rki[1] = -rik[1]; rki[2] = -rik[2]; v_tally3(atomi,atomj,atomk,fj,fk,rji,rki); } } } tmp = tmppji; tmp3 = tmp3pji; dN2[0] = dN2PJI[0]; dN2[1] = dN2PJI[1]; REBO_neighs = REBO_firstneigh[j]; for (l = 0; l < REBO_numneigh[j]; l++) { atoml = REBO_neighs[l]; if (atoml !=atomi) { ltype = map[type[atoml]]; rjl[0] = x[atomj][0]-x[atoml][0]; rjl[1] = x[atomj][1]-x[atoml][1]; rjl[2] = x[atomj][2]-x[atoml][2]; rjlmag = sqrt((rjl[0]*rjl[0])+(rjl[1]*rjl[1])+(rjl[2]*rjl[2])); lamdaijl = 4.0*kronecker(jtype,1) * ((rho[ltype][1]-rjlmag)-(rho[itype][1]-rijmag)); wjl = Sp(rjlmag,rcmin[jtype][ltype],rcmax[jtype][ltype],dwjl); cosijl = (-1.0*((rij[0]*rjl[0])+(rij[1]*rjl[1])+(rij[2]*rjl[2]))) / (rijmag*rjlmag); cosijl = MIN(cosijl,1.0); cosijl = MAX(cosijl,-1.0); dcosijldri[0] = (-rjl[0]/(rijmag*rjlmag)) - (cosijl*rij[0]/(rijmag*rijmag)); dcosijldri[1] = (-rjl[1]/(rijmag*rjlmag)) - (cosijl*rij[1]/(rijmag*rijmag)); dcosijldri[2] = (-rjl[2]/(rijmag*rjlmag)) - (cosijl*rij[2]/(rijmag*rijmag)); dcosijldrj[0] = ((-rij[0]+rjl[0])/(rijmag*rjlmag)) + (cosijl*((rij[0]/pow(rijmag,2.0))-(rjl[0]/(rjlmag*rjlmag)))); dcosijldrj[1] = ((-rij[1]+rjl[1])/(rijmag*rjlmag)) + (cosijl*((rij[1]/pow(rijmag,2.0))-(rjl[1]/(rjlmag*rjlmag)))); dcosijldrj[2] = ((-rij[2]+rjl[2])/(rijmag*rjlmag)) + (cosijl*((rij[2]/pow(rijmag,2.0))-(rjl[2]/(rjlmag*rjlmag)))); dcosijldrl[0] = (rij[0]/(rijmag*rjlmag)) + (cosijl*rjl[0]/(rjlmag*rjlmag)); dcosijldrl[1] = (rij[1]/(rijmag*rjlmag)) + (cosijl*rjl[1]/(rjlmag*rjlmag)); dcosijldrl[2] = (rij[2]/(rijmag*rjlmag)) + (cosijl*rjl[2]/(rjlmag*rjlmag)); // evaluate splines g and derivatives dg g = gSpline(cosijl,NjiC+NjiH,jtype,&dgdc,&dgdN); tmp2 = VA*.5*(tmp*wjl*dgdc*exp(lamdaijl)); fi[0] = -tmp2*dcosijldri[0]; fi[1] = -tmp2*dcosijldri[1]; fi[2] = -tmp2*dcosijldri[2]; fj[0] = -tmp2*dcosijldrj[0]; fj[1] = -tmp2*dcosijldrj[1]; fj[2] = -tmp2*dcosijldrj[2]; fl[0] = -tmp2*dcosijldrl[0]; fl[1] = -tmp2*dcosijldrl[1]; fl[2] = -tmp2*dcosijldrl[2]; tmp2 = VA*.5*(tmp*wjl*g*exp(lamdaijl)*4.0*kronecker(jtype,1)); fi[0] -= tmp2*(rij[0]/rijmag); fi[1] -= tmp2*(rij[1]/rijmag); fi[2] -= tmp2*(rij[2]/rijmag); fj[0] -= tmp2*((-rjl[0]/rjlmag)-(rij[0]/rijmag)); fj[1] -= tmp2*((-rjl[1]/rjlmag)-(rij[1]/rijmag)); fj[2] -= tmp2*((-rjl[2]/rjlmag)-(rij[2]/rijmag)); fl[0] -= tmp2*(rjl[0]/rjlmag); fl[1] -= tmp2*(rjl[1]/rjlmag); fl[2] -= tmp2*(rjl[2]/rjlmag); // coordination forces // dwik forces tmp2 = VA*.5*(tmp*dwjl*g*exp(lamdaijl))/rjlmag; fj[0] -= tmp2*rjl[0]; fj[1] -= tmp2*rjl[1]; fj[2] -= tmp2*rjl[2]; fl[0] += tmp2*rjl[0]; fl[1] += tmp2*rjl[1]; fl[2] += tmp2*rjl[2]; // PIJ forces tmp2 = VA*.5*(tmp*dN2[ltype]*dwjl)/rjlmag; fj[0] -= tmp2*rjl[0]; fj[1] -= tmp2*rjl[1]; fj[2] -= tmp2*rjl[2]; fl[0] += tmp2*rjl[0]; fl[1] += tmp2*rjl[1]; fl[2] += tmp2*rjl[2]; // dgdN forces tmp2=VA*.5*(tmp*tmp3*dwjl)/rjlmag; fj[0] -= tmp2*rjl[0]; fj[1] -= tmp2*rjl[1]; fj[2] -= tmp2*rjl[2]; fl[0] += tmp2*rjl[0]; fl[1] += tmp2*rjl[1]; fl[2] += tmp2*rjl[2]; f[atomi][0] += fi[0]; f[atomi][1] += fi[1]; f[atomi][2] += fi[2]; f[atomj][0] += fj[0]; f[atomj][1] += fj[1]; f[atomj][2] += fj[2]; f[atoml][0] += fl[0]; f[atoml][1] += fl[1]; f[atoml][2] += fl[2]; if (vflag_atom) { rlj[0] = -rjl[0]; rlj[1] = -rjl[1]; rlj[2] = -rjl[2]; v_tally3(atomi,atomj,atoml,fi,fl,rij,rlj); } } } // piRC forces dN3[0] = dN3piRC[0]; dN3[1] = dN3piRC[1]; dN3[2] = dN3piRC[2]; REBO_neighs_i = REBO_firstneigh[i]; for (k = 0; k < REBO_numneigh[i]; k++) { atomk = REBO_neighs_i[k]; if (atomk != atomj) { ktype = map[type[atomk]]; rik[0] = x[atomi][0]-x[atomk][0]; rik[1] = x[atomi][1]-x[atomk][1]; rik[2] = x[atomi][2]-x[atomk][2]; rikmag = sqrt((rik[0]*rik[0])+(rik[1]*rik[1])+(rik[2]*rik[2])); wik = Sp(rikmag,rcmin[itype][ktype],rcmax[itype][ktype],dwik); Nki = nC[atomk]-(wik*kronecker(itype,0))+nH[atomk] - (wik*kronecker(itype,1)); SpN = Sp(Nki,Nmin,Nmax,dNki); tmp2 = VA*dN3[0]*dwik/rikmag; f[atomi][0] -= tmp2*rik[0]; f[atomi][1] -= tmp2*rik[1]; f[atomi][2] -= tmp2*rik[2]; f[atomk][0] += tmp2*rik[0]; f[atomk][1] += tmp2*rik[1]; f[atomk][2] += tmp2*rik[2]; if (vflag_atom) v_tally2(atomi,atomk,-tmp2,rik); tmp2 = VA*dN3[2]*(2.0*NconjtmpI*dwik*SpN)/rikmag; f[atomi][0] -= tmp2*rik[0]; f[atomi][1] -= tmp2*rik[1]; f[atomi][2] -= tmp2*rik[2]; f[atomk][0] += tmp2*rik[0]; f[atomk][1] += tmp2*rik[1]; f[atomk][2] += tmp2*rik[2]; if (vflag_atom) v_tally2(atomi,atomk,-tmp2,rik); if (fabs(dNki) > TOL) { REBO_neighs_k = REBO_firstneigh[atomk]; for (n = 0; n < REBO_numneigh[atomk]; n++) { atomn = REBO_neighs_k[n]; if (atomn != atomi) { ntype = map[type[atomn]]; rkn[0] = x[atomk][0]-x[atomn][0]; rkn[1] = x[atomk][1]-x[atomn][1]; rkn[2] = x[atomk][2]-x[atomn][2]; rknmag = sqrt((rkn[0]*rkn[0])+(rkn[1]*rkn[1])+(rkn[2]*rkn[2])); Sp(rknmag,rcmin[ktype][ntype],rcmax[ktype][ntype],dwkn); tmp2 = VA*dN3[2]*(2.0*NconjtmpI*wik*dNki*dwkn)/rknmag; f[atomk][0] -= tmp2*rkn[0]; f[atomk][1] -= tmp2*rkn[1]; f[atomk][2] -= tmp2*rkn[2]; f[atomn][0] += tmp2*rkn[0]; f[atomn][1] += tmp2*rkn[1]; f[atomn][2] += tmp2*rkn[2]; if (vflag_atom) v_tally2(atomk,atomn,-tmp2,rkn); } } } } } // piRC forces to J side REBO_neighs = REBO_firstneigh[j]; for (l = 0; l < REBO_numneigh[j]; l++) { atoml = REBO_neighs[l]; if (atoml != atomi) { ltype = map[type[atoml]]; rjl[0] = x[atomj][0]-x[atoml][0]; rjl[1] = x[atomj][1]-x[atoml][1]; rjl[2] = x[atomj][2]-x[atoml][2]; rjlmag = sqrt((rjl[0]*rjl[0])+(rjl[1]*rjl[1])+(rjl[2]*rjl[2])); wjl = Sp(rjlmag,rcmin[jtype][ltype],rcmax[jtype][ltype],dwjl); Nlj = nC[atoml]-(wjl*kronecker(jtype,0))+nH[atoml] - (wjl*kronecker(jtype,1)); SpN = Sp(Nlj,Nmin,Nmax,dNlj); tmp2 = VA*dN3[1]*dwjl/rjlmag; f[atomj][0] -= tmp2*rjl[0]; f[atomj][1] -= tmp2*rjl[1]; f[atomj][2] -= tmp2*rjl[2]; f[atoml][0] += tmp2*rjl[0]; f[atoml][1] += tmp2*rjl[1]; f[atoml][2] += tmp2*rjl[2]; if (vflag_atom) v_tally2(atomj,atoml,-tmp2,rjl); tmp2 = VA*dN3[2]*(2.0*NconjtmpJ*dwjl*SpN)/rjlmag; f[atomj][0] -= tmp2*rjl[0]; f[atomj][1] -= tmp2*rjl[1]; f[atomj][2] -= tmp2*rjl[2]; f[atoml][0] += tmp2*rjl[0]; f[atoml][1] += tmp2*rjl[1]; f[atoml][2] += tmp2*rjl[2]; if (vflag_atom) v_tally2(atomj,atoml,-tmp2,rjl); if (fabs(dNlj) > TOL) { REBO_neighs_l = REBO_firstneigh[atoml]; for (n = 0; n < REBO_numneigh[atoml]; n++) { atomn = REBO_neighs_l[n]; if (atomn != atomj) { ntype = map[type[atomn]]; rln[0] = x[atoml][0]-x[atomn][0]; rln[1] = x[atoml][1]-x[atomn][1]; rln[2] = x[atoml][2]-x[atomn][2]; rlnmag = sqrt((rln[0]*rln[0])+(rln[1]*rln[1])+(rln[2]*rln[2])); Sp(rlnmag,rcmin[ltype][ntype],rcmax[ltype][ntype],dwln); tmp2 = VA*dN3[2]*(2.0*NconjtmpJ*wjl*dNlj*dwln)/rlnmag; f[atoml][0] -= tmp2*rln[0]; f[atoml][1] -= tmp2*rln[1]; f[atoml][2] -= tmp2*rln[2]; f[atomn][0] += tmp2*rln[0]; f[atomn][1] += tmp2*rln[1]; f[atomn][2] += tmp2*rln[2]; if (vflag_atom) v_tally2(atoml,atomn,-tmp2,rln); } } } } } if (fabs(Tij) > TOL) { dN3[0] = dN3Tij[0]; dN3[1] = dN3Tij[1]; dN3[2] = dN3Tij[2]; atom2 = atomi; atom3 = atomj; r32[0] = x[atom3][0]-x[atom2][0]; r32[1] = x[atom3][1]-x[atom2][1]; r32[2] = x[atom3][2]-x[atom2][2]; r32mag = sqrt((r32[0]*r32[0])+(r32[1]*r32[1])+(r32[2]*r32[2])); r23[0] = -r32[0]; r23[1] = -r32[1]; r23[2] = -r32[2]; r23mag = r32mag; REBO_neighs_i = REBO_firstneigh[i]; for (k = 0; k < REBO_numneigh[i]; k++) { atomk = REBO_neighs_i[k]; atom1 = atomk; ktype = map[type[atomk]]; if (atomk != atomj) { r21[0] = x[atom2][0]-x[atom1][0]; r21[1] = x[atom2][1]-x[atom1][1]; r21[2] = x[atom2][2]-x[atom1][2]; r21mag = sqrt(r21[0]*r21[0] + r21[1]*r21[1] + r21[2]*r21[2]); cos321 = ((r21[0]*rij[0])+(r21[1]*rij[1])+(r21[2]*rij[2])) / (r21mag*rijmag); cos321 = MIN(cos321,1.0); cos321 = MAX(cos321,-1.0); sin321 = sqrt(1.0 - cos321*cos321); sink2i = 1.0/(sin321*sin321); rik2i = 1.0/(r21mag*r21mag); if (sin321 != 0.0) { rr = (rijmag*rijmag)-(r21mag*r21mag); rjk[0] = r21[0]-rij[0]; rjk[1] = r21[1]-rij[1]; rjk[2] = r21[2]-rij[2]; rjk2 = (rjk[0]*rjk[0])+(rjk[1]*rjk[1])+(rjk[2]*rjk[2]); rijrik = 2.0*rijmag*r21mag; rik2 = r21mag*r21mag; dctik = (-rr+rjk2)/(rijrik*rik2); dctij = (rr+rjk2)/(rijrik*rijmag*rijmag); dctjk = -2.0/rijrik; w21 = Sp(r21mag,rcmin[itype][ktype],rcmaxp[itype][ktype],dw21); rikmag = r21mag; rij2 = r32mag*r32mag; rik2 = r21mag*r21mag; costmp = 0.5*(rij2+rik2-rjk2)/rijmag/rikmag; tspjik = Sp2(costmp,thmin,thmax,dtsjik); dtsjik = -dtsjik; REBO_neighs_j = REBO_firstneigh[j]; for (l = 0; l < REBO_numneigh[j]; l++) { atoml = REBO_neighs_j[l]; atom4 = atoml; ltype = map[type[atoml]]; if (!(atoml == atomi || atoml == atomk)) { r34[0] = x[atom3][0]-x[atom4][0]; r34[1] = x[atom3][1]-x[atom4][1]; r34[2] = x[atom3][2]-x[atom4][2]; r34mag = sqrt(r34[0]*r34[0] + r34[1]*r34[1] + r34[2]*r34[2]); cos234 = -1.0*((rij[0]*r34[0])+(rij[1]*r34[1]) + (rij[2]*r34[2]))/(rijmag*r34mag); cos234 = MIN(cos234,1.0); cos234 = MAX(cos234,-1.0); sin234 = sqrt(1.0 - cos234*cos234); sinl2i = 1.0/(sin234*sin234); rjl2i = 1.0/(r34mag*r34mag); if (sin234 != 0.0) { w34 = Sp(r34mag,rcmin[jtype][ltype], rcmaxp[jtype][ltype],dw34); rr = (r23mag*r23mag)-(r34mag*r34mag); ril[0] = r23[0]+r34[0]; ril[1] = r23[1]+r34[1]; ril[2] = r23[2]+r34[2]; ril2 = (ril[0]*ril[0])+(ril[1]*ril[1])+(ril[2]*ril[2]); rijrjl = 2.0*r23mag*r34mag; rjl2 = r34mag*r34mag; dctjl = (-rr+ril2)/(rijrjl*rjl2); dctji = (rr+ril2)/(rijrjl*r23mag*r23mag); dctil = -2.0/rijrjl; rjlmag = r34mag; rjl2 = r34mag*r34mag; costmp = 0.5*(rij2+rjl2-ril2)/rijmag/rjlmag; tspijl = Sp2(costmp,thmin,thmax,dtsijl); dtsijl = -dtsijl; //need minus sign prefactor = VA*Tij; cross321[0] = (r32[1]*r21[2])-(r32[2]*r21[1]); cross321[1] = (r32[2]*r21[0])-(r32[0]*r21[2]); cross321[2] = (r32[0]*r21[1])-(r32[1]*r21[0]); cross234[0] = (r23[1]*r34[2])-(r23[2]*r34[1]); cross234[1] = (r23[2]*r34[0])-(r23[0]*r34[2]); cross234[2] = (r23[0]*r34[1])-(r23[1]*r34[0]); cwnum = (cross321[0]*cross234[0]) + (cross321[1]*cross234[1])+(cross321[2]*cross234[2]); cwnom = r21mag*r34mag*r23mag*r23mag*sin321*sin234; om1234 = cwnum/cwnom; cw = om1234; Etmp += ((1.0-pow(om1234,2.0))*w21*w34) * (1.0-tspjik)*(1.0-tspijl); dt1dik = (rik2i)-(dctik*sink2i*cos321); dt1djk = (-dctjk*sink2i*cos321); dt1djl = (rjl2i)-(dctjl*sinl2i*cos234); dt1dil = (-dctil*sinl2i*cos234); dt1dij = (2.0/(r23mag*r23mag)) - (dctij*sink2i*cos321)-(dctji*sinl2i*cos234); dt2dik[0] = (-r23[2]*cross234[1])+(r23[1]*cross234[2]); dt2dik[1] = (-r23[0]*cross234[2])+(r23[2]*cross234[0]); dt2dik[2] = (-r23[1]*cross234[0])+(r23[0]*cross234[1]); dt2djl[0] = (-r23[1]*cross321[2])+(r23[2]*cross321[1]); dt2djl[1] = (-r23[2]*cross321[0])+(r23[0]*cross321[2]); dt2djl[2] = (-r23[0]*cross321[1])+(r23[1]*cross321[0]); dt2dij[0] = (r21[2]*cross234[1]) - (r34[2]*cross321[1])-(r21[1]*cross234[2]) + (r34[1]*cross321[2]); dt2dij[1] = (r21[0]*cross234[2]) - (r34[0]*cross321[2])-(r21[2]*cross234[0]) + (r34[2]*cross321[0]); dt2dij[2] = (r21[1]*cross234[0]) - (r34[1]*cross321[0])-(r21[0]*cross234[1]) + (r34[0]*cross321[1]); aa = (prefactor*2.0*cw/cwnom)*w21*w34 * (1.0-tspjik)*(1.0-tspijl); aaa1 = -prefactor*(1.0-pow(om1234,2.0)) * (1.0-tspjik)*(1.0-tspijl); aaa2 = aaa1*w21*w34; at2 = aa*cwnum; fcijpc = (-dt1dij*at2)+(aaa2*dtsjik*dctij*(1.0-tspijl)) + (aaa2*dtsijl*dctji*(1.0-tspjik)); fcikpc = (-dt1dik*at2)+(aaa2*dtsjik*dctik*(1.0-tspijl)); fcjlpc = (-dt1djl*at2)+(aaa2*dtsijl*dctjl*(1.0-tspjik)); fcjkpc = (-dt1djk*at2)+(aaa2*dtsjik*dctjk*(1.0-tspijl)); fcilpc = (-dt1dil*at2)+(aaa2*dtsijl*dctil*(1.0-tspjik)); F23[0] = (fcijpc*r23[0])+(aa*dt2dij[0]); F23[1] = (fcijpc*r23[1])+(aa*dt2dij[1]); F23[2] = (fcijpc*r23[2])+(aa*dt2dij[2]); F12[0] = (fcikpc*r21[0])+(aa*dt2dik[0]); F12[1] = (fcikpc*r21[1])+(aa*dt2dik[1]); F12[2] = (fcikpc*r21[2])+(aa*dt2dik[2]); F34[0] = (fcjlpc*r34[0])+(aa*dt2djl[0]); F34[1] = (fcjlpc*r34[1])+(aa*dt2djl[1]); F34[2] = (fcjlpc*r34[2])+(aa*dt2djl[2]); F31[0] = (fcjkpc*rjk[0]); F31[1] = (fcjkpc*rjk[1]); F31[2] = (fcjkpc*rjk[2]); F24[0] = (fcilpc*ril[0]); F24[1] = (fcilpc*ril[1]); F24[2] = (fcilpc*ril[2]); f1[0] = -F12[0]-F31[0]; f1[1] = -F12[1]-F31[1]; f1[2] = -F12[2]-F31[2]; f2[0] = F23[0]+F12[0]+F24[0]; f2[1] = F23[1]+F12[1]+F24[1]; f2[2] = F23[2]+F12[2]+F24[2]; f3[0] = -F23[0]+F34[0]+F31[0]; f3[1] = -F23[1]+F34[1]+F31[1]; f3[2] = -F23[2]+F34[2]+F31[2]; f4[0] = -F34[0]-F24[0]; f4[1] = -F34[1]-F24[1]; f4[2] = -F34[2]-F24[2]; // coordination forces tmp2 = VA*Tij*((1.0-(om1234*om1234))) * (1.0-tspjik)*(1.0-tspijl)*dw21*w34/r21mag; f2[0] -= tmp2*r21[0]; f2[1] -= tmp2*r21[1]; f2[2] -= tmp2*r21[2]; f1[0] += tmp2*r21[0]; f1[1] += tmp2*r21[1]; f1[2] += tmp2*r21[2]; tmp2 = VA*Tij*((1.0-(om1234*om1234))) * (1.0-tspjik)*(1.0-tspijl)*w21*dw34/r34mag; f3[0] -= tmp2*r34[0]; f3[1] -= tmp2*r34[1]; f3[2] -= tmp2*r34[2]; f4[0] += tmp2*r34[0]; f4[1] += tmp2*r34[1]; f4[2] += tmp2*r34[2]; f[atom1][0] += f1[0]; f[atom1][1] += f1[1]; f[atom1][2] += f1[2]; f[atom2][0] += f2[0]; f[atom2][1] += f2[1]; f[atom2][2] += f2[2]; f[atom3][0] += f3[0]; f[atom3][1] += f3[1]; f[atom3][2] += f3[2]; f[atom4][0] += f4[0]; f[atom4][1] += f4[1]; f[atom4][2] += f4[2]; if (vflag_atom) { r13[0] = -rjk[0]; r13[1] = -rjk[1]; r13[2] = -rjk[2]; r43[0] = -r34[0]; r43[1] = -r34[1]; r43[2] = -r34[2]; v_tally4(atom1,atom2,atom3,atom4,f1,f2,f4,r13,r23,r43); } } } } } } } REBO_neighs = REBO_firstneigh[i]; for (k = 0; k < REBO_numneigh[i]; k++) { atomk = REBO_neighs[k]; if (atomk != atomj) { ktype = map[type[atomk]]; rik[0] = x[atomi][0]-x[atomk][0]; rik[1] = x[atomi][1]-x[atomk][1]; rik[2] = x[atomi][2]-x[atomk][2]; rikmag = sqrt((rik[0]*rik[0])+(rik[1]*rik[1])+(rik[2]*rik[2])); wik = Sp(rikmag,rcmin[itype][ktype],rcmax[itype][ktype],dwik); Nki = nC[atomk]-(wik*kronecker(itype,0))+nH[atomk] - (wik*kronecker(itype,1)); SpN = Sp(Nki,Nmin,Nmax,dNki); tmp2 = VA*dN3[0]*dwik*Etmp/rikmag; f[atomi][0] -= tmp2*rik[0]; f[atomi][1] -= tmp2*rik[1]; f[atomi][2] -= tmp2*rik[2]; f[atomk][0] += tmp2*rik[0]; f[atomk][1] += tmp2*rik[1]; f[atomk][2] += tmp2*rik[2]; if (vflag_atom) v_tally2(atomi,atomk,-tmp2,rik); tmp2 = VA*dN3[2]*(2.0*NconjtmpI*dwik*SpN)*Etmp/rikmag; f[atomi][0] -= tmp2*rik[0]; f[atomi][1] -= tmp2*rik[1]; f[atomi][2] -= tmp2*rik[2]; f[atomk][0] += tmp2*rik[0]; f[atomk][1] += tmp2*rik[1]; f[atomk][2] += tmp2*rik[2]; if (vflag_atom) v_tally2(atomi,atomk,-tmp2,rik); if (fabs(dNki) >TOL) { REBO_neighs_k = REBO_firstneigh[atomk]; for (n = 0; n < REBO_numneigh[atomk]; n++) { atomn = REBO_neighs_k[n]; ntype = map[type[atomn]]; if (atomn !=atomi) { rkn[0] = x[atomk][0]-x[atomn][0]; rkn[1] = x[atomk][1]-x[atomn][1]; rkn[2] = x[atomk][2]-x[atomn][2]; rknmag = sqrt((rkn[0]*rkn[0])+(rkn[1]*rkn[1])+(rkn[2]*rkn[2])); Sp(rknmag,rcmin[ktype][ntype],rcmax[ktype][ntype],dwkn); tmp2 = VA*dN3[2]*(2.0*NconjtmpI*wik*dNki*dwkn)*Etmp/rknmag; f[atomk][0] -= tmp2*rkn[0]; f[atomk][1] -= tmp2*rkn[1]; f[atomk][2] -= tmp2*rkn[2]; f[atomn][0] += tmp2*rkn[0]; f[atomn][1] += tmp2*rkn[1]; f[atomn][2] += tmp2*rkn[2]; if (vflag_atom) v_tally2(atomk,atomn,-tmp2,rkn); } } } } } // Tij forces REBO_neighs = REBO_firstneigh[j]; for (l = 0; l < REBO_numneigh[j]; l++) { atoml = REBO_neighs[l]; if (atoml != atomi) { ltype = map[type[atoml]]; rjl[0] = x[atomj][0]-x[atoml][0]; rjl[1] = x[atomj][1]-x[atoml][1]; rjl[2] = x[atomj][2]-x[atoml][2]; rjlmag = sqrt((rjl[0]*rjl[0])+(rjl[1]*rjl[1])+(rjl[2]*rjl[2])); wjl = Sp(rjlmag,rcmin[jtype][ltype],rcmax[jtype][ltype],dwjl); Nlj = nC[atoml]-(wjl*kronecker(jtype,0))+nH[atoml] - (wjl*kronecker(jtype,1)); SpN = Sp(Nlj,Nmin,Nmax,dNlj); tmp2 = VA*dN3[1]*dwjl*Etmp/rjlmag; f[atomj][0] -= tmp2*rjl[0]; f[atomj][1] -= tmp2*rjl[1]; f[atomj][2] -= tmp2*rjl[2]; f[atoml][0] += tmp2*rjl[0]; f[atoml][1] += tmp2*rjl[1]; f[atoml][2] += tmp2*rjl[2]; if (vflag_atom) v_tally2(atomj,atoml,-tmp2,rjl); tmp2 = VA*dN3[2]*(2.0*NconjtmpJ*dwjl*SpN)*Etmp/rjlmag; f[atomj][0] -= tmp2*rjl[0]; f[atomj][1] -= tmp2*rjl[1]; f[atomj][2] -= tmp2*rjl[2]; f[atoml][0] += tmp2*rjl[0]; f[atoml][1] += tmp2*rjl[1]; f[atoml][2] += tmp2*rjl[2]; if (vflag_atom) v_tally2(atomj,atoml,-tmp2,rjl); if (fabs(dNlj) > TOL) { REBO_neighs_l = REBO_firstneigh[atoml]; for (n = 0; n < REBO_numneigh[atoml]; n++) { atomn = REBO_neighs_l[n]; ntype = map[type[atomn]]; if (atomn != atomj) { rln[0] = x[atoml][0]-x[atomn][0]; rln[1] = x[atoml][1]-x[atomn][1]; rln[2] = x[atoml][2]-x[atomn][2]; rlnmag = sqrt((rln[0]*rln[0])+(rln[1]*rln[1])+(rln[2]*rln[2])); Sp(rlnmag,rcmin[ltype][ntype],rcmax[ltype][ntype],dwln); tmp2 = VA*dN3[2]*(2.0*NconjtmpJ*wjl*dNlj*dwln)*Etmp/rlnmag; f[atoml][0] -= tmp2*rln[0]; f[atoml][1] -= tmp2*rln[1]; f[atoml][2] -= tmp2*rln[2]; f[atomn][0] += tmp2*rln[0]; f[atomn][1] += tmp2*rln[1]; f[atomn][2] += tmp2*rln[2]; if (vflag_atom) v_tally2(atoml,atomn,-tmp2,rln); } } } } } } } return Stb; } /* ---------------------------------------------------------------------- G spline ------------------------------------------------------------------------- */ double PairAIREBO::gSpline(double costh, double Nij, int typei, double *dgdc, double *dgdN) { double coeffs[6],dS,g1,g2,dg1,dg2,cut,g; int i,j; i = 0; j = 0; g = 0.0; cut = 0.0; dS = 0.0; dg1 = 0.0; dg2 = 0.0; *dgdc = 0.0; *dgdN = 0.0; // central atom is Carbon if (typei == 0) { if (costh < gCdom[0]) costh = gCdom[0]; if (costh > gCdom[4]) costh = gCdom[4]; if (Nij >= NCmax) { for (i = 0; i < 4; i++) { if (costh >= gCdom[i] && costh <= gCdom[i+1]) { for (j = 0; j < 6; j++) coeffs[j] = gC2[i][j]; } } g2 = Sp5th(costh,coeffs,&dg2); g = g2; *dgdc = dg2; *dgdN = 0.0; } if (Nij <= NCmin) { for (i = 0; i < 4; i++) { if (costh >= gCdom[i] && costh <= gCdom[i+1]) { for (j = 0; j < 6; j++) coeffs[j] = gC1[i][j]; } } g1 = Sp5th(costh,coeffs,&dg1); g = g1; *dgdc = dg1; *dgdN = 0.0; } if (Nij > NCmin && Nij < NCmax) { for (i = 0; i < 4; i++) { if (costh >= gCdom[i] && costh <= gCdom[i+1]) { for (j = 0; j < 6; j++) coeffs[j] = gC1[i][j]; } } g1 = Sp5th(costh,coeffs,&dg1); for (i = 0; i < 4; i++) { if (costh >= gCdom[i] && costh <= gCdom[i+1]) { for (j = 0; j < 6; j++) coeffs[j] = gC2[i][j]; } } g2 = Sp5th(costh,coeffs,&dg2); cut = Sp(Nij,NCmin,NCmax,dS); g = g2+cut*(g1-g2); *dgdc = dg2+(cut*(dg1-dg2)); *dgdN = dS*(g1-g2); } } // central atom is Hydrogen if (typei == 1) { if (costh < gHdom[0]) costh = gHdom[0]; if (costh > gHdom[3]) costh = gHdom[3]; for (i = 0; i < 3; i++) { if (costh >= gHdom[i] && costh <= gHdom[i+1]) { for (j = 0; j < 6; j++) coeffs[j] = gH[i][j]; } } g = Sp5th(costh,coeffs,&dg1); *dgdN = 0.0; *dgdc = dg1; } return g; } /* ---------------------------------------------------------------------- Pij spline ------------------------------------------------------------------------- */ double PairAIREBO::PijSpline(double NijC, double NijH, int typei, int typej, double dN2[2]) { int x,y,i,done; double Pij,coeffs[16]; for (i = 0; i < 16; i++) coeffs[i]=0.0; x = 0; y = 0; dN2[0] = 0.0; dN2[1] = 0.0; done = 0; // if inputs are out of bounds set them back to a point in bounds if (typei == 0 && typej == 0) { if (NijC < pCCdom[0][0]) NijC=pCCdom[0][0]; if (NijC > pCCdom[0][1]) NijC=pCCdom[0][1]; if (NijH < pCCdom[1][0]) NijH=pCCdom[1][0]; if (NijH > pCCdom[1][1]) NijH=pCCdom[1][1]; if (fabs(NijC-floor(NijC)) < TOL && fabs(NijH-floor(NijH)) < TOL) { Pij = PCCf[(int) NijC][(int) NijH]; dN2[0] = PCCdfdx[(int) NijC][(int) NijH]; dN2[1] = PCCdfdy[(int) NijC][(int) NijH]; done = 1; } if (done == 0) { x = (int) (floor(NijC)); y = (int) (floor(NijH)); for (i = 0; i<16; i++) coeffs[i] = pCC[x][y][i]; Pij = Spbicubic(NijC,NijH,coeffs,dN2); } } // if inputs are out of bounds set them back to a point in bounds if (typei == 0 && typej == 1){ if (NijC < pCHdom[0][0]) NijC=pCHdom[0][0]; if (NijC > pCHdom[0][1]) NijC=pCHdom[0][1]; if (NijH < pCHdom[0][0]) NijH=pCHdom[1][0]; if (NijH > pCHdom[1][1]) NijH=pCHdom[1][1]; if (fabs(NijC-floor(NijC)) < TOL && fabs(NijH-floor(NijH)) < TOL) { Pij = PCHf[(int) NijC][(int) NijH]; dN2[0] = PCHdfdx[(int) NijC][(int) NijH]; dN2[1] = PCHdfdy[(int) NijC][(int) NijH]; done = 1; } if (done == 0) { x = (int) (floor(NijC)); y = (int) (floor(NijH)); for (i = 0; i<16; i++) coeffs[i] = pCH[x][y][i]; Pij = Spbicubic(NijC,NijH,coeffs,dN2); } } if (typei == 1 && typej == 0) { Pij = 0.0; dN2[0] = 0.0; dN2[1] = 0.0; } if (typei == 1 && typej == 1) { Pij = 0.0; dN2[0] = 0.0; dN2[1] = 0.0; } return Pij; } /* ---------------------------------------------------------------------- PiRC spline ------------------------------------------------------------------------- */ double PairAIREBO::piRCSpline(double Nij, double Nji, double Nijconj, int typei, int typej, double dN3[3]) { int x,y,z,i,done; double piRC,coeffs[64]; x=0; y=0; z=0; i=0; done=0; for (i=0; i<64; i++) coeffs[i]=0.0; if (typei==0 && typej==0) { //if the inputs are out of bounds set them back to a point in bounds if (NijpiCCdom[0][1]) Nij=piCCdom[0][1]; if (NjipiCCdom[1][1]) Nji=piCCdom[1][1]; if (NijconjpiCCdom[2][1]) Nijconj=piCCdom[2][1]; if (fabs(Nij-floor(Nij))=(double) i && Nij<=(double) i+1 || Nij==(double) i) x=i; for (i=0; i=(double) i && Nji<=(double) i+1 || Nji==(double) i) y=i; for (i=0; i=(double) i && Nijconj<=(double) i+1 || Nijconj==(double) i) z=i; for (i=0; i<64; i++) coeffs[i]=piCC[x][y][z][i]; piRC=Sptricubic(Nij,Nji,Nijconj,coeffs,dN3); } } // CH interaction if (typei==0 && typej==1 || typei==1 && typej==0) { // if the inputs are out of bounds set them back to a point in bounds if (NijpiCHdom[0][1] || NjipiCHdom[1][1] || NijconjpiCHdom[2][1]) { if (NijpiCHdom[0][1]) Nij=piCHdom[0][1]; if (NjipiCHdom[1][1]) Nji=piCHdom[1][1]; if (NijconjpiCHdom[2][1]) Nijconj=piCHdom[2][1]; } if (fabs(Nij-floor(Nij))=i && Nij<=i+1) x=i; for (i=0; i=i && Nji<=i+1) y=i; for (i=0; i=i && Nijconj<=i+1) z=i; for (i=0; i<64; i++) coeffs[i]=piCH[x][y][z][i]; piRC=Sptricubic(Nij,Nji,Nijconj,coeffs,dN3); } } if (typei==1 && typej==1) { if (NijpiHHdom[0][1] || NjipiHHdom[1][1] || NijconjpiHHdom[2][1]) { Nij=0.0; Nji=0.0; Nijconj=0.0; } if (fabs(Nij-floor(Nij))=i && Nij<=i+1) x=i; for (i=0; i=i && Nji<=i+1) y=i; for (i=0; i=i && Nijconj<=i+1) z=i; for (i=0; i<64; i++) coeffs[i]=piHH[x][y][z][i]; piRC=Sptricubic(Nij,Nji,Nijconj,coeffs,dN3); } } return piRC; } /* ---------------------------------------------------------------------- Tij spline ------------------------------------------------------------------------- */ double PairAIREBO::TijSpline(double Nij, double Nji, double Nijconj, double dN3[3]) { int x,y,z,i,done; double Tijf,coeffs[64]; x=0; y=0; z=0; i=0; Tijf=0.0; done=0; for (i=0; i<64; i++) coeffs[i]=0.0; //if the inputs are out of bounds set them back to a point in bounds if (NijTijdom[0][1]) Nij=Tijdom[0][1]; if (NjiTijdom[1][1]) Nji=Tijdom[1][1]; if (NijconjTijdom[2][1]) Nijconj=Tijdom[2][1]; if (fabs(Nij-floor(Nij))=i && Nij<=i+1) x=i; for (i=0; i=i && Nji<=i+1) y=i; for (i=0; i=i && Nijconj<=i+1) z=i; for (i=0; i<64; i++) coeffs[i]=Tijc[x][y][z][i]; Tijf=Sptricubic(Nij,Nji,Nijconj,coeffs,dN3); } return Tijf; } /* ---------------------------------------------------------------------- Kronecker delta function ------------------------------------------------------------------------- */ double PairAIREBO::kronecker(int a, int b) { double kd; if (a == b) kd = 1.0; else kd = 0.0; return kd; } /* ---------------------------------------------------------------------- add pages to REBO neighbor list, starting at npage ------------------------------------------------------------------------- */ void PairAIREBO::add_pages(int npage) { maxpage += PGDELTA; pages = (int **) memory->srealloc(pages,maxpage*sizeof(int *),"AIREBO:pages"); for (int i = npage; i < maxpage; i++) memory->create(pages[i],pgsize,"AIREBO:pages[i]"); } /* ---------------------------------------------------------------------- read AIREBO potential file ------------------------------------------------------------------------- */ void PairAIREBO::read_file(char *filename) { int i,j,k,l,limit; char s[MAXLINE]; // REBO Parameters (AIREBO) double rcmin_CC,rcmin_CH,rcmin_HH,rcmax_CC,rcmax_CH, rcmax_HH,rcmaxp_CC,rcmaxp_CH,rcmaxp_HH; double Q_CC,Q_CH,Q_HH,alpha_CC,alpha_CH,alpha_HH,A_CC,A_CH,A_HH; double BIJc_CC1,BIJc_CC2,BIJc_CC3,BIJc_CH1,BIJc_CH2,BIJc_CH3, BIJc_HH1,BIJc_HH2,BIJc_HH3; double Beta_CC1,Beta_CC2,Beta_CC3,Beta_CH1,Beta_CH2,Beta_CH3, Beta_HH1,Beta_HH2,Beta_HH3; double rho_CC,rho_CH,rho_HH; // LJ Parameters (AIREBO) double rcLJmin_CC,rcLJmin_CH,rcLJmin_HH,rcLJmax_CC,rcLJmax_CH, rcLJmax_HH,bLJmin_CC; double bLJmin_CH,bLJmin_HH,bLJmax_CC,bLJmax_CH,bLJmax_HH, epsilon_CC,epsilon_CH,epsilon_HH; double sigma_CC,sigma_CH,sigma_HH,epsilonT_CCCC,epsilonT_CCCH,epsilonT_HCCH; MPI_Comm_rank(world,&me); // read file on proc 0 if (me == 0) { FILE *fp = fopen(filename,"r"); if (fp == NULL) { char str[128]; sprintf(str,"Cannot open AIREBO potential file %s",filename); error->one(str); } // skip initial comment lines while (1) { fgets(s,MAXLINE,fp); if (s[0] != '#') break; } // read parameters fgets(s,MAXLINE,fp); sscanf(s,"%lg",&rcmin_CC); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&rcmin_CH); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&rcmin_HH); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&rcmax_CC); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&rcmax_CH); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&rcmax_HH); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&rcmaxp_CC); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&rcmaxp_CH); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&rcmaxp_HH); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&smin); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&Nmin); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&Nmax); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&NCmin); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&NCmax); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&Q_CC); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&Q_CH); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&Q_HH); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&alpha_CC); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&alpha_CH); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&alpha_HH); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&A_CC); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&A_CH); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&A_HH); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&BIJc_CC1); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&BIJc_CC2); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&BIJc_CC3); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&BIJc_CH1); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&BIJc_CH2); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&BIJc_CH3); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&BIJc_HH1); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&BIJc_HH2); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&BIJc_HH3); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&Beta_CC1); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&Beta_CC2); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&Beta_CC3); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&Beta_CH1); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&Beta_CH2); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&Beta_CH3); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&Beta_HH1); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&Beta_HH2); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&Beta_HH3); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&rho_CC); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&rho_CH); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&rho_HH); // LJ parameters fgets(s,MAXLINE,fp); sscanf(s,"%lg",&rcLJmin_CC); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&rcLJmin_CH); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&rcLJmin_HH); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&rcLJmax_CC); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&rcLJmax_CH); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&rcLJmax_HH); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&bLJmin_CC); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&bLJmin_CH); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&bLJmin_HH); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&bLJmax_CC); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&bLJmax_CH); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&bLJmax_HH); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&epsilon_CC); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&epsilon_CH); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&epsilon_HH); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&sigma_CC); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&sigma_CH); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&sigma_HH); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&epsilonT_CCCC); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&epsilonT_CCCH); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&epsilonT_HCCH); // gC spline fgets(s,MAXLINE,fp); fgets(s,MAXLINE,fp); fgets(s,MAXLINE,fp); // number-1 = # of domains for the spline fgets(s,MAXLINE,fp); sscanf(s,"%d",&limit); for (i = 0; i < limit; i++) { fgets(s,MAXLINE,fp); sscanf(s,"%lg",&gCdom[i]); } fgets(s,MAXLINE,fp); for (i = 0; i < limit-1; i++) { for (j = 0; j < 6; j++) { fgets(s,MAXLINE,fp); sscanf(s,"%lg",&gC1[i][j]); } } fgets(s,MAXLINE,fp); for (i = 0; i < limit-1; i++) { for (j = 0; j < 6; j++) { fgets(s,MAXLINE,fp); sscanf(s,"%lg",&gC2[i][j]); } } // gH spline fgets(s,MAXLINE,fp); fgets(s,MAXLINE,fp); fgets(s,MAXLINE,fp); fgets(s,MAXLINE,fp); sscanf(s,"%d",&limit); for (i = 0; i < limit; i++) { fgets(s,MAXLINE,fp); sscanf(s,"%lg",&gHdom[i]); } fgets(s,MAXLINE,fp); for (i = 0; i < limit-1; i++) { for (j = 0; j < 6; j++) { fgets(s,MAXLINE,fp); sscanf(s,"%lg",&gH[i][j]); } } // pCC spline fgets(s,MAXLINE,fp); fgets(s,MAXLINE,fp); fgets(s,MAXLINE,fp); fgets(s,MAXLINE,fp); sscanf(s,"%d",&limit); for (i = 0; i < limit/2; i++) { for (j = 0; j < limit/2; j++) { fgets(s,MAXLINE,fp); sscanf(s,"%lg",&pCCdom[i][j]); } } fgets(s,MAXLINE,fp); for (i = 0; i < (int) pCCdom[0][1]; i++) { for (j = 0; j < (int) pCCdom[1][1]; j++) { for (k = 0; k < 16; k++) { fgets(s,MAXLINE,fp); sscanf(s,"%lg",&pCC[i][j][k]); } } } // pCH spline fgets(s,MAXLINE,fp); fgets(s,MAXLINE,fp); fgets(s,MAXLINE,fp); fgets(s,MAXLINE,fp); sscanf(s,"%d",&limit); for (i = 0; i < limit/2; i++) { for (j = 0; j < limit/2; j++) { fgets(s,MAXLINE,fp); sscanf(s,"%lg",&pCHdom[i][j]); } } fgets(s,MAXLINE,fp); for (i = 0; i < (int) pCHdom[0][1]; i++) { for (j = 0; j < (int) pCHdom[1][1]; j++) { for (k = 0; k < 16; k++) { fgets(s,MAXLINE,fp); sscanf(s,"%lg",&pCH[i][j][k]); } } } // piCC cpline fgets(s,MAXLINE,fp); fgets(s,MAXLINE,fp); fgets(s,MAXLINE,fp); fgets(s,MAXLINE,fp); sscanf(s,"%d",&limit); for (i = 0; i < limit/2; i++) { for (j = 0; j < limit/3; j++) { fgets(s,MAXLINE,fp); sscanf(s,"%lg",&piCCdom[i][j]); } } fgets(s,MAXLINE,fp); for (i = 0; i < (int) piCCdom[0][1]; i++) { for (j = 0; j < (int) piCCdom[1][1]; j++) { for (k = 0; k < (int) piCCdom[2][1]; k++) { for (l = 0; l < 64; l = l+1) { fgets(s,MAXLINE,fp); sscanf(s,"%lg",&piCC[i][j][k][l]); } } } } // piCH spline fgets(s,MAXLINE,fp); fgets(s,MAXLINE,fp); fgets(s,MAXLINE,fp); fgets(s,MAXLINE,fp); sscanf(s,"%d",&limit); for (i = 0; i < limit/2; i++) { for (j = 0; j < limit/3; j++) { fgets(s,MAXLINE,fp); sscanf(s,"%lg",&piCHdom[i][j]); } } fgets(s,MAXLINE,fp); for (i = 0; i < (int) piCHdom[0][1]; i++) { for (j = 0; j < (int) piCHdom[1][1]; j++) { for (k = 0; k < (int) piCHdom[2][1]; k++) { for (l = 0; l < 64; l = l+1) { fgets(s,MAXLINE,fp); sscanf(s,"%lg",&piCH[i][j][k][l]); } } } } // piHH spline fgets(s,MAXLINE,fp); fgets(s,MAXLINE,fp); fgets(s,MAXLINE,fp); fgets(s,MAXLINE,fp); sscanf(s,"%d",&limit); for (i = 0; i < limit/2; i++) { for (j = 0; j < limit/3; j++) { fgets(s,MAXLINE,fp); sscanf(s,"%lg",&piHHdom[i][j]); } } fgets(s,MAXLINE,fp); for (i = 0; i < (int) piHHdom[0][1]; i++) { for (j = 0; j < (int) piHHdom[1][1]; j++) { for (k = 0; k < (int) piHHdom[2][1]; k++) { for (l = 0; l < 64; l = l+1) { fgets(s,MAXLINE,fp); sscanf(s,"%lg",&piHH[i][j][k][l]); } } } } // Tij spline fgets(s,MAXLINE,fp); fgets(s,MAXLINE,fp); fgets(s,MAXLINE,fp); fgets(s,MAXLINE,fp); sscanf(s,"%d",&limit); for (i = 0; i < limit/2; i++) { for (j = 0; j < limit/3; j++) { fgets(s,MAXLINE,fp); sscanf(s,"%lg",&Tijdom[i][j]); } } fgets(s,MAXLINE,fp); for (i = 0; i < (int) Tijdom[0][1]; i++) { for (j = 0; j < (int) Tijdom[1][1]; j++) { for (k = 0; k < (int) Tijdom[2][1]; k++) { for (l = 0; l < 64; l = l+1) { fgets(s,MAXLINE,fp); sscanf(s,"%lg",&Tijc[i][j][k][l]); } } } } fclose(fp); } // store read-in values in arrays if (me == 0) { // REBO rcmin[0][0] = rcmin_CC; rcmin[0][1] = rcmin_CH; rcmin[1][0] = rcmin[0][1]; rcmin[1][1] = rcmin_HH; rcmax[0][0] = rcmax_CC; rcmax[0][1] = rcmax_CH; rcmax[1][0] = rcmax[0][1]; rcmax[1][1] = rcmax_HH; rcmaxsq[0][0] = rcmax[0][0]*rcmax[0][0]; rcmaxsq[1][0] = rcmax[1][0]*rcmax[1][0]; rcmaxsq[0][1] = rcmax[0][1]*rcmax[0][1]; rcmaxsq[1][1] = rcmax[1][1]*rcmax[1][1]; rcmaxp[0][0] = rcmaxp_CC; rcmaxp[0][1] = rcmaxp_CH; rcmaxp[1][0] = rcmaxp[0][1]; rcmaxp[1][1] = rcmaxp_HH; Q[0][0] = Q_CC; Q[0][1] = Q_CH; Q[1][0] = Q[0][1]; Q[1][1] = Q_HH; alpha[0][0] = alpha_CC; alpha[0][1] = alpha_CH; alpha[1][0] = alpha[0][1]; alpha[1][1] = alpha_HH; A[0][0] = A_CC; A[0][1] = A_CH; A[1][0] = A[0][1]; A[1][1] = A_HH; rho[0][0] = rho_CC; rho[0][1] = rho_CH; rho[1][0] = rho[0][1]; rho[1][1] = rho_HH; BIJc[0][0][0] = BIJc_CC1; BIJc[0][0][1] = BIJc_CC2; BIJc[0][0][2] = BIJc_CC3; BIJc[0][1][0] = BIJc_CH1; BIJc[0][1][1] = BIJc_CH2; BIJc[0][1][2] = BIJc_CH3; BIJc[1][0][0] = BIJc_CH1; BIJc[1][0][1] = BIJc_CH2; BIJc[1][0][2] = BIJc_CH3; BIJc[1][1][0] = BIJc_HH1; BIJc[1][1][1] = BIJc_HH2; BIJc[1][1][2] = BIJc_HH3; Beta[0][0][0] = Beta_CC1; Beta[0][0][1] = Beta_CC2; Beta[0][0][2] = Beta_CC3; Beta[0][1][0] = Beta_CH1; Beta[0][1][1] = Beta_CH2; Beta[0][1][2] = Beta_CH3; Beta[1][0][0] = Beta_CH1; Beta[1][0][1] = Beta_CH2; Beta[1][0][2] = Beta_CH3; Beta[1][1][0] = Beta_HH1; Beta[1][1][1] = Beta_HH2; Beta[1][1][2] = Beta_HH3; // LJ rcLJmin[0][0] = rcLJmin_CC; rcLJmin[0][1] = rcLJmin_CH; rcLJmin[1][0] = rcLJmin[0][1]; rcLJmin[1][1] = rcLJmin_HH; rcLJmax[0][0] = rcLJmax_CC; rcLJmax[0][1] = rcLJmax_CH; rcLJmax[1][0] = rcLJmax[0][1]; rcLJmax[1][1] = rcLJmax_HH; rcLJmaxsq[0][0] = rcLJmax[0][0]*rcLJmax[0][0]; rcLJmaxsq[1][0] = rcLJmax[1][0]*rcLJmax[1][0]; rcLJmaxsq[0][1] = rcLJmax[0][1]*rcLJmax[0][1]; rcLJmaxsq[1][1] = rcLJmax[1][1]*rcLJmax[1][1]; bLJmin[0][0] = bLJmin_CC; bLJmin[0][1] = bLJmin_CH; bLJmin[1][0] = bLJmin[0][1]; bLJmin[1][1] = bLJmin_HH; bLJmax[0][0] = bLJmax_CC; bLJmax[0][1] = bLJmax_CH; bLJmax[1][0] = bLJmax[0][1]; bLJmax[1][1] = bLJmax_HH; epsilon[0][0] = epsilon_CC; epsilon[0][1] = epsilon_CH; epsilon[1][0] = epsilon[0][1]; epsilon[1][1] = epsilon_HH; sigma[0][0] = sigma_CC; sigma[0][1] = sigma_CH; sigma[1][0] = sigma[0][1]; sigma[1][1] = sigma_HH; // torsional thmin = -1.0; thmax = -0.995; epsilonT[0][0] = epsilonT_CCCC; epsilonT[0][1] = epsilonT_CCCH; epsilonT[1][0] = epsilonT[0][1]; epsilonT[1][1] = epsilonT_HCCH; } // broadcast read-in and setup values MPI_Bcast(&thmin,1,MPI_DOUBLE,0,world); MPI_Bcast(&thmax,1,MPI_DOUBLE,0,world); MPI_Bcast(&smin,1,MPI_DOUBLE,0,world); MPI_Bcast(&Nmin,1,MPI_DOUBLE,0,world); MPI_Bcast(&Nmax,1,MPI_DOUBLE,0,world); MPI_Bcast(&NCmin,1,MPI_DOUBLE,0,world); MPI_Bcast(&NCmax,1,MPI_DOUBLE,0,world); MPI_Bcast(&rcmin[0][0],4,MPI_DOUBLE,0,world); MPI_Bcast(&rcmax[0][0],4,MPI_DOUBLE,0,world); MPI_Bcast(&rcmaxsq[0][0],4,MPI_DOUBLE,0,world); MPI_Bcast(&rcmaxp[0][0],4,MPI_DOUBLE,0,world); MPI_Bcast(&Q[0][0],4,MPI_DOUBLE,0,world); MPI_Bcast(&alpha[0][0],4,MPI_DOUBLE,0,world); MPI_Bcast(&A[0][0],4,MPI_DOUBLE,0,world); MPI_Bcast(&rho[0][0],4,MPI_DOUBLE,0,world); MPI_Bcast(&BIJc[0][0][0],12,MPI_DOUBLE,0,world); MPI_Bcast(&Beta[0][0][0],12,MPI_DOUBLE,0,world); MPI_Bcast(&rcLJmin[0][0],4,MPI_DOUBLE,0,world); MPI_Bcast(&rcLJmax[0][0],4,MPI_DOUBLE,0,world); MPI_Bcast(&rcLJmaxsq[0][0],4,MPI_DOUBLE,0,world); MPI_Bcast(&rcLJmin[0][0],4,MPI_DOUBLE,0,world); MPI_Bcast(&rcLJmin[0][0],4,MPI_DOUBLE,0,world); MPI_Bcast(&rcLJmin[0][0],4,MPI_DOUBLE,0,world); MPI_Bcast(&rcLJmax[0][0],4,MPI_DOUBLE,0,world); MPI_Bcast(&bLJmin[0][0],4,MPI_DOUBLE,0,world); MPI_Bcast(&bLJmax[0][0],4,MPI_DOUBLE,0,world); MPI_Bcast(&epsilon[0][0],4,MPI_DOUBLE,0,world); MPI_Bcast(&sigma[0][0],4,MPI_DOUBLE,0,world); MPI_Bcast(&epsilonT[0][0],4,MPI_DOUBLE,0,world); MPI_Bcast(&gCdom[0],5,MPI_DOUBLE,0,world); MPI_Bcast(&gC1[0][0],24,MPI_DOUBLE,0,world); MPI_Bcast(&gC2[0][0],24,MPI_DOUBLE,0,world); MPI_Bcast(&gHdom[0],4,MPI_DOUBLE,0,world); MPI_Bcast(&gH[0][0],18,MPI_DOUBLE,0,world); MPI_Bcast(&pCCdom[0][0],4,MPI_DOUBLE,0,world); MPI_Bcast(&pCHdom[0][0],4,MPI_DOUBLE,0,world); MPI_Bcast(&pCC[0][0][0],256,MPI_DOUBLE,0,world); MPI_Bcast(&pCH[0][0][0],256,MPI_DOUBLE,0,world); MPI_Bcast(&piCCdom[0][0],6,MPI_DOUBLE,0,world); MPI_Bcast(&piCHdom[0][0],6,MPI_DOUBLE,0,world); MPI_Bcast(&piHHdom[0][0],6,MPI_DOUBLE,0,world); MPI_Bcast(&piCC[0][0][0][0],9216,MPI_DOUBLE,0,world); MPI_Bcast(&piCH[0][0][0][0],9216,MPI_DOUBLE,0,world); MPI_Bcast(&piHH[0][0][0][0],9216,MPI_DOUBLE,0,world); MPI_Bcast(&Tijdom[0][0],6,MPI_DOUBLE,0,world); MPI_Bcast(&Tijc[0][0][0][0],9216,MPI_DOUBLE,0,world); } // ---------------------------------------------------------------------- // generic Spline functions // ---------------------------------------------------------------------- /* ---------------------------------------------------------------------- fifth order spline evaluation ------------------------------------------------------------------------- */ double PairAIREBO::Sp5th(double x, double coeffs[6], double *df) { double f; int i; i = 0; f = 0.0; *df = 0.0; for (i = 0; i<6; i++) { f += coeffs[i]*pow(x,((double) i)); if (i > 0) *df += coeffs[i]*((double) i)*pow(x,((double) i-1.0)); } return f; } /* ---------------------------------------------------------------------- bicubic spline evaluation ------------------------------------------------------------------------- */ double PairAIREBO::Spbicubic(double x, double y, double coeffs[16], double df[2]) { double f; int i,j,cn; f = 0.0; df[0] = 0.0; df[1] = 0.0; cn = 0; for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) { f += coeffs[cn]*pow(x,((double) i))*pow(y,((double) j)); if (i > 0) df[0] += (coeffs[cn]*((double) i)*pow(x,((double) i-1.0)) * pow(y,((double) j))); if (j > 0) df[1] += (coeffs[cn]*((double) j)*pow(x,((double) i)) * pow(y,((double) j-1.0))); cn++; } } return f; } /* ---------------------------------------------------------------------- tricubic spline evaluation ------------------------------------------------------------------------- */ double PairAIREBO::Sptricubic(double x, double y, double z, double coeffs[64], double df[3]) { double f,ir,jr,kr; int i,j,k,cn; f = 0.0; df[0] = 0.0; df[1] = 0.0; df[2] = 0.0; cn = 0; for (i = 0; i < 4; i++) { ir = (double) i; for (j = 0; j < 4; j++) { jr = (double) j; for (k = 0; k < 4; k++) { kr = (double) k; f += (coeffs[cn]*pow(x,ir)*pow(y,jr)*pow(z,kr)); if (i > 0) df[0] += (coeffs[cn]*ir*pow(x,ir-1.0)*pow(y,jr)*pow(z,kr)); if (j > 0) df[1] += (coeffs[cn]*jr*pow(x,ir)*pow(y,jr-1.0)*pow(z,kr)); if (k > 0) df[2] += (coeffs[cn]*kr*pow(x,ir)*pow(y,jr)*pow(z,kr-1.0)); cn++; } } } return f; } /* ---------------------------------------------------------------------- initialize spline knot values ------------------------------------------------------------------------- */ void PairAIREBO::spline_init() { int i,j,k; for (i = 0; i < 5; i++) { for (j = 0; j < 5; j++) { PCCf[i][j] = 0.0; PCCdfdx[i][j] = 0.0; PCCdfdy[i][j] = 0.0; PCHf[i][j] = 0.0; PCHdfdx[i][j] = 0.0; PCHdfdy[i][j] = 0.0; } } PCCf[0][2] = -0.00050; PCCf[0][3] = 0.0161253646; PCCf[1][1] = -0.010960; PCCf[1][2] = 0.00632624824; PCCf[2][0] = -0.0276030; PCCf[2][1] = 0.00317953083; PCHf[0][1] = 0.209336733; PCHf[0][2] = -0.0644496154; PCHf[0][3] = -0.303927546; PCHf[1][0] = 0.010; PCHf[1][1] = -0.125123401; PCHf[1][2] = -0.298905246; PCHf[2][0] = -0.122042146; PCHf[2][1] = -0.300529172; PCHf[3][0] = -0.307584705; for (i = 0; i < 5; i++) { for (j = 0; j < 5; j++) { for (k = 0; k < 10; k++) { piCCf[i][j][k] = 0.0; piCCdfdx[i][j][k] = 0.0; piCCdfdy[i][j][k] = 0.0; piCCdfdz[i][j][k] = 0.0; piCHf[i][j][k] = 0.0; piCHdfdx[i][j][k] = 0.0; piCHdfdy[i][j][k] = 0.0; piCHdfdz[i][j][k] = 0.0; piHHf[i][j][k] = 0.0; piHHdfdx[i][j][k] = 0.0; piHHdfdy[i][j][k] = 0.0; piHHdfdz[i][j][k] = 0.0; Tf[i][j][k] = 0.0; Tdfdx[i][j][k] = 0.0; Tdfdy[i][j][k] = 0.0; Tdfdz[i][j][k] = 0.0; } } } for (i = 3; i < 10; i++) piCCf[0][0][i] = 0.0049586079; piCCf[1][0][1] = 0.021693495; piCCf[0][1][1] = 0.021693495; for (i = 2; i < 10; i++) piCCf[1][0][i] = 0.0049586079; for (i = 2; i < 10; i++) piCCf[0][1][i] = 0.0049586079; piCCf[1][1][1] = 0.05250; piCCf[1][1][2] = -0.002088750; for (i = 3; i < 10; i++) piCCf[1][1][i] = -0.00804280; piCCf[2][0][1] = 0.024698831850; piCCf[0][2][1] = 0.024698831850; piCCf[2][0][2] = -0.00597133450; piCCf[0][2][2] = -0.00597133450; for (i = 3; i < 10; i++) piCCf[2][0][i] = 0.0049586079; for (i = 3; i < 10; i++) piCCf[0][2][i] = 0.0049586079; piCCf[2][1][1] = 0.00482478490; piCCf[1][2][1] = 0.00482478490; piCCf[2][1][2] = 0.0150; piCCf[1][2][2] = 0.0150; piCCf[2][1][3] = -0.010; piCCf[1][2][3] = -0.010; piCCf[2][1][4] = -0.01168893870; piCCf[1][2][4] = -0.01168893870; piCCf[2][1][5] = -0.013377877400; piCCf[1][2][5] = -0.013377877400; piCCf[2][1][6] = -0.015066816000; piCCf[1][2][6] = -0.015066816000; for (i = 7; i < 10; i++) piCCf[2][1][i] = -0.015066816000; for (i = 7; i < 10; i++) piCCf[1][2][i] = -0.015066816000; piCCf[2][2][1] = 0.0472247850; piCCf[2][2][2] = 0.0110; piCCf[2][2][3] = 0.0198529350; piCCf[2][2][4] = 0.01654411250; piCCf[2][2][5] = 0.013235290; piCCf[2][2][6] = 0.00992646749999 ; piCCf[2][2][7] = 0.006617644999; piCCf[2][2][8] = 0.00330882250; piCCf[3][0][1] = -0.05989946750; piCCf[0][3][1] = -0.05989946750; piCCf[3][0][2] = -0.05989946750; piCCf[0][3][2] = -0.05989946750; for (i = 3; i < 10; i++) piCCf[3][0][i] = 0.0049586079; for (i = 3; i < 10; i++) piCCf[0][3][i] = 0.0049586079; piCCf[3][1][2] = -0.0624183760; piCCf[1][3][2] = -0.0624183760; for (i = 3; i < 10; i++) piCCf[3][1][i] = -0.0624183760; for (i = 3; i < 10; i++) piCCf[1][3][i] = -0.0624183760; piCCf[3][2][1] = -0.02235469150; piCCf[2][3][1] = -0.02235469150; for (i = 2; i < 10; i++) piCCf[3][2][i] = -0.02235469150; for (i = 2; i < 10; i++) piCCf[2][3][i] = -0.02235469150; piCCdfdx[2][1][1] = -0.026250; piCCdfdx[2][1][5] = -0.0271880; piCCdfdx[2][1][6] = -0.0271880; for (i = 7; i < 10; i++) piCCdfdx[2][1][i] = -0.0271880; piCCdfdx[1][3][2] = 0.0187723882; for (i = 2; i < 10; i++) piCCdfdx[2][3][i] = 0.031209; piCCdfdy[1][2][1] = -0.026250; piCCdfdy[1][2][5] = -0.0271880; piCCdfdy[1][2][6] = -0.0271880; for (i = 7; i < 10; i++) piCCdfdy[1][2][i] = -0.0271880; piCCdfdy[3][1][2] = 0.0187723882; for (i = 2; i < 10; i++) piCCdfdy[3][2][i] = 0.031209; piCCdfdz[1][1][2] = -0.0302715; piCCdfdz[2][1][4] = -0.0100220; piCCdfdz[1][2][4] = -0.0100220; piCCdfdz[2][1][5] = -0.0100220; piCCdfdz[1][2][5] = -0.0100220; for (i = 4; i < 9; i++) piCCdfdz[2][2][i] = -0.0033090; // make top end of piCC flat instead of zero i = 4; for (j = 0; j < 4; j++){ for (k = 1; k < 11; k++){ piCCf[i][j][k] = piCCf[i-1][j][k]; } } for (i = 0; i < 4; i++){ // also enforces some symmetry for (j = i+1; j < 5; j++){ for (k = 1; k < 11; k++){ piCCf[i][j][k] = piCCf[j][i][k]; } } } for (k = 1; k < 11; k++) piCCf[4][4][k] = piCCf[3][4][k]; k = 10; for (i = 0; i < 5; i++){ for (j = 0; j < 5; j++){ piCCf[i][j][k] = piCCf[i][j][k-1]; } } piCHf[1][1][1] = -0.050; piCHf[1][1][2] = -0.050; piCHf[1][1][3] = -0.30; for (i = 4; i < 10; i++) piCHf[1][1][i] = -0.050; for (i = 5; i < 10; i++) piCHf[2][0][i] = -0.004523893758064; for (i = 5; i < 10; i++) piCHf[0][2][i] = -0.004523893758064; piCHf[2][1][2] = -0.250; piCHf[1][2][2] = -0.250; piCHf[2][1][3] = -0.250; piCHf[1][2][3] = -0.250; piCHf[3][1][1] = -0.10; piCHf[1][3][1] = -0.10; piCHf[3][1][2] = -0.125; piCHf[1][3][2] = -0.125; piCHf[3][1][3] = -0.125; piCHf[1][3][3] = -0.125; for (i = 4; i < 10; i++) piCHf[3][1][i] = -0.10; for (i = 4; i < 10; i++) piCHf[1][3][i] = -0.10; // make top end of piCH flat instead of zero // also enforces some symmetry i = 4; for (j = 0; j < 4; j++){ for (k = 1; k < 11; k++){ piCHf[i][j][k] = piCHf[i-1][j][k]; } } for (i = 0; i < 4; i++){ for (j = i+1; j < 5; j++){ for (k = 1; k < 11; k++){ piCHf[i][j][k] = piCHf[j][i][k]; } } } for (k = 1; k < 11; k++) piCHf[4][4][k] = piCHf[3][4][k]; k = 10; for (i = 0; i < 5; i++){ for (j = 0; j < 5; j++){ piCHf[i][j][k] = piCHf[i][j][k-1]; } } piHHf[1][1][1] = 0.124915958; Tf[2][2][1] = -0.035140; for (i = 2; i < 10; i++) Tf[2][2][i] = -0.0040480; } /* ---------------------------------------------------------------------- memory usage of local atom-based arrays ------------------------------------------------------------------------- */ double PairAIREBO::memory_usage() { double bytes = 0.0; bytes += maxlocal * sizeof(int); bytes += maxlocal * sizeof(int *); bytes += maxpage * neighbor->pgsize * sizeof(int); bytes += 3 * maxlocal * sizeof(double); return bytes; } diff --git a/src/MANYBODY/pair_comb.cpp b/src/MANYBODY/pair_comb.cpp index ea415b968..3e4d95fa6 100644 --- a/src/MANYBODY/pair_comb.cpp +++ b/src/MANYBODY/pair_comb.cpp @@ -1,2030 +1,2037 @@ /* ---------------------------------------------------------------------- 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: Tzu-Ray Shan (U Florida, rayshan@ufl.edu) LAMMPS implementation of the Charge-optimized many-body (COMB) potential based on the HELL MD program (Prof Simon Phillpot, UF, sphil@mse.ufl.edu) and Aidan Thompson's Tersoff code in LAMMPS ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "pair_comb.h" #include "atom.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 "group.h" using namespace LAMMPS_NS; #define MAXLINE 1024 #define DELTA 4 /* ---------------------------------------------------------------------- */ PairComb::PairComb(LAMMPS *lmp) : Pair(lmp) { single_enable = 0; one_coeff = 1; PI = 4.0*atan(1.0); PI2 = 2.0*atan(1.0); PI4 = atan(1.0); PIsq = sqrt(PI); nmax = 0; NCo = NULL; nelements = 0; elements = NULL; nparams = 0; maxparam = 0; params = NULL; elem2param = NULL; intype = NULL; fafb = NULL; dfafb = NULL; ddfafb = NULL; phin = NULL; dphin = NULL; erpaw = NULL; // set comm size needed by this Pair comm_forward = 1; comm_reverse = 1; } /* ---------------------------------------------------------------------- check if allocated, since class can be destructed when incomplete ------------------------------------------------------------------------- */ PairComb::~PairComb() { memory->destroy(NCo); if (elements) for (int i = 0; i < nelements; i++) delete [] elements[i]; delete [] elements; memory->sfree(params); memory->destroy(elem2param); memory->destroy(intype); memory->destroy(fafb); memory->destroy(dfafb); memory->destroy(ddfafb); memory->destroy(phin); memory->destroy(dphin); memory->destroy(erpaw); if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); delete [] map; delete [] esm; } } /* ---------------------------------------------------------------------- */ void PairComb::compute(int eflag, int vflag) { int i,j,k,ii,jj,kk,inum,jnum,iparam_i; int itag,jtag,itype,jtype,ktype,iparam_ij,iparam_ijk; double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair; double rsq,rsq1,rsq2; double delr1[3],delr2[3],fi[3],fj[3],fk[3]; double zeta_ij,prefactor; double fqi,fqij; int *ilist,*jlist,*numneigh,**firstneigh; int mr1,mr2,mr3; int rsc,inty; double elp_ij,filp[3],fjlp[3],fklp[3]; double iq,jq; double yaself; double potal,fac11,fac11e; double vionij,fvionij,sr1,sr2,sr3,Eov,Fov; evdwl = ecoul = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = vflag_atom = 0; // grow coordination array if necessary if (atom->nmax > nmax) { memory->destroy(NCo); nmax = atom->nmax; memory->create(NCo,nmax,"pair:NCo"); } double **x = atom->x; double **f = atom->f; double *q = atom->q; int *tag = atom->tag; int *type = atom->type; int nlocal = atom->nlocal; int newton_pair = force->newton_pair; int ntype = atom->ntypes; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; yaself = vionij = fvionij = Eov = Fov = 0.0; // self energy correction term: potal potal_calc(potal,fac11,fac11e); // loop over full neighbor list of my atoms for (ii = 0; ii < inum; ii++) { i = ilist[ii]; itag = tag[i]; itype = map[type[i]]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; iq = q[i]; NCo[i] = 0; iparam_i = elem2param[itype][itype][itype]; // self energy, only on i atom yaself = self(¶ms[iparam_i],iq,potal); if (evflag) ev_tally(i,i,nlocal,0,yaself,0.0,0.0,0.0,0.0,0.0); // two-body interactions (long and short repulsive) jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; + j &= NEIGHMASK; jtag = tag[j]; if (itag > jtag) { if ((itag+jtag) % 2 == 0) continue; } else if (itag < jtag) { if ((itag+jtag) % 2 == 1) continue; } else { if (x[j][2] < x[i][2]) continue; if (x[j][2] == ztmp && x[j][1] < ytmp) continue; if (x[j][2] == ztmp && x[j][1] == ytmp && x[j][0] < xtmp) continue; } // Qj calculates 2-body Coulombic jtype = map[type[j]]; jq = q[j]; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; iparam_ij = elem2param[itype][jtype][jtype]; // long range q-dependent if (rsq > params[iparam_ij].lcutsq) continue; inty = intype[itype][jtype]; // polynomial three-point interpolation tri_point(rsq, mr1, mr2, mr3, sr1, sr2, sr3, itype); // 1/r energy and forces direct(inty,mr1,mr2,mr3,rsq,sr1,sr2,sr3,iq,jq, potal,fac11,fac11e,vionij,fvionij); // field correction to self energy field(¶ms[iparam_ij],rsq,iq,jq,vionij,fvionij); // polarization field // sums up long range forces f[i][0] += delx*fvionij; f[i][1] += dely*fvionij; f[i][2] += delz*fvionij; f[j][0] -= delx*fvionij; f[j][1] -= dely*fvionij; f[j][2] -= delz*fvionij; if (evflag) ev_tally(i,j,nlocal,newton_pair,0.0,vionij,fvionij,delx,dely,delz); // short range q-independent if (rsq > params[iparam_ij].cutsq) continue; repulsive(¶ms[iparam_ij],rsq,fpair,eflag,evdwl,iq,jq); // repulsion is pure two-body, sums up pair repulsive forces f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; 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); } // accumulate coordination number information if (cor_flag) { for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; + j &= NEIGHMASK; jtype = map[type[j]]; iparam_ij = elem2param[itype][jtype][jtype]; if(params[iparam_ij].hfocor > 0.0 ) { delr1[0] = x[j][0] - xtmp; delr1[1] = x[j][1] - ytmp; delr1[2] = x[j][2] - ztmp; rsq1 = vec3_dot(delr1,delr1); if (rsq1 > params[iparam_ij].cutsq) continue; NCo[i] += 1; } } } // three-body interactions // skip immediately if I-J is not within cutoff for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; + j &= NEIGHMASK; jtype = map[type[j]]; iparam_ij = elem2param[itype][jtype][jtype]; // this Qj for q-dependent BSi jq = q[j]; delr1[0] = x[j][0] - xtmp; delr1[1] = x[j][1] - ytmp; delr1[2] = x[j][2] - ztmp; rsq1 = vec3_dot(delr1,delr1); if (rsq1 > params[iparam_ij].cutsq) continue; // accumulate bondorder zeta for each i-j interaction via loop over k zeta_ij = 0.0; cuo_flag1 = 0; cuo_flag2 = 0; for (kk = 0; kk < jnum; kk++) { if (jj == kk) continue; k = jlist[kk]; + k &= NEIGHMASK; ktype = map[type[k]]; iparam_ijk = elem2param[itype][jtype][ktype]; delr2[0] = x[k][0] - xtmp; delr2[1] = x[k][1] - ytmp; delr2[2] = x[k][2] - ztmp; rsq2 = vec3_dot(delr2,delr2); if (rsq2 > params[iparam_ijk].cutsq) continue; zeta_ij += zeta(¶ms[iparam_ijk],rsq1,rsq2,delr1,delr2); if (params[iparam_ijk].hfocor == -2.0) cuo_flag1 = 1; if (params[iparam_ijk].hfocor == -1.0) cuo_flag2 = 1; } if (cuo_flag1 && cuo_flag2) cuo_flag = 1; else cuo_flag = 0; force_zeta(¶ms[iparam_ij],rsq1,zeta_ij,fpair, prefactor,eflag,evdwl,iq,jq); // over-coordination correction for HfO2 if (cor_flag && NCo[i] != 0) Over_cor(¶ms[iparam_ij],rsq1,NCo[i],Eov, Fov); evdwl += Eov; fpair += Fov; f[i][0] += delr1[0]*fpair; f[i][1] += delr1[1]*fpair; f[i][2] += delr1[2]*fpair; f[j][0] -= delr1[0]*fpair; f[j][1] -= delr1[1]*fpair; f[j][2] -= delr1[2]*fpair; if (evflag) ev_tally(i,j,nlocal,newton_pair, evdwl,0.0,-fpair,-delr1[0],-delr1[1],-delr1[2]); // attractive term via loop over k (3-body forces) for (kk = 0; kk < jnum; kk++) { if (jj == kk) continue; k = jlist[kk]; + k &= NEIGHMASK; ktype = map[type[k]]; iparam_ijk = elem2param[itype][jtype][ktype]; delr2[0] = x[k][0] - xtmp; delr2[1] = x[k][1] - ytmp; delr2[2] = x[k][2] - ztmp; rsq2 = vec3_dot(delr2,delr2); if (rsq2 > params[iparam_ijk].cutsq) continue; for (rsc = 0; rsc < 3; rsc++) fi[rsc] = fj[rsc] = fk[rsc] = 0.0; attractive(¶ms[iparam_ijk],prefactor, rsq1,rsq2,delr1,delr2,fi,fj,fk); // 3-body LP and BB correction and forces elp_ij = elp(¶ms[iparam_ijk],rsq1,rsq2,delr1,delr2); flp(¶ms[iparam_ijk],rsq1,rsq2,delr1,delr2,filp,fjlp,fklp); for (rsc = 0; rsc < 3; rsc++) { fi[rsc] += filp[rsc]; fj[rsc] += fjlp[rsc]; fk[rsc] += fklp[rsc]; } for (rsc = 0; rsc < 3; rsc++) { f[i][rsc] += fi[rsc]; f[j][rsc] += fj[rsc]; f[k][rsc] += fk[rsc]; } if (evflag) ev_tally(i,j,nlocal,newton_pair,elp_ij,0.0,0.0,0.0,0.0,0.0); if (vflag_atom) v_tally3(i,j,k,fj,fk,delr1,delr2); } } if (cuo_flag) params[iparam_i].cutsq *= 0.65; } cuo_flag = 0; if (vflag_fdotr) virial_compute(); } /* ---------------------------------------------------------------------- */ void PairComb::allocate() { allocated = 1; int n = atom->ntypes; memory->create(setflag,n+1,n+1,"pair:setflag"); memory->create(cutsq,n+1,n+1,"pair:cutsq"); map = new int[n+1]; esm = new double[n]; } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairComb::settings(int narg, char **arg) { if (narg > 0) error->all("Illegal pair_style command"); } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairComb::coeff(int narg, char **arg) { int i,j,n; double r; if (!allocated) allocate(); if (narg != 3 + atom->ntypes) error->all("Incorrect args for pair coefficients"); // insure I,J args are * * if (strcmp(arg[0],"*") != 0 || strcmp(arg[1],"*") != 0) error->all("Incorrect args for pair coefficients"); // read args that map atom types to elements in potential file // map[i] = which element the Ith atom type is, -1 if NULL // nelements = # of unique elements // elements = list of element names if (elements) { for (i = 0; i < nelements; i++) delete [] elements[i]; delete [] elements; } elements = new char*[atom->ntypes]; for (i = 0; i < atom->ntypes; i++) elements[i] = NULL; nelements = 0; for (i = 3; i < narg; i++) { if (strcmp(arg[i],"NULL") == 0) { map[i-2] = -1; continue; } for (j = 0; j < nelements; j++) if (strcmp(arg[i],elements[j]) == 0) break; map[i-2] = j; if (j == nelements) { n = strlen(arg[i]) + 1; elements[j] = new char[n]; strcpy(elements[j],arg[i]); nelements++; } } // read potential file and initialize potential parameters read_file(arg[2]); setup(); n = atom->ntypes; // generate streitz-mintmire direct 1/r energy look-up table if (comm->me == 0 && screen) fprintf(screen,"Pair COMB:\n"); if (comm->me == 0 && screen) fprintf(screen," generating Coulomb integral lookup table ...\n"); sm_table(); if (cor_flag && comm->me == 0 && screen) fprintf(screen," will apply over-coordination correction ...\n"); if (!cor_flag&& comm->me == 0 && screen) fprintf(screen," will not apply over-coordination correction ...\n"); // clear setflag since coeff() called once with I,J = * * for (int i = 1; i <= n; i++) for (int j = i; j <= n; j++) setflag[i][j] = 0; // set setflag i,j for type pairs where both are mapped to elements int count = 0; for (int i = 1; i <= n; i++) for (int j = i; j <= n; j++) if (map[i] >= 0 && map[j] >= 0) { setflag[i][j] = 1; count++; } if (count == 0) error->all("Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairComb::init_style() { if (atom->tag_enable == 0) error->all("Pair style COMB requires atom IDs"); if (force->newton_pair == 0) error->all("Pair style COMB requires newton pair on"); if (!atom->q_flag) error->all("Pair style COMB requires atom attribute q"); // ptr to QEQ fix //for (i = 0; i < modify->nfix; i++) // if (strcmp(modify->fix[i]->style,"qeq") == 0) break; //if (i < modify->nfix) fixqeq = (FixQEQ *) modify->fix[i]; //else fixqeq = NULL; // need a full neighbor list int irequest = neighbor->request(this); neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->full = 1; } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairComb::init_one(int i, int j) { if (setflag[i][j] == 0) error->all("All pair coeffs are not set"); return cutmax; } /* ---------------------------------------------------------------------- */ void PairComb::read_file(char *file) { int params_per_line = 49; char **words = new char*[params_per_line+1]; if (params) delete [] params; params = NULL; nparams = 0; // open file on proc 0 FILE *fp; if (comm->me == 0) { fp = fopen(file,"r"); if (fp == NULL) { char str[128]; sprintf(str,"Cannot open COMB potential file %s",file); error->one(str); } } // read each line out of file, skipping blank lines or leading '#' // store line of params if all 3 element tags are in element list int n,nwords,ielement,jelement,kelement; 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("Incorrect format in COMB 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; // ielement,jelement,kelement = 1st args // if all 3 args are in element list, then parse this line // else skip to next line for (ielement = 0; ielement < nelements; ielement++) if (strcmp(words[0],elements[ielement]) == 0) break; if (ielement == nelements) continue; for (jelement = 0; jelement < nelements; jelement++) if (strcmp(words[1],elements[jelement]) == 0) break; if (jelement == nelements) continue; for (kelement = 0; kelement < nelements; kelement++) if (strcmp(words[2],elements[kelement]) == 0) break; if (kelement == nelements) 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].ielement = ielement; params[nparams].jelement = jelement; params[nparams].kelement = kelement; params[nparams].powerm = atof(words[3]); params[nparams].c = atof(words[4]); params[nparams].d = atof(words[5]); params[nparams].h = atof(words[6]); params[nparams].powern = atof(words[7]); params[nparams].beta = atof(words[8]); params[nparams].lam21 = atof(words[9]); params[nparams].lam22 = atof(words[10]); params[nparams].bigb1 = atof(words[11]); params[nparams].bigb2 = atof(words[12]); params[nparams].bigr = atof(words[13]); params[nparams].bigd = atof(words[14]); params[nparams].lam11 = atof(words[15]); params[nparams].lam12 = atof(words[16]); params[nparams].biga1 = atof(words[17]); params[nparams].biga2 = atof(words[18]); params[nparams].plp1 = atof(words[19]); params[nparams].plp3 = atof(words[20]); params[nparams].plp6 = atof(words[21]); params[nparams].a123 = atof(words[22]); params[nparams].aconf= atof(words[23]); params[nparams].addrep = atof(words[24]); params[nparams].romigb = atof(words[25]); params[nparams].romigc = atof(words[26]); params[nparams].romigd = atof(words[27]); params[nparams].romiga = atof(words[28]); params[nparams].QL1 = atof(words[29]); params[nparams].QU1 = atof(words[30]); params[nparams].DL1 = atof(words[31]); params[nparams].DU1 = atof(words[32]); params[nparams].QL2 = atof(words[33]); params[nparams].QU2 = atof(words[34]); params[nparams].DL2 = atof(words[35]); params[nparams].DU2 = atof(words[36]); params[nparams].chi = atof(words[37]); params[nparams].dj = atof(words[38]); params[nparams].dk = atof(words[39]); params[nparams].dl = atof(words[40]); params[nparams].dm = atof(words[41]); params[nparams].esm1 = atof(words[42]); params[nparams].cmn1 = atof(words[43]); params[nparams].cml1 = atof(words[44]); params[nparams].cmn2 = atof(words[45]); params[nparams].cml2 = atof(words[46]); params[nparams].coulcut = atof(words[47]); params[nparams].hfocor = atof(words[48]); params[nparams].powermint = int(params[nparams].powerm); // parameter sanity checks if (params[nparams].lam11 < 0.0 || params[nparams].lam12 < 0.0 || params[nparams].c < 0.0 || params[nparams].d < 0.0 || params[nparams].powern < 0.0 || params[nparams].beta < 0.0 || params[nparams].lam21 < 0.0 || params[nparams].lam22 < 0.0 || params[nparams].bigb1< 0.0 || params[nparams].bigb2< 0.0 || params[nparams].biga1< 0.0 || params[nparams].biga2< 0.0 || params[nparams].bigr < 0.0 || params[nparams].bigd < 0.0 || params[nparams].bigd > params[nparams].bigr || params[nparams].powerm - params[nparams].powermint != 0.0 || (params[nparams].powermint != 3 && params[nparams].powermint != 1) || params[nparams].plp1 < 0.0 || params[nparams].plp3 < 0.0 || params[nparams].plp6 < 0.0 || params[nparams].a123 > 360.0 || params[nparams].aconf < 0.0 || params[nparams].addrep < 0.0 || params[nparams].romigb < 0.0 || params[nparams].romigc < 0.0 || params[nparams].romigd < 0.0 || params[nparams].romiga < 0.0 || params[nparams].QL1 > 0.0 || params[nparams].QU1 < 0.0 || params[nparams].DL1 < 0.0 || params[nparams].DU1 > 0.0 || params[nparams].QL2 > 0.0 || params[nparams].QU2 < 0.0 || params[nparams].DL2 < 0.0 || params[nparams].DU2 > 0.0 || params[nparams].chi < 0.0 || // params[nparams].dj < 0.0 || params[nparams].dk < 0.0 || // params[nparams].dl < 0.0 || params[nparams].dm < 0.0 || params[nparams].esm1 < 0.0) error->all("Illegal COMB parameter"); if (params[nparams].lam11 < params[nparams].lam21 || params[nparams].lam12 < params[nparams].lam22 || params[nparams].biga1< params[nparams].bigb1 || params[nparams].biga2< params[nparams].bigb2) error->all("Illegal COMB parameter"); nparams++; } delete [] words; } /* ---------------------------------------------------------------------- */ void PairComb::setup() { int i,j,k,m,n; // set elem2param for all element triplet combinations // must be a single exact match to lines read from file // do not allow for ACB in place of ABC memory->destroy(elem2param); memory->create(elem2param,nelements,nelements,nelements,"pair:elem2param"); for (i = 0; i < nelements; i++) for (j = 0; j < nelements; j++) for (k = 0; k < nelements; k++) { n = -1; for (m = 0; m < nparams; m++) { if (i == params[m].ielement && j == params[m].jelement && k == params[m].kelement) { if (n >= 0) error->all("Potential file has duplicate entry"); n = m; } } if (n < 0) error->all("Potential file is missing an entry"); elem2param[i][j][k] = n; } // compute parameter values derived from inputs for (m = 0; m < nparams; m++) { params[m].cut = params[m].bigr + params[m].bigd; params[m].cutsq = params[m].cut*params[m].cut; params[m].c1 = pow(2.0*params[m].powern*1.0e-16,-1.0/params[m].powern); params[m].c2 = pow(2.0*params[m].powern*1.0e-8,-1.0/params[m].powern); params[m].c3 = 1.0/params[m].c2; params[m].c4 = 1.0/params[m].c1; params[m].rlm1 = 0.5*(params[m].lam11+params[m].lam12)*params[m].romigc; params[m].rlm2 = 0.5*(params[m].lam21+params[m].lam22)*params[m].romigd; params[m].Qo1 = (params[m].QU1+params[m].QL1)/2.0; // (A22) params[m].dQ1 = (params[m].QU1-params[m].QL1)/2.0; // (A21) params[m].aB1 = 1.0 / (1.0-pow(fabs(params[m].Qo1/params[m].dQ1),10)); // (A20) params[m].bB1 = pow(fabs(params[m].aB1),0.1)/params[m].dQ1; // (A19) params[m].nD1 = log(params[m].DU1/(params[m].DU1-params[m].DL1))/ log(params[m].QU1/(params[m].QU1-params[m].QL1)); params[m].bD1 = (pow((params[m].DL1-params[m].DU1),(1.0/params[m].nD1)))/ (params[m].QU1-params[m].QL1); params[m].Qo2 = (params[m].QU2+params[m].QL2)/2.0; // (A22) params[m].dQ2 = (params[m].QU2-params[m].QL2)/2.0; // (A21) params[m].aB2 = 1.0 / (1.0-pow(fabs(params[m].Qo2/params[m].dQ2),10)); // (A20) params[m].bB2 = pow(fabs(params[m].aB2),0.1)/params[m].dQ2; // (A19) params[m].nD2 = log(params[m].DU2/(params[m].DU2-params[m].DL2))/ log(params[m].QU2/(params[m].QU2-params[m].QL2)); params[m].bD2 = (pow((params[m].DL2-params[m].DU2),(1.0/params[m].nD2)))/ (params[m].QU2-params[m].QL2); params[m].lcut = params[m].coulcut; params[m].lcutsq = params[m].lcut*params[m].lcut; } // set cutmax to max of all params cutmax = 0.0; cor_flag = 0; for (m = 0; m < nparams; m++) { if (params[m].cut > cutmax) cutmax = params[m].cut; if (params[m].lcut > cutmax) cutmax = params[m].lcut; if (params[m].hfocor > 0.0001) cor_flag = 1; } } /* ---------------------------------------------------------------------- */ void PairComb::repulsive(Param *param, double rsq, double &fforce, int eflag, double &eng, double iq, double jq) { double r,tmp_fc,tmp_fc_d,tmp_exp,Di,Dj; double bigA,Asi,Asj,vrcs,fvrcs,fforce_tmp; double rslp,rslp2,rslp4,arr1,arr2,fc2j,fc3j,fcp2j,fcp3j; double romi = param->addrep; double rrcs = param->bigr + param->bigd; r = sqrt(rsq); if (r > rrcs) return ; tmp_fc = comb_fc(r,param); tmp_fc_d = comb_fc_d(r,param); tmp_exp = exp(-param->rlm1 * r); arr1 = 2.22850; arr2 = 1.89350; fc2j = comb_fc2(r); fc3j = comb_fc3(r); fcp2j = comb_fc2_d(r); fcp3j = comb_fc3_d(r); Di = param->DU1 + pow(fabs(param->bD1*(param->QU1-iq)),param->nD1); Dj = param->DU2 + pow(fabs(param->bD2*(param->QU2-jq)),param->nD2); Asi = param->biga1 * exp(param->lam11*Di); Asj = param->biga2 * exp(param->lam12*Dj); if ( Asi > 0.0 && Asj > 0.0 ) bigA = sqrt(Asi*Asj)*param->romiga; else bigA = 0.0; fforce = -bigA * tmp_exp * (tmp_fc_d - tmp_fc*param->rlm1) / r; // additional repulsion for TiO2 and HfO2 (switch by cor_flag) vrcs = 0.0; fvrcs = 0.0; if (romi > 0.0) { if (!cor_flag) { vrcs = romi * pow((1.0-r/rrcs),2.0); fvrcs= romi * 2.0 * (r/rrcs-1.0)/rrcs; } else if (cor_flag) { rslp = ((arr1-r)/(arr1-arr2)); rslp2 = rslp * rslp; rslp4 = rslp2 * rslp2; vrcs = fc2j * fc3j * romi * ((50.0*rslp4-30.0*rslp2+4.50))/8.0; fvrcs = fcp2j*fcp3j*romi*rslp*(-25.0*rslp2+7.50)/(arr1-arr2); } fforce_tmp = fforce*vrcs - (tmp_fc * bigA * tmp_exp * fvrcs); fforce += fforce_tmp; } // eng = repulsive energy if (eflag) eng = (tmp_fc * bigA * tmp_exp)*(1.0+vrcs); } /* ---------------------------------------------------------------------- */ double PairComb::zeta(Param *param, double rsqij, double rsqik, double *delrij, double *delrik) { double rij,rik,costheta,arg,ex_delr; rij = sqrt(rsqij); if (rij > param->bigr+param->bigd) return 0.0; rik = sqrt(rsqik); costheta = vec3_dot(delrij,delrik) / (rij*rik); if (param->powermint == 3) arg = pow(param->rlm2 * (rij-rik),3.0); else arg = param->rlm2 * (rij-rik); if (arg > 69.0776) ex_delr = 1.e30; else if (arg < -69.0776) ex_delr = 0.0; else ex_delr = exp(arg); return comb_fc(rik,param) * comb_gijk(costheta,param) * ex_delr; } /* ---------------------------------------------------------------------- Legendre polynomial bond angle correction to energy ------------------------------------------------------------------------- */ double PairComb::elp(Param *param, double rsqij, double rsqik, double *delrij, double *delrik) { if (param->aconf > 1.0e-6 || param->plp1 > 1.0e-6 || param->plp3 > 1.0e-6 || param->plp6 > 1.0e-6) { double rij,rik,costheta,lp1,lp3,lp6; double rmu,rmu2,comtt,fck; double pplp1 = param->plp1, pplp3 = param->plp3, pplp6 = param->plp6; double c123 = cos(param->a123*PI/180.0); // cos(theta) of the i-j-k // cutoff function of rik rij = sqrt(rsqij); rik = sqrt(rsqik); costheta = vec3_dot(delrij,delrik) / (rij*rik); fck = comb_fc(rik,param); rmu = costheta; // Legendre Polynomial functions if (param->plp1 > 1.0e-6 || param->plp3 > 1.0e-6 || param->plp6 > 1.0e-6) { rmu2 = rmu*rmu; lp1 = rmu; lp3 = 0.5*(5.0*rmu2*rmu-3.0*rmu); lp6 = (231.0*rmu2*rmu2*rmu2-315.0*rmu2*rmu2+105.0*rmu2-5.0)/16.0; comtt = pplp1*lp1 + pplp3*lp3 + pplp6*lp6; } else comtt = 0.0; // bond-bending terms if (param->aconf>1e-4) { if (param->hfocor >= 0.0) comtt += param->aconf *(rmu-c123)*(rmu-c123); else if (param->hfocor < 0.0) comtt += param->aconf *(4.0-(rmu-c123)*(rmu-c123)); } return 0.5 * fck * comtt; } return 0.0; } /* ---------------------------------------------------------------------- Legendre polynomial bond angle correction to forces ------------------------------------------------------------------------- */ void PairComb::flp(Param *param, double rsqij, double rsqik, double *delrij, double *delrik, double *drilp, double *drjlp, double *drklp) { double ffj1,ffj2,ffk1,ffk2; ffj1 = 0.0; ffj2 = 0.0; ffk1 = 0.0; ffk2 = 0.0; if (param->aconf > 1.0e-4 || param->plp1 > 1.0e-6 || param->plp3 > 1.0e-6 || param->plp6 > 1.0e-6) { double rij,rik,costheta,lp1,lp1_d,lp3,lp3_d,lp6,lp6_d; double rmu,rmu2,comtt,comtt_d,com4k,com5,fcj,fck,fck_d; double pplp1 = param->plp1; double pplp3 = param->plp3; double pplp6 = param->plp6; double c123 = cos(param->a123*PI/180.0); // fck_d = derivative of cutoff function rij = sqrt(rsqij); rik = sqrt(rsqik); costheta = vec3_dot(delrij,delrik) / (rij*rik); fcj = comb_fc(rij,param); fck = comb_fc(rik,param); fck_d = comb_fc_d(rik,param); rmu = costheta; // Legendre Polynomial functions and derivatives if (param->plp1 > 1.0e-6 || param->plp3 > 1.0e-6 || param->plp6 > 1.0e-6) { rmu2 = rmu*rmu; lp1 = rmu; lp3 = (2.5*rmu2*rmu-1.5*rmu); lp6 = (231.0*rmu2*rmu2*rmu2-315.0*rmu2*rmu2+105.0*rmu2-5.0)/16.0; lp1_d = 1.0;lp3_d = (7.5*rmu2-1.5); lp6_d = (1386.0*rmu2*rmu2*rmu-1260.0*rmu2*rmu+210.0)/16.0; comtt = pplp1*lp1 + pplp3*lp3 + pplp6*lp6; comtt_d = pplp1*lp1_d + pplp3*lp3_d + pplp6*lp6_d; } else { comtt = 0.0; comtt_d = 0.0; } // bond-bending terms derivatives if (param->aconf > 1.0e-4) { if (param->hfocor >= 0.0) { comtt += param->aconf *(rmu-c123)*(rmu-c123); comtt_d += 2.0*param->aconf*(rmu-c123); } else if (param->hfocor < 0.0) { comtt += param->aconf *(4.0-(rmu-c123)*(rmu-c123)); comtt_d += -2.0*param->aconf*(rmu-c123); } } com4k = fcj * fck_d * comtt; com5 = fcj * fck * comtt_d; ffj1 =-0.5*(com5/(rij*rik)); ffj2 = 0.5*(com5*rmu/rsqij); ffk1 = ffj1; ffk2 = 0.5*(-com4k/rik+com5*rmu/rsqik); } else { ffj1 = 0.0; ffj2 = 0.0; ffk1 = 0.0; ffk2 = 0.0; } // j-atom vec3_scale(ffj1,delrik,drjlp); // (k,x[],y[]), y[]=k*x[] vec3_scaleadd(ffj2,delrij,drjlp,drjlp); // (k,x[],y[],z[]), z[]=k*x[]+y[] // k-atom vec3_scale(ffk1,delrij,drklp); vec3_scaleadd(ffk2,delrik,drklp,drklp); // i-atom vec3_add(drjlp,drklp,drilp); // (x[],y[],z[]), z[]=x[]+y[] vec3_scale(-1.0,drilp,drilp); } /* ---------------------------------------------------------------------- */ void PairComb::force_zeta(Param *param, double rsq, double zeta_ij, double &fforce, double &prefactor, int eflag, double &eng, double iq, double jq) { double r,fa,fa_d,bij; r = sqrt(rsq); if (r > param->bigr+param->bigd) return; fa = comb_fa(r,param,iq,jq); fa_d = comb_fa_d(r,param,iq,jq); bij = comb_bij(zeta_ij,param); fforce = 0.5*bij*fa_d / r; prefactor = -0.5*fa * comb_bij_d(zeta_ij,param); // eng = attractive energy if (eflag) eng = 0.5*bij*fa; } /* ---------------------------------------------------------------------- */ double PairComb::comb_fc(double r, Param *param) { double comb_R = param->bigr; double comb_D = param->bigd; if (r < comb_R-comb_D) return 1.0; if (r > comb_R+comb_D) return 0.0; return 0.5*(1.0 + cos(PI*(r - comb_R)/comb_D)); } /* ---------------------------------------------------------------------- */ double PairComb::comb_fc_d(double r, Param *param) { double comb_R = param->bigr; double comb_D = param->bigd; if (r < comb_R-comb_D) return 0.0; if (r > comb_R+comb_D) return 0.0; return -(PI2/comb_D) * sin(PI*(r - comb_R)/comb_D); } /* ---------------------------------------------------------------------- */ double PairComb::comb_fc2(double r) { double comb_R = 1.89350; double comb_D = comb_R + 0.050; if (r < comb_R) return 0.0; if (r > comb_D) return 1.0; return 0.5*(1.0 + cos(PI*(r - comb_R)/(comb_D-comb_R))); } /* ---------------------------------------------------------------------- */ double PairComb::comb_fc2_d(double r) { double comb_R = 1.89350; double comb_D = comb_R + 0.050; if (r < comb_R) return 0.0; if (r > comb_D) return 0.0; return -(PI2/(comb_D-comb_R)) * sin(PI*(r - comb_R)/(comb_D-comb_R)); } /* ---------------------------------------------------------------------- */ double PairComb::comb_fc3(double r) { double comb_R = 2.51350; double comb_D = comb_R + 0.050; if (r < comb_R) return 1.0; if (r > comb_D) return 0.0; return 0.5*(1.0 + cos(PI*(r - comb_R)/(comb_D-comb_R))); } /* ---------------------------------------------------------------------- */ double PairComb::comb_fc3_d(double r) { double comb_R = 2.51350; double comb_D = comb_R + 0.050; if (r < comb_R) return 0.0; if (r > comb_D) return 0.0; return -(PI2/(comb_D-comb_R)) * sin(PI*(r - comb_R)/(comb_D-comb_R)); } /* ---------------------------------------------------------------------- */ double PairComb::self(Param *param, double qi, double selfpot) { double self_tmp, cmin, cmax, qmin, qmax; double s1=param->chi, s2=param->dj, s3=param->dk, s4=param->dl, s5=param->dm; self_tmp = 0.0; qmin = param->QL1*0.90; qmax = param->QU1*0.90; cmin = cmax = 1000.0; self_tmp = qi*(s1+qi*(s2+selfpot+qi*(s3+qi*(s4+qi*qi*s5)))); if (qi < qmin) self_tmp += cmin * pow((qi-qmin),4); if (qi > qmax) self_tmp += cmax * pow((qi-qmax),4); return self_tmp; } /* ---------------------------------------------------------------------- */ double PairComb::comb_fa(double r, Param *param, double iq, double jq) { double bigB,Bsi,Bsj; double qi,qj,Di,Dj; if (r > param->bigr + param->bigd) return 0.0; qi = iq; qj = jq; Di = Dj = Bsi = Bsj = bigB = 0.0; Di = param->DU1 + pow(fabs(param->bD1*(param->QU1-qi)),param->nD1); Dj = param->DU2 + pow(fabs(param->bD2*(param->QU2-qj)),param->nD2); Bsi = param->bigb1 * exp(param->lam21*Di)* (param->aB1-fabs(pow(param->bB1*(qi-param->Qo1),10))); Bsj = param->bigb2 * exp(param->lam22*Dj)* (param->aB2-fabs(pow(param->bB2*(qj-param->Qo2),10))); if (Bsi > 0.0 && Bsj > 0.0) bigB = sqrt(Bsi*Bsj)*param->romigb; else bigB = 0.0; return -bigB * exp(-param->rlm2 * r) * comb_fc(r,param); } /* ---------------------------------------------------------------------- */ double PairComb::comb_fa_d(double r, Param *param, double iq, double jq) { double bigB,Bsi,Bsj; double qi,qj,Di,Dj; if (r > param->bigr + param->bigd) return 0.0; qi = iq; qj = jq; Di = Dj = Bsi = Bsj = bigB = 0.0; Di = param->DU1 + pow(fabs(param->bD1*(param->QU1-qi)),param->nD1); Dj = param->DU2 + pow(fabs(param->bD2*(param->QU2-qj)),param->nD2); Bsi = param->bigb1 * exp(param->lam21*Di)* (param->aB1-fabs(pow(param->bB1*(qi-param->Qo1),10))); Bsj = param->bigb2 * exp(param->lam22*Dj)* (param->aB2-fabs(pow(param->bB2*(qj-param->Qo2),10))); if (Bsi > 0.0 && Bsj > 0.0) bigB = sqrt(Bsi*Bsj)*param->romigb; else bigB = 0.0; return bigB * exp(-param->rlm2 * r) * (param->rlm2 * comb_fc(r,param) - comb_fc_d(r,param)); } /* ---------------------------------------------------------------------- */ double PairComb::comb_bij(double zeta, Param *param) { double tmp = param->beta * zeta; if (tmp > param->c1) return 1.0/sqrt(tmp); if (tmp > param->c2) return (1.0 - pow(tmp,-param->powern) / (2.0*param->powern))/sqrt(tmp); if (tmp < param->c4) return 1.0; if (tmp < param->c3) return 1.0 - pow(tmp,param->powern)/(2.0*param->powern); return pow(1.0 + pow(tmp,param->powern), -1.0/(2.0*param->powern)); } /* ---------------------------------------------------------------------- */ double PairComb::comb_bij_d(double zeta, Param *param) { double tmp = param->beta * zeta; if (tmp > param->c1) return param->beta * -0.5*pow(tmp,-1.5); if (tmp > param->c2) return param->beta * (-0.5*pow(tmp,-1.5) * (1.0 - 0.5*(1.0 + 1.0/(2.0*param->powern)) * pow(tmp,-param->powern))); if (tmp < param->c4) return 0.0; if (tmp < param->c3) return -0.5*param->beta * pow(tmp,param->powern-1.0); double tmp_n = pow(tmp,param->powern); return -0.5 * pow(1.0+tmp_n, -1.0-(1.0/(2.0*param->powern)))*tmp_n / zeta; } /* ---------------------------------------------------------------------- */ double PairComb::comb_gijk(double costheta, Param *param) { double comb_c = param->c; double comb_d = param->d; return (1.0 + pow(comb_c/comb_d,2.0) - pow(comb_c,2.0) / (pow(comb_d,2.0) + pow(param->h - costheta,2.0))); }; /* ---------------------------------------------------------------------- */ double PairComb::comb_gijk_d(double costheta, Param *param) { double numerator = -2.0 * pow(param->c,2) * (param->h - costheta); double denominator = pow(pow(param->d,2.0) + pow(param->h - costheta,2.0),2.0); return numerator/denominator; } /*------------------------------------------------------------------------- */ void PairComb::attractive(Param *param, double prefactor, double rsqij, double rsqik, double *delrij, double *delrik, double *fi, double *fj, double *fk) { double rij_hat[3],rik_hat[3]; double rij,rijinv,rik,rikinv; rij = sqrt(rsqij); rijinv = 1.0/rij; vec3_scale(rijinv,delrij,rij_hat); rik = sqrt(rsqik); rikinv = 1.0/rik; vec3_scale(rikinv,delrik,rik_hat); comb_zetaterm_d(prefactor,rij_hat,rij,rik_hat,rik,fi,fj,fk,param); } /* ---------------------------------------------------------------------- */ void PairComb::comb_zetaterm_d(double prefactor, double *rij_hat, double rij, double *rik_hat, double rik, double *dri, double *drj, double *drk, Param *param) { double gijk,gijk_d,ex_delr,ex_delr_d,fc,dfc,cos_theta,tmp; double dcosdri[3],dcosdrj[3],dcosdrk[3]; fc = comb_fc(rik,param); dfc = comb_fc_d(rik,param); if (param->powermint == 3) tmp = pow(param->rlm2 * (rij-rik),3.0); else tmp = param->rlm2 * (rij-rik); if (tmp > 69.0776) ex_delr = 1.e30; else if (tmp < -69.0776) ex_delr = 0.0; else ex_delr = exp(tmp); // ex_delr is Ygexp if (param->powermint == 3) ex_delr_d = 3.0*pow(param->rlm2,3.0) * pow(rij-rik,2.0)*ex_delr; // com3 else ex_delr_d = param->rlm2 * ex_delr; // com3 cos_theta = vec3_dot(rij_hat,rik_hat); gijk = comb_gijk(cos_theta,param); gijk_d = comb_gijk_d(cos_theta,param); costheta_d(rij_hat,rij,rik_hat,rik,dcosdri,dcosdrj,dcosdrk); // compute the derivative wrt Ri // dri = -dfc*gijk*ex_delr*rik_hat; // dri += fc*gijk_d*ex_delr*dcosdri; // dri += fc*gijk*ex_delr_d*(rik_hat - rij_hat); // (k,x[],y[]), y[]=k*x[] // (k,x[],y[],z[]), z[]=k*x[]+y[] vec3_scale(-dfc*gijk*ex_delr,rik_hat,dri); vec3_scaleadd(fc*gijk_d*ex_delr,dcosdri,dri,dri); vec3_scaleadd(fc*gijk*ex_delr_d,rik_hat,dri,dri); vec3_scaleadd(-fc*gijk*ex_delr_d,rij_hat,dri,dri); vec3_scale(prefactor,dri,dri); // compute the derivative wrt Rj // drj = fc*gijk_d*ex_delr*dcosdrj; // drj += fc*gijk*ex_delr_d*rij_hat; vec3_scale(fc*gijk_d*ex_delr,dcosdrj,drj); vec3_scaleadd(fc*gijk*ex_delr_d,rij_hat,drj,drj); vec3_scale(prefactor,drj,drj); // compute the derivative wrt Rk // drk = dfc*gijk*ex_delr*rik_hat; // drk += fc*gijk_d*ex_delr*dcosdrk; // drk += -fc*gijk*ex_delr_d*rik_hat; vec3_scale(dfc*gijk*ex_delr,rik_hat,drk); vec3_scaleadd(fc*gijk_d*ex_delr,dcosdrk,drk,drk); vec3_scaleadd(-fc*gijk*ex_delr_d,rik_hat,drk,drk); vec3_scale(prefactor,drk,drk); } /* ---------------------------------------------------------------------- */ void PairComb::costheta_d(double *rij_hat, double rij, double *rik_hat, double rik, double *dri, double *drj, double *drk) { // first element is devative wrt Ri, second wrt Rj, third wrt Rk double cos_theta = vec3_dot(rij_hat,rik_hat); vec3_scaleadd(-cos_theta,rij_hat,rik_hat,drj); vec3_scale(1.0/rij,drj,drj); vec3_scaleadd(-cos_theta,rik_hat,rij_hat,drk); vec3_scale(1.0/rik,drk,drk); vec3_add(drj,drk,dri); vec3_scale(-1.0,dri,dri); } /* ---------------------------------------------------------------------- */ void PairComb::sm_table() { int i,j,k,m,nntypes,ncoul; int inty, itype, jtype; int iparam_i, iparam_ij, iparam_ji; double r,dra,drin,rc,z,zr,zrc,ea,eb,ea3,eb3,alf; double exp2er,exp2ersh,fafash,dfafash,F1,dF1,ddF1,E1,E2,E3,E4; double exp2ear,exp2ebr,exp2earsh,exp2ebrsh,fafbsh,dfafbsh; int n = atom->ntypes; int *type = atom->type; dra = 0.001; // lookup table step size drin = 0.1; // starting distance of 1/r rc = cutmax; alf = 0.20; nntypes = int((n+1)*n/2); // interaction types ncoul = int((rc-drin)/dra)+1; memory->destroy(intype); memory->destroy(fafb); memory->destroy(dfafb); memory->destroy(ddfafb); memory->destroy(phin); memory->destroy(dphin); memory->destroy(erpaw); // allocate arrays memory->create(intype,n,n,"pair:intype"); memory->create(fafb,ncoul,nntypes,"pair:fafb"); memory->create(dfafb,ncoul,nntypes,"pair:dfafb"); memory->create(ddfafb,ncoul,nntypes,"pair:ddfafb"); memory->create(phin,ncoul,nntypes,"pair:phin"); memory->create(dphin,ncoul,nntypes,"pair:dphin"); memory->create(erpaw,25000,2,"pair:erpaw"); // set interaction number: 0-0=0, 1-1=1, 0-1=1-0=2 m = 0; k = n; for (i = 0; i < n; i++) { for (j = 0; j < n; j++) { if (j == i) { intype[i][j] = m; m += 1; } else if (j != i && j > i) { intype[i][j] = k; k += 1; } else if (j != i && j < i) { intype[i][j] = intype[j][i]; } } } // default arrays to zero for (i = 0; i < ncoul; i ++) { for (j = 0; j < nntypes; j ++) { fafb[i][j] = 0.0; dfafb[i][j] = 0.0; ddfafb[i][j] = 0.0; phin[i][j] = 0.0; dphin[i][j] = 0.0; } } // direct 1/r energy with Slater 1S orbital overlap for (i = 0; i < n; i++) { r = drin; itype = params[i].ielement; iparam_i = elem2param[itype][itype][itype]; z = params[iparam_i].esm1; for (j = 0; j < ncoul; j++) { exp2er = exp(-2.0 * z * r); phin[j][i] = 1.0 - exp2er * (1.0 + 2.0 * z * r * (1.0 + z * r)); dphin[j][i] = (4.0 * exp2er * z * z * z * r * r); r += dra; } } for (i = 0; i < n; i ++) { for (j = 0; j < n; j ++) { r = drin; if (j == i) { itype = params[i].ielement; inty = intype[itype][itype]; iparam_i = elem2param[itype][itype][itype]; z = params[iparam_i].esm1; zrc = z * rc; exp2ersh = exp(-2.0 * zrc); fafash = -exp2ersh * (1.0 / rc + z * (11.0/8.0 + 3.0/4.0*zrc + zrc*zrc/6.0)); dfafash = exp2ersh * (1.0/(rc*rc) + 2.0*z/rc + z*z*(2.0 + 7.0/6.0*zrc + zrc*zrc/3.0)); for (k = 0; k < ncoul; k ++) { zr = z * r; exp2er = exp(-2.0*zr); F1 = -exp2er * (1.0 / r + z * (11.0/8.0 + 3.0/4.0*zr + zr*zr/6.0)); dF1 = exp2er * (1.0/(r*r) + 2.0*z/r + z*z*(2.0 + 7.0/6.0*zr + zr*zr/3.0)); ddF1 = -exp2er * (2.0/(r*r*r) + 4.0*z/(r*r) - z*z*z/3.0*(17.0/2.0 + 5.0*zr + 2.0*zr*zr)); fafb[k][inty] = F1-fafash-(r-rc)*dfafash; dfafb[k][inty] = (dF1 - dfafash); ddfafb[k][inty] = ddF1; r += dra; } } else if (j != i) { itype = params[i].ielement; jtype = params[j].ielement; inty = intype[itype][jtype]; iparam_ij = elem2param[itype][jtype][jtype]; ea = params[iparam_ij].esm1; ea3 = ea*ea*ea; iparam_ji = elem2param[jtype][itype][itype]; eb = params[iparam_ji].esm1; eb3 = eb*eb*eb; E1 = ea*eb3*eb/((ea+eb)*(ea+eb)*(ea-eb)*(ea-eb)); E2 = eb*ea3*ea/((ea+eb)*(ea+eb)*(eb-ea)*(eb-ea)); E3 = (3.0*ea*ea*eb3*eb-eb3*eb3) / ((ea+eb)*(ea+eb)*(ea+eb)*(ea-eb)*(ea-eb)*(ea-eb)); E4 = (3.0*eb*eb*ea3*ea-ea3*ea3) / ((ea+eb)*(ea+eb)*(ea+eb)*(eb-ea)*(eb-ea)*(eb-ea)); exp2earsh = exp(-2.0*ea*rc); exp2ebrsh = exp(-2.0*eb*rc); fafbsh = -exp2earsh*(E1 + E3/rc)-exp2ebrsh*(E2 + E4/rc); dfafbsh = exp2earsh*(2.0*ea*(E1+E3/rc)+E3/(rc*rc)) + exp2ebrsh*(2.0*eb*(E2+E4/rc)+E4/(rc*rc)); for (k = 0; k < ncoul; k ++) { exp2ear = exp(-2.0*ea*r); exp2ebr = exp(-2.0*eb*r); fafb[k][inty] = - exp2ear*(E1+E3/r) - exp2ebr*(E2+E4/r) - fafbsh - (r-rc) * dfafbsh; dfafb[k][inty] = (exp2ear*(2.0*ea*(E1+E3/r) + E3/(r*r)) + exp2ebr*(2.0*eb*(E2+E4/r) + E4/(r*r))- dfafbsh); ddfafb[k][inty] = (- exp2ear*(E3/(r*r)*(1.0/r+2.0*ea/r+2.0/(r*r)) + 2.0*ea*(E1+E3/r))- exp2ebr*(E4/(r*r) *(1.0/r+2.0*eb/r+2.0/(r*r)) + 2.0*eb*(E2+E4/r))); r += dra; } } } } for (i = 0; i < 25000; i ++) { r = dra * i + drin; erpaw[i][0] = erfc(r*alf); erpaw[i][1] = exp(-r*r*alf*alf); } } /* ---------------------------------------------------------------------- */ void PairComb::potal_calc(double &calc1, double &calc2, double &calc3) { double potal,alf,rcoul,fac11,fac11e,esucon; int m; rcoul = 0.0; for (m = 0; m < nparams; m++) if (params[m].lcut > rcoul) rcoul = params[m].lcut; alf = 0.20; esucon = force->qqr2e; calc2 = (erfc(rcoul*alf)/rcoul/rcoul+2.0*alf/PIsq* exp(-alf*alf*rcoul*rcoul)/rcoul)*esucon/rcoul; calc3 = (erfc(rcoul*alf)/rcoul)*esucon; calc1 = -(alf/PIsq*esucon+calc3*0.5); } /* ---------------------------------------------------------------------- */ void PairComb::tri_point(double rsq, int &mr1, int &mr2, int &mr3, double &sr1, double &sr2, double &sr3, int &itype) { double r, rin, dr, dd, rr1, rridr, rridr2; int m = itype; rin = 0.10; dr = 0.0010; r = sqrt(rsq); if (r < rin + 2.0*dr) r = rin + 2.0*dr; if (r > cutmax - 2.0*dr) r = cutmax - 2.0*dr; rridr = (r-rin)/dr; mr1 = int(rridr)-1; dd = rridr - float(mr1); if (dd > 0.5) mr1 += 1; mr2 = mr1 + 1; mr3 = mr2 + 1; rr1 = float(mr1)*dr; rridr = (r - rin - rr1)/dr; rridr2 = rridr * rridr; sr1 = (rridr2 - rridr) * 0.50; sr2 = 1.0 - rridr2; sr3 = (rridr2 + rridr) * 0.50; } /* ---------------------------------------------------------------------- */ void PairComb::direct(int inty, int mr1, int mr2, int mr3, double rsq, double sr1, double sr2, double sr3, double iq, double jq, double potal, double fac11, double fac11e, double &pot_tmp, double &pot_d) { double r,erfcc,fafbn1,potij,sme2,chrij,esucon; double r3,erfcd,dfafbn1,smf2,dvdrr,alf,alfdpi; r = sqrt(rsq); r3 = r * rsq; alf = 0.20; alfdpi = 2.0*alf/PIsq; esucon = force->qqr2e; pot_tmp = 0.0; pot_d = 0.0; // 1/r energy erfcc = sr1*erpaw[mr1][0] + sr2*erpaw[mr2][0] + sr3*erpaw[mr3][0]; fafbn1= sr1*fafb[mr1][inty] + sr2*fafb[mr2][inty] + sr3*fafb[mr3][inty]; potij = (erfcc/r * esucon - fac11e); sme2 = potij + fafbn1 * esucon; pot_tmp = 1.0 * iq * jq *sme2; // 1/r force (wrt r) erfcd = sr1*erpaw[mr1][1] + sr2*erpaw[mr2][1] + sr3*erpaw[mr3][1]; dfafbn1= sr1*dfafb[mr1][inty] + sr2*dfafb[mr2][inty] + sr3*dfafb[mr3][inty]; dvdrr = (erfcc/r3+alfdpi*erfcd/rsq)*esucon-fac11; smf2 = dvdrr - dfafbn1 * esucon/r; pot_d = 1.0 * iq * jq * smf2; } /* ---------------------------------------------------------------------- */ void PairComb::field(Param *param, double rsq, double iq,double jq, double &vionij,double &fvionij) { double r,r5,r6,rc,rc5,rc6,rf5,drf6,smpn,smpl,rfx1,rfx2; double cmi1,cmi2,cmj1,cmj2; r = sqrt(rsq); r5 = r*r*r*r*r; r6 = r5 * r; rc = param->lcut; rc5 = rc*rc*rc*rc*rc; rc6 = rc5 * rc; cmi1 = param->cmn1; cmi2 = param->cmn2; cmj1 = param->cml1; cmj2 = param->cml2; rf5 = 1.0/r5 - 1.0/rc5 + 5.0*(r-rc)/rc6; drf6 = 5.0/rc6 - 5.0/r6; // field correction energy smpn = rf5*jq*(cmi1+jq*cmi2); smpl = rf5*iq*(cmj1+iq*cmj2); vionij += 1.0 * (smpn + smpl); // field correction force rfx1 = jq*drf6*(cmi1+jq*cmi2)/r; rfx2 = iq*drf6*(cmj1+iq*cmj2)/r; fvionij -= 1.0 * (rfx1 + rfx2); } /* ---------------------------------------------------------------------- */ double PairComb::yasu_char(double *qf_fix, int &igroup) { int i,j,k,ii,jj,kk,jnum; int itag,jtag,itype,jtype,ktype,iparam_i,iparam_ij,iparam_ijk; double xtmp,ytmp,ztmp,evdwl,fpair; double rsq,rsq1,rsq2,delr1[3],delr2[3],zeta_ij; int *ilist,*jlist,*numneigh,**firstneigh; double iq,jq,fqi,fqj,fqij,fqjj,ecoul,yaself,yaself_d; double potal,fac11,fac11e,sr1,sr2,sr3; int mr1,mr2,mr3,inty; int zeta_flag; double **x = atom->x; double *q = atom->q; int *tag = atom->tag; int *type = atom->type; int nlocal = atom->nlocal; int inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; int *mask = atom->mask; int groupbit = group->bitmask[igroup]; qf = qf_fix; for (ii = 0; ii < inum; ii++) { i = ilist[ii]; if (mask[i] & groupbit) qf[i] = 0.0; } // communicating charge force to all nodes, first forward then reverse comm->forward_comm_pair(this); // self energy correction term: potal potal_calc(potal,fac11,fac11e); // loop over full neighbor list of my atoms fqi = fqj = fqij = fqjj = 0.0; for (ii = 0; ii < inum; ii ++) { i = ilist[ii]; if (mask[i] & groupbit) { itype = map[type[i]]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; iq = q[i]; iparam_i = elem2param[itype][itype][itype]; // charge force from self energy fqi = qfo_self(¶ms[iparam_i],iq,potal); // two-body interactions jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; + j &= NEIGHMASK; jtype = map[type[j]]; jq = q[j]; delr1[0] = x[j][0] - xtmp; delr1[1] = x[j][1] - ytmp; delr1[2] = x[j][2] - ztmp; rsq1 = vec3_dot(delr1,delr1); iparam_ij = elem2param[itype][jtype][jtype]; // long range q-dependent if (rsq1 > params[iparam_ij].lcutsq) continue; inty = intype[itype][jtype]; // polynomial three-point interpolation tri_point(rsq1,mr1,mr2,mr3,sr1,sr2,sr3,itype); // 1/r charge forces qfo_direct(inty,mr1,mr2,mr3,rsq1,sr1,sr2,sr3,fac11e,fqij); fqi += jq * fqij; qf[j] += iq * fqij; // field correction to self energy and charge force qfo_field(¶ms[iparam_ij],rsq1,iq,jq,fqij,fqjj); fqi += fqij; qf[j] += fqjj; // polarization field charge force // three-body interactions if (rsq1 > params[iparam_ij].cutsq) continue; zeta_ij = 0.0; for (kk = 0; kk < jnum; kk++) { if (jj == kk) continue; k = jlist[kk]; + k &= NEIGHMASK; ktype = map[type[k]]; iparam_ijk = elem2param[itype][jtype][ktype]; delr2[0] = x[k][0] - xtmp; delr2[1] = x[k][1] - ytmp; delr2[2] = x[k][2] - ztmp; rsq2 = vec3_dot(delr2,delr2); if (rsq2 > params[iparam_ijk].cutsq) continue; zeta_ij += zeta(¶ms[iparam_ijk],rsq1,rsq2,delr1,delr2); } // charge force in Aij and Bij qfo_short(¶ms[iparam_ij],rsq1,zeta_ij,iq,jq,fqij,fqjj); fqi += fqij; qf[j] += fqjj; } qf[i] += fqi; } } comm->reverse_comm_pair(this); // sum charge force on each node and return it double eneg = 0.0; for (ii = 0; ii < inum; ii++) { i = ilist[ii]; if (mask[i] & groupbit) eneg += qf[i]; } double enegtot; MPI_Allreduce(&eneg,&enegtot,1,MPI_DOUBLE,MPI_SUM,world); return enegtot; } /* ---------------------------------------------------------------------- */ double PairComb::qfo_self(Param *param, double qi, double selfpot) { double self_d,cmin,cmax,qmin,qmax; double s1 = param->chi; double s2 = param->dj; double s3 = param->dk; double s4 = param->dl; double s5 = param->dm; self_d = 0.0; qmin = param->QL1*0.90; qmax = param->QU1*0.90; if (qmax > 4.50 ) qmax = -0.70; cmin = cmax = 1000.0; self_d = s1+qi*(2.0*(s2+selfpot)+qi*(3.0*s3+qi*(4.0*s4+qi*qi*6.0*s5))); if (qi < qmin) { // char str[128]; // sprintf(str,"Pair COMB charge %.10f with force %.10f hit min barrier", // qi,self_d); // error->warning(str,0); self_d += 4.0 * cmin * pow((qi-qmin),3); } if (qi > qmax) { // char str[128]; // sprintf(str,"Pair COMB charge %.10f with force %.10f hit max barrier", // qi,self_d); // error->warning(str,0); self_d += 4.0 * cmax * pow((qi-qmax),3); } return self_d; } /* ---------------------------------------------------------------------- */ void PairComb::qfo_direct(int inty, int mr1, int mr2, int mr3, double rsq, double sr1, double sr2, double sr3, double fac11e, double &fqij) { double r, erfcc, fafbn1, vm, esucon; r = sqrt(rsq); esucon=force->qqr2e; // 1/r force (wrt q) erfcc = sr1*erpaw[mr1][0] + sr2*erpaw[mr2][0] + sr3*erpaw[mr3][0]; fafbn1= sr1*fafb[mr1][inty] + sr2*fafb[mr2][inty] + sr3*fafb[mr3][inty]; vm = (erfcc/r * esucon - fac11e); fqij = 0.5 * (vm+esucon*fafbn1); } /* ---------------------------------------------------------------------- */ void PairComb::qfo_field(Param *param, double rsq,double iq,double jq, double &fqij, double &fqjj) { double r,r5,r6,rc,rc5,rc6; double cmi1,cmi2,cmj1,cmj2,rf5; fqij = fqjj = 0.0; r = sqrt(rsq); r5 = r*r*r*r*r; r6 = r5 * r; rc = param->lcut; rc5 = rc*rc*rc*rc*rc; rc6 = rc5 * rc; cmi1 = param->cmn1; cmi2 = param->cmn2; cmj1 = param->cml1; cmj2 = param->cml2; rf5 = 1.0/r5 - 1.0/rc5 + 5.0*(r-rc)/rc6; // field correction charge force fqij = 0.5 * rf5 * (cmj1 + 2.0 * iq * cmj2); fqjj = 0.5 * rf5 * (cmi1 + 2.0 * jq * cmi2); } /* ---------------------------------------------------------------------- */ void PairComb::qfo_short(Param *param, double rsq, double zeta_ij, double iq, double jq, double &fqij, double &fqjj) { double r,tmp_fc,tmp_fc_d,tmp_exp1,tmp_exp2; double bigA,Asi,Asj,vrcs; double romi = param->addrep,rrcs = param->bigr + param->bigd; double qi,qj,Di,Dj,bigB,Bsi,Bsj; double QUchi,QOchi,QUchj,QOchj,YYDiqp,YYDjqp; double YYAsiqp,YYAsjqp,YYBsiqp,YYBsjqp; double caj,cbj,bij,cfqr,cfqs; double romie = param->romiga; double romib = param->romigb; double ca1,ca2,ca3,ca4; double rslp,rslp2,rslp4,arr1,arr2,fc2j,fc3j,fcp2j,fcp3j; qi = iq; qj = jq; r = sqrt(rsq); Di = Dj = Asi = Asj = bigA = Bsi = Bsj = bigB = 0.0; QUchi = QOchi = QUchj = QOchj = YYDiqp = YYDjqp =0.0; YYAsiqp = YYAsjqp = YYBsiqp = YYBsjqp = 0.0; caj = cbj = vrcs = cfqr = cfqs = 0.0; tmp_fc = comb_fc(r,param); tmp_fc_d = comb_fc_d(r,param); tmp_exp1 = exp(-param->rlm1 * r); tmp_exp2 = exp(-param->rlm2 * r); bij = comb_bij(zeta_ij,param); arr1 = 2.22850; arr2 = 1.89350; fc2j = comb_fc2(r); fc3j = comb_fc3(r); fcp2j = comb_fc2_d(r); fcp3j = comb_fc3_d(r); vrcs = 0.0; if (romi > 0.0) { if (!cor_flag) vrcs = romi * pow((1.0-r/rrcs),2.0); else if (cor_flag) { rslp = ((arr1-r)/(arr1-arr2)); rslp2 = rslp * rslp; rslp4 = rslp2 * rslp2; vrcs = fc2j * fc3j * romi * ((50.0*rslp4-30.0*rslp2+4.50))/8.0; } } Di = param->DU1 + pow(fabs(param->bD1*(param->QU1-qi)),param->nD1); Dj = param->DU2 + pow(fabs(param->bD2*(param->QU2-qj)),param->nD2); Asi = param->biga1 * exp(param->lam11*Di); Asj = param->biga2 * exp(param->lam12*Dj); Bsi = param->bigb1 * exp(param->lam21*Di)* (param->aB1-fabs(pow(param->bB1*(qi-param->Qo1),10))); Bsj = param->bigb2 * exp(param->lam22*Dj)* (param->aB2-fabs(pow(param->bB2*(qj-param->Qo2),10))); QUchi = (param->QU1-qi)*param->bD1; QUchj = (param->QU2-qj)*param->bD2; QOchi = (qi-param->Qo1)*param->bB1; QOchj = (qj-param->Qo2)*param->bB2; if (QUchi == 0.0) YYDiqp = 0.0; else YYDiqp = -param->nD1 * QUchi * param->bD1 * pow(fabs(QUchi),(param->nD1-2.0)); if (QUchj == 0.0) YYDjqp = 0.0; else YYDjqp = -param->nD2 * QUchj * param->bD2 * pow(fabs(QUchj),(param->nD2-2.0)); YYAsiqp = Asi * param->lam11 * YYDiqp; YYAsjqp = Asj * param->lam12 * YYDjqp; if (QOchi == 0.0) YYBsiqp=Bsi*param->lam21*YYDiqp; else YYBsiqp=Bsi*param->lam21*YYDiqp-param->bigb1*exp(param->lam21*Di)* 10.0*QOchi*param->bB1*pow(fabs(QOchi),(10.0-2.0)); if (QOchj == 0.0) YYBsjqp=Bsj*param->lam22*YYDjqp; else YYBsjqp=Bsj*param->lam22*YYDjqp-param->bigb2*exp(param->lam22*Dj)* 10.0*QOchj*param->bB2*pow(fabs(QOchj),(10.0-2.0)); if (Asi > 0.0 && Asj > 0.0) caj = 1.0/(2.0*sqrt(Asi*Asj)) * romie; else caj == 0.0; if (Bsi > 0.0 && Bsj > 0.0) cbj = 1.0/(2.0*sqrt(Bsi*Bsj)) * romib ; else cbj == 0.0; cfqr = 0.50 * tmp_fc * (1.0 + vrcs); // 0.5 b/c full atom loop cfqs = -0.50 * tmp_fc * bij; ca1 = Asj * caj * YYAsiqp; ca2 = Bsj * cbj * YYBsiqp; ca3 = Asi * caj * YYAsjqp; ca4 = Bsi * cbj * YYBsjqp; fqij = cfqr * tmp_exp1 * ca1; fqij += cfqs * tmp_exp2 * ca2; fqjj = cfqr * tmp_exp1 * ca3; fqjj += cfqs * tmp_exp2 * ca4; } /* ---------------------------------------------------------------------- */ void PairComb::Over_cor(Param *param, double rsq1, int NCoi, double &Eov, double &Fov) { double ECo,BCo,tmp_fc,tmp_fc_d; double r = sqrt(rsq1); int NCon = NCoi - 7; tmp_fc = comb_fc(r,param); tmp_fc_d = comb_fc(r,param); Eov = 0.0; Fov = 0.0; ECo = param->hfocor; BCo = 0.1; if (NCon >= 0.20) { Eov = tmp_fc * ECo * NCon/(1.0+exp(BCo*NCon)); Fov = -(tmp_fc_d*Eov + tmp_fc*ECo/(1.0+exp(BCo*NCon)) - (tmp_fc*ECo*NCon*BCo*exp(BCo*NCon)) / ((1.0+exp(BCo*NCon))*(1.0+exp(BCo*NCon)))); Fov /= r; } } /* ---------------------------------------------------------------------- */ int PairComb::pack_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++] = qf[j]; } return 1; } /* ---------------------------------------------------------------------- */ void PairComb::unpack_comm(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n ; for (i = first; i < last; i++) qf[i] = buf[m++]; } /* ---------------------------------------------------------------------- */ int PairComb::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++] = qf[i]; return 1; } /* ---------------------------------------------------------------------- */ void PairComb::unpack_reverse_comm(int n, int *list, double *buf) { int i,j,m; m = 0; for (i = 0; i < n; i++) { j = list[i]; qf[j] += buf[m++]; } } /* ---------------------------------------------------------------------- memory usage of local atom-based arrays ------------------------------------------------------------------------- */ double PairComb::memory_usage() { double bytes = maxeatom * sizeof(double); bytes += maxvatom*6 * sizeof(double); bytes += nmax * sizeof(int); return bytes; } diff --git a/src/MANYBODY/pair_eam.cpp b/src/MANYBODY/pair_eam.cpp index 1da055a96..b89a397bf 100644 --- a/src/MANYBODY/pair_eam.cpp +++ b/src/MANYBODY/pair_eam.cpp @@ -1,874 +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 authors: Stephen Foiles (SNL), Murray Daw (SNL) ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #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 MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define MAXLINE 1024 /* ---------------------------------------------------------------------- */ PairEAM::PairEAM(LAMMPS *lmp) : Pair(lmp) { nmax = 0; rho = NULL; fp = NULL; nfuncfl = 0; funcfl = NULL; setfl = NULL; fs = NULL; frho = NULL; rhor = NULL; z2r = 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() { memory->destroy(rho); memory->destroy(fp); if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); delete [] map; delete [] type2frho; memory->destroy(type2rhor); memory->destroy(type2z2r); } 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); } 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; } 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; } 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 newton_pair = force->newton_pair; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // 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; 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 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 (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 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 = -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 = phi; if (evflag) ev_tally(i,j,nlocal,newton_pair, evdwl,0.0,fpair,delx,dely,delz); } } } if (vflag_fdotr) virial_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"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairEAM::settings(int narg, char **arg) { if (narg > 0) error->all("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("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); // 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++; } } } if (count == 0) error->all("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(); int irequest = neighbor->request(this); } /* ---------------------------------------------------------------------- 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 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 = fopen(filename,"r"); if (fptr == NULL) { char str[128]; sprintf(str,"Cannot open EAM potential file %s",filename); error->one(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,rhomax; 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_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 1; } /* ---------------------------------------------------------------------- */ void PairEAM::unpack_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 1; } /* ---------------------------------------------------------------------- */ 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; } diff --git a/src/MANYBODY/pair_eim.cpp b/src/MANYBODY/pair_eim.cpp index cc7b702da..3a99d59a8 100644 --- a/src/MANYBODY/pair_eim.cpp +++ b/src/MANYBODY/pair_eim.cpp @@ -1,1168 +1,1171 @@ /* ---------------------------------------------------------------------- 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: Xiaowang Zhou (SNL) ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "pair_eim.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 MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define MAXLINE 1024 /* ---------------------------------------------------------------------- */ PairEIM::PairEIM(LAMMPS *lmp) : Pair(lmp) { single_enable = 0; one_coeff = 1; setfl = NULL; nmax = 0; rho = NULL; fp = NULL; nelements = 0; elements = NULL; negativity = NULL; q0 = NULL; cutforcesq = NULL; Fij = NULL; Gij = NULL; phiij = NULL; Fij_spline = NULL; Gij_spline = NULL; phiij_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 ------------------------------------------------------------------------- */ PairEIM::~PairEIM() { memory->destroy(rho); memory->destroy(fp); if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); delete [] map; memory->destroy(type2Fij); memory->destroy(type2Gij); memory->destroy(type2phiij); } for (int i = 0; i < nelements; i++) delete [] elements[i]; delete [] elements; deallocate_setfl(); delete [] negativity; delete [] q0; memory->destroy(cutforcesq); memory->destroy(Fij); memory->destroy(Gij); memory->destroy(phiij); memory->destroy(Fij_spline); memory->destroy(Gij_spline); memory->destroy(phiij_spline); } /* ---------------------------------------------------------------------- */ void PairEIM::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,phip,phi,coul,coulp,recip,psip; 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 array if necessary 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 newton_pair = force->newton_pair; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // zero out density if (newton_pair) { m = nlocal + atom->nghost; for (i = 0; i < m; i++) { rho[i] = 0.0; fp[i] = 0.0; } } else { for (i = 0; i < nlocal; i++) { rho[i] = 0.0; fp[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 < cutforcesq[itype][jtype]) { p = sqrt(rsq)*rdr + 1.0; m = static_cast (p); m = MIN(m,nr-1); p -= m; p = MIN(p,1.0); coeff = Fij_spline[type2Fij[itype][jtype]][m]; rho[i] += ((coeff[3]*p + coeff[4])*p + coeff[5])*p + coeff[6]; if (newton_pair || j < nlocal) { coeff = Fij_spline[type2Fij[jtype][itype]][m]; rho[j] += ((coeff[3]*p + coeff[4])*p + coeff[5])*p + coeff[6]; } } } } // communicate and sum densities rhofp = 1; if (newton_pair) comm->reverse_comm_pair(this); comm->forward_comm_pair(this); 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 < cutforcesq[itype][jtype]) { p = sqrt(rsq)*rdr + 1.0; m = static_cast (p); m = MIN(m,nr-1); p -= m; p = MIN(p,1.0); coeff = Gij_spline[type2Gij[itype][jtype]][m]; fp[i] += rho[j]*(((coeff[3]*p + coeff[4])*p + coeff[5])*p + coeff[6]); if (newton_pair || j < nlocal) { fp[j] += rho[i]*(((coeff[3]*p + coeff[4])*p + coeff[5])*p + coeff[6]); } } } } // communicate and sum modified densities rhofp = 2; if (newton_pair) comm->reverse_comm_pair(this); comm->forward_comm_pair(this); for (ii = 0; ii < inum; ii++) { i = ilist[ii]; itype = type[i]; if (eflag) { phi = 0.5*rho[i]*fp[i]; if (eflag_global) eng_vdwl += phi; if (eflag_atom) eatom[i] += phi; } } // 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; 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 < cutforcesq[itype][jtype]) { 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' coeff = Fij_spline[type2Fij[jtype][itype]][m]; rhoip = (coeff[0]*p + coeff[1])*p + coeff[2]; coeff = Fij_spline[type2Fij[itype][jtype]][m]; rhojp = (coeff[0]*p + coeff[1])*p + coeff[2]; coeff = phiij_spline[type2phiij[itype][jtype]][m]; phip = (coeff[0]*p + coeff[1])*p + coeff[2]; phi = ((coeff[3]*p + coeff[4])*p + coeff[5])*p + coeff[6]; coeff = Gij_spline[type2Gij[itype][jtype]][m]; coul = ((coeff[3]*p + coeff[4])*p + coeff[5])*p + coeff[6]; coulp = (coeff[0]*p + coeff[1])*p + coeff[2]; psip = phip + (rho[i]*rho[j]-q0[itype]*q0[jtype])*coulp + fp[i]*rhojp + fp[j]*rhoip; recip = 1.0/r; fpair = -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 = phi-q0[itype]*q0[jtype]*coul; if (evflag) ev_tally(i,j,nlocal,newton_pair, evdwl,0.0,fpair,delx,dely,delz); } } } if (vflag_fdotr) virial_compute(); } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairEIM::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; memory->create(type2Fij,n+1,n+1,"pair:type2Fij"); memory->create(type2Gij,n+1,n+1,"pair:type2Gij"); memory->create(type2phiij,n+1,n+1,"pair:type2phiij"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairEIM::settings(int narg, char **arg) { if (narg > 0) error->all("Illegal pair_style command"); } /* ---------------------------------------------------------------------- set coeffs from set file ------------------------------------------------------------------------- */ void PairEIM::coeff(int narg, char **arg) { int i,j,m,n; if (!allocated) allocate(); if (narg < 5) error->all("Incorrect args for pair coefficients"); // insure I,J args are * * if (strcmp(arg[0],"*") != 0 || strcmp(arg[1],"*") != 0) error->all("Incorrect args for pair coefficients"); // read EIM element names before filename // nelements = # of EIM elements to read from file // elements = list of unique element names if (nelements) { for (i = 0; i < nelements; i++) delete [] elements[i]; delete [] elements; } nelements = narg - 3 - atom->ntypes; if (nelements < 1) error->all("Incorrect args for pair coefficients"); elements = new char*[nelements]; for (i = 0; i < nelements; i++) { n = strlen(arg[i+2]) + 1; elements[i] = new char[n]; strcpy(elements[i],arg[i+2]); } // read EIM file deallocate_setfl(); setfl = new Setfl(); read_file(arg[2+nelements]); // read args that map atom types to elements in potential file // map[i] = which element the Ith atom type is, -1 if NULL for (i = 3 + nelements; i < narg; i++) { m = i - (3+nelements) + 1; for (j = 0; j < nelements; j++) if (strcmp(arg[i],elements[j]) == 0) break; if (j < nelements) map[m] = j; else if (strcmp(arg[i],"NULL") == 0) map[m] = -1; else error->all("Incorrect args for pair coefficients"); } // clear setflag since coeff() called once with I,J = * * n = atom->ntypes; for (i = 1; i <= n; i++) for (j = i; j <= n; j++) setflag[i][j] = 0; // set setflag i,j for type pairs where both are mapped to elements // set mass of atom type if i = j int count = 0; for (i = 1; i <= n; i++) for (j = i; j <= n; j++) if (map[i] >= 0 && map[j] >= 0) { setflag[i][j] = 1; if (i == j) atom->set_mass(i,setfl->mass[map[i]]); count++; } if (count == 0) error->all("Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairEIM::init_style() { // convert read-in file(s) to arrays and spline them file2array(); array2spline(); int irequest = neighbor->request(this); } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairEIM::init_one(int i, int j) { cutmax = sqrt(cutforcesq[i][j]); return cutmax; } /* ---------------------------------------------------------------------- read potential values from a set file ------------------------------------------------------------------------- */ void PairEIM::read_file(char *filename) { // open potential file int me = comm->me; FILE *fptr; if (me == 0) { fptr = fopen(filename,"r"); if (fptr == NULL) { char str[128]; sprintf(str,"Cannot open EIM potential file %s",filename); error->one(str); } } int npair = nelements*(nelements+1)/2; setfl->ielement = new int[nelements]; setfl->mass = new double[nelements]; setfl->negativity = new double[nelements]; setfl->ra = new double[nelements]; setfl->ri = new double[nelements]; setfl->Ec = new double[nelements]; setfl->q0 = new double[nelements]; setfl->rcutphiA = new double[npair]; setfl->rcutphiR = new double[npair]; setfl->Eb = new double[npair]; setfl->r0 = new double[npair]; setfl->alpha = new double[npair]; setfl->beta = new double[npair]; setfl->rcutq = new double[npair]; setfl->Asigma = new double[npair]; setfl->rq = new double[npair]; setfl->rcutsigma = new double[npair]; setfl->Ac = new double[npair]; setfl->zeta = new double[npair]; setfl->rs = new double[npair]; setfl->tp = new int[npair]; if (me == 0) if (!grabglobal(fptr)) error->one("Could not grab global entry from EIM potential file"); MPI_Bcast(&setfl->division,1,MPI_DOUBLE,0,world); MPI_Bcast(&setfl->rbig,1,MPI_DOUBLE,0,world); MPI_Bcast(&setfl->rsmall,1,MPI_DOUBLE,0,world); for (int i = 0; i < nelements; i++) { if (me == 0) if (!grabsingle(fptr,i)) error->one("Could not grab element entry from EIM potential file"); MPI_Bcast(&setfl->ielement[i],1,MPI_INT,0,world); MPI_Bcast(&setfl->mass[i],1,MPI_DOUBLE,0,world); MPI_Bcast(&setfl->negativity[i],1,MPI_DOUBLE,0,world); MPI_Bcast(&setfl->ra[i],1,MPI_DOUBLE,0,world); MPI_Bcast(&setfl->ri[i],1,MPI_DOUBLE,0,world); MPI_Bcast(&setfl->Ec[i],1,MPI_DOUBLE,0,world); MPI_Bcast(&setfl->q0[i],1,MPI_DOUBLE,0,world); } for (int i = 0; i < nelements; i++) { for (int j = i; j < nelements; j++) { int ij; if (i == j) ij = i; else if (i < j) ij = nelements*(i+1) - (i+1)*(i+2)/2 + j; else ij = nelements*(j+1) - (j+1)*(j+2)/2 + i; if (me == 0) if (grabpair(fptr,i,j) == 0) error->one("Could not grab pair entry from EIM potential file"); MPI_Bcast(&setfl->rcutphiA[ij],1,MPI_DOUBLE,0,world); MPI_Bcast(&setfl->rcutphiR[ij],1,MPI_DOUBLE,0,world); MPI_Bcast(&setfl->Eb[ij],1,MPI_DOUBLE,0,world); MPI_Bcast(&setfl->r0[ij],1,MPI_DOUBLE,0,world); MPI_Bcast(&setfl->alpha[ij],1,MPI_DOUBLE,0,world); MPI_Bcast(&setfl->beta[ij],1,MPI_DOUBLE,0,world); MPI_Bcast(&setfl->rcutq[ij],1,MPI_DOUBLE,0,world); MPI_Bcast(&setfl->Asigma[ij],1,MPI_DOUBLE,0,world); MPI_Bcast(&setfl->rq[ij],1,MPI_DOUBLE,0,world); MPI_Bcast(&setfl->rcutsigma[ij],1,MPI_DOUBLE,0,world); MPI_Bcast(&setfl->Ac[ij],1,MPI_DOUBLE,0,world); MPI_Bcast(&setfl->zeta[ij],1,MPI_DOUBLE,0,world); MPI_Bcast(&setfl->rs[ij],1,MPI_DOUBLE,0,world); MPI_Bcast(&setfl->tp[ij],1,MPI_INT,0,world); } } setfl->nr = 5000; setfl->cut = 0.0; for (int i = 0; i < npair; i++) { if (setfl->cut < setfl->rcutphiA[i]) setfl->cut = setfl->rcutphiA[i]; if (setfl->cut < setfl->rcutphiR[i]) setfl->cut = setfl->rcutphiR[i]; if (setfl->cut < setfl->rcutq[i]) setfl->cut = setfl->rcutq[i]; if (setfl->cut < setfl->rcutsigma[i]) setfl->cut = setfl->rcutsigma[i]; } setfl->dr = setfl->cut/(setfl->nr-1.0); memory->create(setfl->cuts,nelements,nelements,"pair:cuts"); for (int i = 0; i < nelements; i++) { for (int j = 0; j < nelements; j++) { if (i > j) { setfl->cuts[i][j] = setfl->cuts[j][i]; } else { int ij; if (i == j) { ij = i; } else { ij = nelements*(i+1) - (i+1)*(i+2)/2 + j; } setfl->cuts[i][j] = setfl->rcutphiA[ij]; if (setfl->cuts[i][j] < setfl->rcutphiR[ij]) setfl->cuts[i][j] = setfl->rcutphiR[ij]; if (setfl->cuts[i][j] < setfl->rcutq[ij]) setfl->cuts[i][j] = setfl->rcutq[ij]; if (setfl->cuts[i][j] < setfl->rcutsigma[ij]) setfl->cuts[i][j] = setfl->rcutsigma[ij]; } } } memory->create(setfl->Fij,nelements,nelements,setfl->nr+1,"pair:Fij"); memory->create(setfl->Gij,nelements,nelements,setfl->nr+1,"pair:Gij"); memory->create(setfl->phiij,nelements,nelements,setfl->nr+1,"pair:phiij"); for (int i = 0; i < nelements; i++) for (int j = 0; j < nelements; j++) { for (int k = 0; k < setfl->nr; k++) { if (i > j) { setfl->phiij[i][j][k+1] = setfl->phiij[j][i][k+1]; } else { double r = k*setfl->dr; setfl->phiij[i][j][k+1] = funcphi(i,j,r); } } } for (int i = 0; i < nelements; i++) for (int j = 0; j < nelements; j++) { for (int k = 0; k < setfl->nr; k++) { double r = k*setfl->dr; setfl->Fij[i][j][k+1] = funcsigma(i,j,r); } } for (int i = 0; i < nelements; i++) for (int j = 0; j < nelements; j++) { for (int k = 0; k < setfl->nr; k++) { if (i > j) { setfl->Gij[i][j][k+1] = setfl->Gij[j][i][k+1]; } else { double r = k*setfl->dr; setfl->Gij[i][j][k+1] = funccoul(i,j,r); } } } // close the potential file if (me == 0) fclose(fptr); } /* ---------------------------------------------------------------------- deallocate data associated with setfl file ------------------------------------------------------------------------- */ void PairEIM::deallocate_setfl() { if (!setfl) return; delete [] setfl->ielement; delete [] setfl->mass; delete [] setfl->negativity; delete [] setfl->ra; delete [] setfl->ri; delete [] setfl->Ec; delete [] setfl->q0; delete [] setfl->rcutphiA; delete [] setfl->rcutphiR; delete [] setfl->Eb; delete [] setfl->r0; delete [] setfl->alpha; delete [] setfl->beta; delete [] setfl->rcutq; delete [] setfl->Asigma; delete [] setfl->rq; delete [] setfl->rcutsigma; delete [] setfl->Ac; delete [] setfl->zeta; delete [] setfl->rs; delete [] setfl->tp; memory->destroy(setfl->cuts); memory->destroy(setfl->Fij); memory->destroy(setfl->Gij); memory->destroy(setfl->phiij); delete setfl; } /* ---------------------------------------------------------------------- convert read-in potentials to standard array format interpolate all file values to a single grid and cutoff ------------------------------------------------------------------------- */ void PairEIM::file2array() { int i,j,m,n; int irow,icol; int ntypes = atom->ntypes; delete [] negativity; delete [] q0; delete [] cutforcesq; negativity = new double[ntypes+1]; q0 = new double[ntypes+1]; memory->create(cutforcesq,ntypes+1,ntypes+1,"pair:cutforcesq"); for (i = 1; i <= ntypes; i++) { if (map[i] == -1) { negativity[i]=0.0; q0[i]=0.0; } else { negativity[i]=setfl->negativity[map[i]]; q0[i]=setfl->q0[map[i]]; } } for (i = 1; i <= ntypes; i++) for (j = 1; j <= ntypes; j++) { if (map[i] == -1 || map[j] == -1) { cutforcesq[i][j] = setfl->cut; cutforcesq[i][j] = cutforcesq[i][j]*cutforcesq[i][j]; } else { cutforcesq[i][j] = setfl->cuts[map[i]][map[j]]; cutforcesq[i][j] = cutforcesq[i][j]*cutforcesq[i][j]; } } nr = setfl->nr; dr = setfl->dr; // ------------------------------------------------------------------ // setup Fij arrays // ------------------------------------------------------------------ nFij = nelements*nelements + 1; memory->destroy(Fij); memory->create(Fij,nFij,nr+1,"pair:Fij"); // copy each element's Fij to global Fij n=0; for (i = 0; i < nelements; i++) for (j = 0; j < nelements; j++) { for (m = 1; m <= nr; m++) Fij[n][m] = setfl->Fij[i][j][m]; n++; } // add extra Fij of zeroes for non-EIM types to point to (pair hybrid) for (m = 1; m <= nr; m++) Fij[nFij-1][m] = 0.0; // type2Fij[i][j] = which Fij array (0 to nFij-1) each type pair maps to // setfl of Fij arrays // value = n = sum over rows of matrix until reach irow,icol // if atom type doesn't point to element (non-EIM atom in pair hybrid) // then map it to last Fij array of zeroes for (i = 1; i <= ntypes; i++) { for (j = 1; j <= ntypes; j++) { irow = map[i]; icol = map[j]; if (irow == -1 || icol == -1) { type2Fij[i][j] = nFij-1; } else { n = 0; for (m = 0; m < irow; m++) n += nelements; n += icol; type2Fij[i][j] = n; } } } // ------------------------------------------------------------------ // setup Gij arrays // ------------------------------------------------------------------ nGij = nelements * (nelements+1) / 2 + 1; memory->destroy(Gij); memory->create(Gij,nGij,nr+1,"pair:Gij"); // copy each element's Gij to global Gij, only for I >= J n=0; for (i = 0; i < nelements; i++) for (j = 0; j <= i; j++) { for (m = 1; m <= nr; m++) Gij[n][m] = setfl->Gij[i][j][m]; n++; } // add extra Gij of zeroes for non-EIM types to point to (pair hybrid) for (m = 1; m <= nr; m++) Gij[nGij-1][m] = 0.0; // type2Gij[i][j] = which Gij array (0 to nGij-1) each type pair maps to // setfl of Gij 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 atom type doesn't point to element (non-EIM atom in pair hybrid) // then map it to last Gij array of zeroes for (i = 1; i <= ntypes; i++) { for (j = 1; j <= ntypes; j++) { irow = map[i]; icol = map[j]; if (irow == -1 || icol == -1) { type2Gij[i][j] = nGij-1; } else { if (irow < icol) { irow = map[j]; icol = map[i]; } n = 0; for (m = 0; m < irow; m++) n += m + 1; n += icol; type2Gij[i][j] = n; } } } // ------------------------------------------------------------------ // setup phiij arrays // ------------------------------------------------------------------ nphiij = nelements * (nelements+1) / 2 + 1; memory->destroy(phiij); memory->create(phiij,nphiij,nr+1,"pair:phiij"); // copy each element pair phiij to global phiij, only for I >= J n = 0; for (i = 0; i < nelements; i++) for (j = 0; j <= i; j++) { for (m = 1; m <= nr; m++) phiij[n][m] = setfl->phiij[i][j][m]; n++; } // add extra phiij of zeroes for non-EIM types to point to (pair hybrid) for (m = 1; m <= nr; m++) phiij[nphiij-1][m] = 0.0; // type2phiij[i][j] = which phiij array (0 to nphiij-1) // each type pair maps to // setfl of phiij 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 atom type doesn't point to element (non-EIM atom in pair hybrid) // then map it to last phiij array of zeroes for (i = 1; i <= ntypes; i++) { for (j = 1; j <= ntypes; j++) { irow = map[i]; icol = map[j]; if (irow == -1 || icol == -1) { type2phiij[i][j] = nphiij-1; } else { if (irow < icol) { irow = map[j]; icol = map[i]; } n = 0; for (m = 0; m < irow; m++) n += m + 1; n += icol; type2phiij[i][j] = n; } } } } /* ---------------------------------------------------------------------- */ void PairEIM::array2spline() { rdr = 1.0/dr; memory->destroy(Fij_spline); memory->destroy(Gij_spline); memory->destroy(phiij_spline); memory->create(Fij_spline,nFij,nr+1,7,"pair:Fij"); memory->create(Gij_spline,nGij,nr+1,7,"pair:Gij"); memory->create(phiij_spline,nphiij,nr+1,7,"pair:phiij"); for (int i = 0; i < nFij; i++) interpolate(nr,dr,Fij[i],Fij_spline[i],0.0); for (int i = 0; i < nGij; i++) interpolate(nr,dr,Gij[i],Gij_spline[i],0.0); for (int i = 0; i < nphiij; i++) interpolate(nr,dr,phiij[i],phiij_spline[i],0.0); } /* ---------------------------------------------------------------------- */ void PairEIM::interpolate(int n, double delta, double *f, double **spline, double origin) { 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] = 0.0; 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 global line from file and store info in setfl return 0 if error ------------------------------------------------------------------------- */ int PairEIM::grabglobal(FILE *fptr) { char line[MAXLINE]; char *pch = NULL, *data = NULL; while (pch == NULL) { if (fgets(line,MAXLINE,fptr) == NULL) break; pch = strstr(line,"global"); if (pch != NULL) { data = strtok (line," \t\n\r\f"); data = strtok (NULL,"?"); sscanf(data,"%lg %lg %lg",&setfl->division,&setfl->rbig,&setfl->rsmall); } } if (pch == NULL) return 0; return 1; } /* ---------------------------------------------------------------------- grab elemental line from file and store info in setfl return 0 if error ------------------------------------------------------------------------- */ int PairEIM::grabsingle(FILE *fptr, int i) { char line[MAXLINE]; rewind(fptr); char *pch1 = NULL, *pch2 = NULL, *data = NULL; while (pch1 == NULL || pch2 == NULL) { if (fgets(line,MAXLINE,fptr) == NULL) break; pch1 = strtok (line," \t\n\r\f"); pch1 = strstr(pch1,"element:"); if (pch1 != NULL) { pch2 = strtok(NULL, " \t\n\r\f"); if (pch2 != NULL) data = strtok (NULL, "?"); if (strcmp(pch2,elements[i]) == 0) { sscanf(data,"%d %lg %lg %lg %lg %lg %lg",&setfl->ielement[i], &setfl->mass[i],&setfl->negativity[i],&setfl->ra[i], &setfl->ri[i],&setfl->Ec[i],&setfl->q0[i]); } else { pch2 = NULL; } } } if (pch1 == NULL || pch2 == NULL) return 0; return 1; } /* ---------------------------------------------------------------------- grab pair line from file and store info in setfl return 0 if error ------------------------------------------------------------------------- */ int PairEIM::grabpair(FILE *fptr, int i, int j) { char line[MAXLINE]; rewind(fptr); int ij; if (i == j) ij = i; else if (i < j) ij = nelements*(i+1) - (i+1)*(i+2)/2 + j; else ij = nelements*(j+1) - (j+1)*(j+2)/2 + i; char *pch1 = NULL, *pch2 = NULL, *pch3 = NULL, *data = NULL; while (pch1 == NULL || pch2 == NULL || pch3 == NULL) { if (fgets(line,MAXLINE,fptr) == NULL) break; pch1 = strtok (line," \t\n\r\f"); pch1 = strstr(pch1,"pair:"); if (pch1 != NULL) { pch2 = strtok (NULL, " \t\n\r\f"); if (pch2 != NULL) pch3 = strtok (NULL, " \t\n\r\f"); if (pch3 != NULL) data = strtok (NULL, "?"); if ((strcmp(pch2,elements[i]) == 0 && strcmp(pch3,elements[j]) == 0) || (strcmp(pch2,elements[j]) == 0 && strcmp(pch3,elements[i]) == 0)) { sscanf(data,"%lg %lg %lg %lg %lg", &setfl->rcutphiA[ij],&setfl->rcutphiR[ij], &setfl->Eb[ij],&setfl->r0[ij],&setfl->alpha[ij]); fgets(line,MAXLINE,fptr); sscanf(line,"%lg %lg %lg %lg %lg", &setfl->beta[ij],&setfl->rcutq[ij],&setfl->Asigma[ij], &setfl->rq[ij],&setfl->rcutsigma[ij]); fgets(line,MAXLINE,fptr); sscanf(line,"%lg %lg %lg %d", &setfl->Ac[ij],&setfl->zeta[ij],&setfl->rs[ij], &setfl->tp[ij]); } else { pch1 = NULL; pch2 = NULL; pch3 = NULL; } } } if (pch1 == NULL || pch2 == NULL || pch3 == NULL) return 0; return 1; } /* ---------------------------------------------------------------------- cutoff function ------------------------------------------------------------------------- */ double PairEIM::funccutoff(double rp, double rc, double r) { double rbig = setfl->rbig; double rsmall = setfl->rsmall; double a = (rsmall-rbig)/(rc-rp)*(r-rp)+rbig; a = erfc(a); double b = erfc(rbig); double c = erfc(rsmall); return (a-c)/(b-c); } /* ---------------------------------------------------------------------- pair interaction function phi ------------------------------------------------------------------------- */ double PairEIM::funcphi(int i, int j, double r) { int ij; double value = 0.0; if (i == j) ij = i; else if (i < j) ij = nelements*(i+1) - (i+1)*(i+2)/2 + j; else ij = nelements*(j+1) - (j+1)*(j+2)/2 + i; if (r < 0.2) r = 0.2; if (setfl->tp[ij] == 1) { double a = setfl->Eb[ij]*setfl->alpha[ij] / (setfl->beta[ij]-setfl->alpha[ij]); double b = setfl->Eb[ij]*setfl->beta[ij] / (setfl->beta[ij]-setfl->alpha[ij]); if (r < setfl->rcutphiA[ij]) { value -= a*exp(-setfl->beta[ij]*(r/setfl->r0[ij]-1.0))* funccutoff(setfl->r0[ij],setfl->rcutphiA[ij],r); } if (r < setfl-> rcutphiR[ij]) { value += b*exp(-setfl->alpha[ij]*(r/setfl->r0[ij]-1.0))* funccutoff(setfl->r0[ij],setfl->rcutphiR[ij],r); } } else if (setfl->tp[ij] == 2) { double a=setfl->Eb[ij]*setfl->alpha[ij]*pow(setfl->r0[ij],setfl->beta[ij])/ (setfl->beta[ij]-setfl->alpha[ij]); double b=a*setfl->beta[ij]/setfl->alpha[ij]* pow(setfl->r0[ij],setfl->alpha[ij]-setfl->beta[ij]); if (r < setfl->rcutphiA[ij]) { value -= a/pow(r,setfl->beta[ij])* funccutoff(setfl->r0[ij],setfl->rcutphiA[ij],r); } if (r < setfl-> rcutphiR[ij]) { value += b/pow(r,setfl->alpha[ij])* funccutoff(setfl->r0[ij],setfl->rcutphiR[ij],r); } } return value; } /* ---------------------------------------------------------------------- ion propensity function sigma ------------------------------------------------------------------------- */ double PairEIM::funcsigma(int i, int j, double r) { int ij; double value = 0.0; if (i == j) ij = i; else if (i < j) ij = nelements*(i+1) - (i+1)*(i+2)/2 + j; else ij = nelements*(j+1) - (j+1)*(j+2)/2 + i; if (r < 0.2) r = 0.2; if (r < setfl->rcutq[ij]) { value = setfl->Asigma[ij]*(setfl->negativity[j]-setfl->negativity[i]) * funccutoff(setfl->rq[ij],setfl->rcutq[ij],r); } return value; } /* ---------------------------------------------------------------------- charge-charge interaction function sigma ------------------------------------------------------------------------- */ double PairEIM::funccoul(int i, int j, double r) { int ij; double value = 0.0; if (i == j) ij = i; else if (i < j) ij = nelements*(i+1) - (i+1)*(i+2)/2 + j; else ij = nelements*(j+1) - (j+1)*(j+2)/2 + i; if (r < 0.2) r = 0.2; if (r < setfl->rcutsigma[ij]) { value = setfl->Ac[ij]*exp(-setfl->zeta[ij]*r)* funccutoff(setfl->rs[ij],setfl->rcutsigma[ij],r); } return value; } /* ---------------------------------------------------------------------- */ int PairEIM::pack_comm(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; m = 0; if (rhofp == 1) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = rho[j]; } } if (rhofp == 2) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = fp[j]; } } return 1; } /* ---------------------------------------------------------------------- */ void PairEIM::unpack_comm(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; if (rhofp == 1) { for (i = first; i < last; i++) rho[i] = buf[m++]; } if (rhofp == 2) { for (i = first; i < last; i++) fp[i] = buf[m++]; } } /* ---------------------------------------------------------------------- */ int PairEIM::pack_reverse_comm(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; if (rhofp == 1) { for (i = first; i < last; i++) buf[m++] = rho[i]; } if (rhofp == 2) { for (i = first; i < last; i++) buf[m++] = fp[i]; } return 1; } /* ---------------------------------------------------------------------- */ void PairEIM::unpack_reverse_comm(int n, int *list, double *buf) { int i,j,m; m = 0; if (rhofp == 1) { for (i = 0; i < n; i++) { j = list[i]; rho[j] += buf[m++]; } } if (rhofp == 2) { for (i = 0; i < n; i++) { j = list[i]; fp[j] += buf[m++]; } } } /* ---------------------------------------------------------------------- memory usage of local atom-based arrays ------------------------------------------------------------------------- */ double PairEIM::memory_usage() { double bytes = maxeatom * sizeof(double); bytes += maxvatom*6 * sizeof(double); bytes += 2 * nmax * sizeof(double); return bytes; } diff --git a/src/MANYBODY/pair_sw.cpp b/src/MANYBODY/pair_sw.cpp index ed062a5c7..555a7622a 100755 --- a/src/MANYBODY/pair_sw.cpp +++ b/src/MANYBODY/pair_sw.cpp @@ -1,599 +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. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author: Aidan Thompson (SNL) ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "pair_sw.h" #include "atom.h" #include "neighbor.h" #include "neigh_request.h" #include "force.h" #include "comm.h" #include "memory.h" #include "neighbor.h" #include "neigh_list.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define MAXLINE 1024 #define DELTA 4 /* ---------------------------------------------------------------------- */ PairSW::PairSW(LAMMPS *lmp) : Pair(lmp) { single_enable = 0; one_coeff = 1; nelements = 0; elements = NULL; nparams = maxparam = 0; params = NULL; elem2param = NULL; } /* ---------------------------------------------------------------------- check if allocated, since class can be destructed when incomplete ------------------------------------------------------------------------- */ PairSW::~PairSW() { if (elements) for (int i = 0; i < nelements; i++) delete [] elements[i]; delete [] elements; memory->destroy(params); memory->destroy(elem2param); if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); delete [] map; } } /* ---------------------------------------------------------------------- */ void PairSW::compute(int eflag, int vflag) { int i,j,k,ii,jj,kk,inum,jnum,jnumm1,itag,jtag; int itype,jtype,ktype,ijparam,ikparam,ijkparam; double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair; double rsq,rsq1,rsq2; double delr1[3],delr2[3],fj[3],fk[3]; 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 *tag = atom->tag; 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 full neighbor list of my atoms for (ii = 0; ii < inum; ii++) { i = ilist[ii]; itag = tag[i]; itype = map[type[i]]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; // two-body interactions, skip half of them jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; + j &= NEIGHMASK; jtag = tag[j]; if (itag > jtag) { if ((itag+jtag) % 2 == 0) continue; } else if (itag < jtag) { if ((itag+jtag) % 2 == 1) continue; } else { if (x[j][2] < ztmp) continue; if (x[j][2] == ztmp && x[j][1] < ytmp) continue; if (x[j][2] == ztmp && x[j][1] == ytmp && x[j][0] < xtmp) continue; } jtype = map[type[j]]; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; ijparam = elem2param[itype][jtype][jtype]; if (rsq > params[ijparam].cutsq) continue; twobody(¶ms[ijparam],rsq,fpair,eflag,evdwl); f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; 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); } jnumm1 = jnum - 1; for (jj = 0; jj < jnumm1; jj++) { j = jlist[jj]; + j &= NEIGHMASK; jtype = map[type[j]]; ijparam = elem2param[itype][jtype][jtype]; delr1[0] = x[j][0] - xtmp; delr1[1] = x[j][1] - ytmp; delr1[2] = x[j][2] - ztmp; rsq1 = delr1[0]*delr1[0] + delr1[1]*delr1[1] + delr1[2]*delr1[2]; if (rsq1 > params[ijparam].cutsq) continue; for (kk = jj+1; kk < jnum; kk++) { k = jlist[kk]; + k &= NEIGHMASK; ktype = map[type[k]]; ikparam = elem2param[itype][ktype][ktype]; ijkparam = elem2param[itype][jtype][ktype]; delr2[0] = x[k][0] - xtmp; delr2[1] = x[k][1] - ytmp; delr2[2] = x[k][2] - ztmp; rsq2 = delr2[0]*delr2[0] + delr2[1]*delr2[1] + delr2[2]*delr2[2]; if (rsq2 > params[ikparam].cutsq) continue; threebody(¶ms[ijparam],¶ms[ikparam],¶ms[ijkparam], rsq1,rsq2,delr1,delr2,fj,fk,eflag,evdwl); f[i][0] -= fj[0] + fk[0]; f[i][1] -= fj[1] + fk[1]; f[i][2] -= fj[2] + fk[2]; f[j][0] += fj[0]; f[j][1] += fj[1]; f[j][2] += fj[2]; f[k][0] += fk[0]; f[k][1] += fk[1]; f[k][2] += fk[2]; if (evflag) ev_tally3(i,j,k,evdwl,0.0,fj,fk,delr1,delr2); } } } if (vflag_fdotr) virial_compute(); } /* ---------------------------------------------------------------------- */ void PairSW::allocate() { allocated = 1; int n = atom->ntypes; memory->create(setflag,n+1,n+1,"pair:setflag"); memory->create(cutsq,n+1,n+1,"pair:cutsq"); map = new int[n+1]; } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairSW::settings(int narg, char **arg) { if (narg != 0) error->all("Illegal pair_style command"); } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairSW::coeff(int narg, char **arg) { int i,j,n; if (!allocated) allocate(); if (narg != 3 + atom->ntypes) error->all("Incorrect args for pair coefficients"); // insure I,J args are * * if (strcmp(arg[0],"*") != 0 || strcmp(arg[1],"*") != 0) error->all("Incorrect args for pair coefficients"); // read args that map atom types to elements in potential file // map[i] = which element the Ith atom type is, -1 if NULL // nelements = # of unique elements // elements = list of element names if (elements) { for (i = 0; i < nelements; i++) delete [] elements[i]; delete [] elements; } elements = new char*[atom->ntypes]; for (i = 0; i < atom->ntypes; i++) elements[i] = NULL; nelements = 0; for (i = 3; i < narg; i++) { if (strcmp(arg[i],"NULL") == 0) { map[i-2] = -1; continue; } for (j = 0; j < nelements; j++) if (strcmp(arg[i],elements[j]) == 0) break; map[i-2] = j; if (j == nelements) { n = strlen(arg[i]) + 1; elements[j] = new char[n]; strcpy(elements[j],arg[i]); nelements++; } } // read potential file and initialize potential parameters read_file(arg[2]); setup(); // clear setflag since coeff() called once with I,J = * * n = atom->ntypes; for (int i = 1; i <= n; i++) for (int j = i; j <= n; j++) setflag[i][j] = 0; // set setflag i,j for type pairs where both are mapped to elements int count = 0; for (int i = 1; i <= n; i++) for (int j = i; j <= n; j++) if (map[i] >= 0 && map[j] >= 0) { setflag[i][j] = 1; count++; } if (count == 0) error->all("Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairSW::init_style() { if (atom->tag_enable == 0) error->all("Pair style Stillinger-Weber requires atom IDs"); if (force->newton_pair == 0) error->all("Pair style Stillinger-Weber requires newton pair on"); // need a full neighbor list int irequest = neighbor->request(this); neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->full = 1; } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairSW::init_one(int i, int j) { if (setflag[i][j] == 0) error->all("All pair coeffs are not set"); return cutmax; } /* ---------------------------------------------------------------------- */ void PairSW::read_file(char *file) { int params_per_line = 14; char **words = new char*[params_per_line+1]; memory->sfree(params); params = NULL; nparams = maxparam = 0; // open file on proc 0 FILE *fp; if (comm->me == 0) { fp = fopen(file,"r"); if (fp == NULL) { char str[128]; sprintf(str,"Cannot open Stillinger-Weber potential file %s",file); error->one(str); } } // read each set of params from potential file // one set of params can span multiple lines // store params if all 3 element tags are in element list int n,nwords,ielement,jelement,kelement; 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("Incorrect format in Stillinger-Weber 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; // ielement,jelement,kelement = 1st args // if all 3 args are in element list, then parse this line // else skip to next entry in file for (ielement = 0; ielement < nelements; ielement++) if (strcmp(words[0],elements[ielement]) == 0) break; if (ielement == nelements) continue; for (jelement = 0; jelement < nelements; jelement++) if (strcmp(words[1],elements[jelement]) == 0) break; if (jelement == nelements) continue; for (kelement = 0; kelement < nelements; kelement++) if (strcmp(words[2],elements[kelement]) == 0) break; if (kelement == nelements) 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].ielement = ielement; params[nparams].jelement = jelement; params[nparams].kelement = kelement; params[nparams].epsilon = atof(words[3]); params[nparams].sigma = atof(words[4]); params[nparams].littlea = atof(words[5]); params[nparams].lambda = atof(words[6]); params[nparams].gamma = atof(words[7]); params[nparams].costheta = atof(words[8]); params[nparams].biga = atof(words[9]); params[nparams].bigb = atof(words[10]); params[nparams].powerp = atof(words[11]); params[nparams].powerq = atof(words[12]); params[nparams].tol = atof(words[13]); if (params[nparams].epsilon < 0.0 || params[nparams].sigma < 0.0 || params[nparams].littlea < 0.0 || params[nparams].lambda < 0.0 || params[nparams].gamma < 0.0 || params[nparams].biga < 0.0 || params[nparams].bigb < 0.0 || params[nparams].powerp < 0.0 || params[nparams].powerq < 0.0 || params[nparams].tol < 0.0) error->all("Illegal Stillinger-Weber parameter"); nparams++; } delete [] words; } /* ---------------------------------------------------------------------- */ void PairSW::setup() { int i,j,k,m,n; double rtmp; // set elem2param for all triplet combinations // must be a single exact match to lines read from file // do not allow for ACB in place of ABC memory->destroy(elem2param); memory->create(elem2param,nelements,nelements,nelements,"pair:elem2param"); for (i = 0; i < nelements; i++) for (j = 0; j < nelements; j++) for (k = 0; k < nelements; k++) { n = -1; for (m = 0; m < nparams; m++) { if (i == params[m].ielement && j == params[m].jelement && k == params[m].kelement) { if (n >= 0) error->all("Potential file has duplicate entry"); n = m; } } if (n < 0) error->all("Potential file is missing an entry"); elem2param[i][j][k] = n; } // compute parameter values derived from inputs // set cutsq using shortcut to reduce neighbor list for accelerated // calculations. cut must remain unchanged as it is a potential parameter // (cut = a*sigma) for (m = 0; m < nparams; m++) { params[m].cut = params[m].sigma*params[m].littlea; rtmp = params[m].cut; if (params[m].tol > 0.0) { if (params[m].tol > 0.01) params[m].tol = 0.01; if (params[m].gamma < 1.0) rtmp = rtmp + params[m].gamma * params[m].sigma / log(params[m].tol); else rtmp = rtmp + params[m].sigma / log(params[m].tol); } params[m].cutsq = rtmp * rtmp; params[m].sigma_gamma = params[m].sigma*params[m].gamma; params[m].lambda_epsilon = params[m].lambda*params[m].epsilon; params[m].lambda_epsilon2 = 2.0*params[m].lambda*params[m].epsilon; params[m].c1 = params[m].biga*params[m].epsilon * params[m].powerp*params[m].bigb * pow(params[m].sigma,params[m].powerp); params[m].c2 = params[m].biga*params[m].epsilon*params[m].powerq * pow(params[m].sigma,params[m].powerq); params[m].c3 = params[m].biga*params[m].epsilon*params[m].bigb * pow(params[m].sigma,params[m].powerp+1.0); params[m].c4 = params[m].biga*params[m].epsilon * pow(params[m].sigma,params[m].powerq+1.0); params[m].c5 = params[m].biga*params[m].epsilon*params[m].bigb * pow(params[m].sigma,params[m].powerp); params[m].c6 = params[m].biga*params[m].epsilon * pow(params[m].sigma,params[m].powerq); } // set cutmax to max of all params cutmax = 0.0; for (m = 0; m < nparams; m++) { rtmp = sqrt(params[m].cutsq); if (rtmp > cutmax) cutmax = rtmp; } } /* ---------------------------------------------------------------------- */ void PairSW::twobody(Param *param, double rsq, double &fforce, int eflag, double &eng) { double r,rinvsq,rp,rq,rainv,rainvsq,expsrainv; r = sqrt(rsq); rinvsq = 1.0/rsq; rp = pow(r,-param->powerp); rq = pow(r,-param->powerq); rainv = 1.0 / (r - param->cut); rainvsq = rainv*rainv*r; expsrainv = exp(param->sigma * rainv); fforce = (param->c1*rp - param->c2*rq + (param->c3*rp -param->c4*rq) * rainvsq) * expsrainv * rinvsq; if (eflag) eng = (param->c5*rp - param->c6*rq) * expsrainv; } /* ---------------------------------------------------------------------- */ void PairSW::threebody(Param *paramij, Param *paramik, Param *paramijk, double rsq1, double rsq2, double *delr1, double *delr2, double *fj, double *fk, int eflag, double &eng) { double r1,rinvsq1,rainv1,gsrainv1,gsrainvsq1,expgsrainv1; double r2,rinvsq2,rainv2,gsrainv2,gsrainvsq2,expgsrainv2; double rinv12,cs,delcs,delcssq,facexp,facrad,frad1,frad2; double facang,facang12,csfacang,csfac1,csfac2; r1 = sqrt(rsq1); rinvsq1 = 1.0/rsq1; rainv1 = 1.0/(r1 - paramij->cut); gsrainv1 = paramij->sigma_gamma * rainv1; gsrainvsq1 = gsrainv1*rainv1/r1; expgsrainv1 = exp(gsrainv1); r2 = sqrt(rsq2); rinvsq2 = 1.0/rsq2; rainv2 = 1.0/(r2 - paramik->cut); gsrainv2 = paramik->sigma_gamma * rainv2; gsrainvsq2 = gsrainv2*rainv2/r2; expgsrainv2 = exp(gsrainv2); rinv12 = 1.0/(r1*r2); cs = (delr1[0]*delr2[0] + delr1[1]*delr2[1] + delr1[2]*delr2[2]) * rinv12; delcs = cs - paramijk->costheta; delcssq = delcs*delcs; facexp = expgsrainv1*expgsrainv2; // facrad = sqrt(paramij->lambda_epsilon*paramik->lambda_epsilon) * // facexp*delcssq; facrad = paramijk->lambda_epsilon * facexp*delcssq; frad1 = facrad*gsrainvsq1; frad2 = facrad*gsrainvsq2; facang = paramijk->lambda_epsilon2 * facexp*delcs; facang12 = rinv12*facang; csfacang = cs*facang; csfac1 = rinvsq1*csfacang; fj[0] = delr1[0]*(frad1+csfac1)-delr2[0]*facang12; fj[1] = delr1[1]*(frad1+csfac1)-delr2[1]*facang12; fj[2] = delr1[2]*(frad1+csfac1)-delr2[2]*facang12; csfac2 = rinvsq2*csfacang; fk[0] = delr2[0]*(frad2+csfac2)-delr1[0]*facang12; fk[1] = delr2[1]*(frad2+csfac2)-delr1[1]*facang12; fk[2] = delr2[2]*(frad2+csfac2)-delr1[2]*facang12; if (eflag) eng = facrad; } diff --git a/src/MANYBODY/pair_tersoff.cpp b/src/MANYBODY/pair_tersoff.cpp index 0ca96b583..579356f81 100755 --- a/src/MANYBODY/pair_tersoff.cpp +++ b/src/MANYBODY/pair_tersoff.cpp @@ -1,795 +1,799 @@ /* ---------------------------------------------------------------------- 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 "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "pair_tersoff.h" #include "atom.h" #include "neighbor.h" #include "neigh_list.h" #include "neigh_request.h" #include "force.h" #include "comm.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define MAXLINE 1024 #define DELTA 4 /* ---------------------------------------------------------------------- */ PairTersoff::PairTersoff(LAMMPS *lmp) : Pair(lmp) { single_enable = 0; one_coeff = 1; PI = 4.0*atan(1.0); PI2 = 2.0*atan(1.0); PI4 = atan(1.0); nelements = 0; elements = NULL; nparams = maxparam = 0; params = NULL; elem2param = NULL; } /* ---------------------------------------------------------------------- check if allocated, since class can be destructed when incomplete ------------------------------------------------------------------------- */ PairTersoff::~PairTersoff() { if (elements) for (int i = 0; i < nelements; i++) delete [] elements[i]; delete [] elements; memory->destroy(params); memory->destroy(elem2param); if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); delete [] map; } } /* ---------------------------------------------------------------------- */ void PairTersoff::compute(int eflag, int vflag) { int i,j,k,ii,jj,kk,inum,jnum; int itag,jtag,itype,jtype,ktype,iparam_ij,iparam_ijk; double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair; double rsq,rsq1,rsq2; double delr1[3],delr2[3],fi[3],fj[3],fk[3]; double zeta_ij,prefactor; int *ilist,*jlist,*numneigh,**firstneigh; evdwl = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = vflag_atom = 0; double **x = atom->x; double **f = atom->f; int *tag = atom->tag; 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 full neighbor list of my atoms for (ii = 0; ii < inum; ii++) { i = ilist[ii]; itag = tag[i]; itype = map[type[i]]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; // two-body interactions, skip half of them jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; + j &= NEIGHMASK; jtag = tag[j]; if (itag > jtag) { if ((itag+jtag) % 2 == 0) continue; } else if (itag < jtag) { if ((itag+jtag) % 2 == 1) continue; } else { if (x[j][2] < x[i][2]) continue; if (x[j][2] == ztmp && x[j][1] < ytmp) continue; if (x[j][2] == ztmp && x[j][1] == ytmp && x[j][0] < xtmp) continue; } jtype = map[type[j]]; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; iparam_ij = elem2param[itype][jtype][jtype]; if (rsq > params[iparam_ij].cutsq) continue; repulsive(¶ms[iparam_ij],rsq,fpair,eflag,evdwl); f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; 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); } // three-body interactions // skip immediately if I-J is not within cutoff for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; + j &= NEIGHMASK; jtype = map[type[j]]; iparam_ij = elem2param[itype][jtype][jtype]; delr1[0] = x[j][0] - xtmp; delr1[1] = x[j][1] - ytmp; delr1[2] = x[j][2] - ztmp; rsq1 = delr1[0]*delr1[0] + delr1[1]*delr1[1] + delr1[2]*delr1[2]; if (rsq1 > params[iparam_ij].cutsq) continue; // accumulate bondorder zeta for each i-j interaction via loop over k zeta_ij = 0.0; for (kk = 0; kk < jnum; kk++) { if (jj == kk) continue; k = jlist[kk]; + k &= NEIGHMASK; ktype = map[type[k]]; iparam_ijk = elem2param[itype][jtype][ktype]; delr2[0] = x[k][0] - xtmp; delr2[1] = x[k][1] - ytmp; delr2[2] = x[k][2] - ztmp; rsq2 = delr2[0]*delr2[0] + delr2[1]*delr2[1] + delr2[2]*delr2[2]; if (rsq2 > params[iparam_ijk].cutsq) continue; zeta_ij += zeta(¶ms[iparam_ijk],rsq1,rsq2,delr1,delr2); } // pairwise force due to zeta force_zeta(¶ms[iparam_ij],rsq1,zeta_ij,fpair,prefactor,eflag,evdwl); f[i][0] += delr1[0]*fpair; f[i][1] += delr1[1]*fpair; f[i][2] += delr1[2]*fpair; f[j][0] -= delr1[0]*fpair; f[j][1] -= delr1[1]*fpair; f[j][2] -= delr1[2]*fpair; if (evflag) ev_tally(i,j,nlocal,newton_pair, evdwl,0.0,-fpair,-delr1[0],-delr1[1],-delr1[2]); // attractive term via loop over k for (kk = 0; kk < jnum; kk++) { if (jj == kk) continue; k = jlist[kk]; + k &= NEIGHMASK; ktype = map[type[k]]; iparam_ijk = elem2param[itype][jtype][ktype]; delr2[0] = x[k][0] - xtmp; delr2[1] = x[k][1] - ytmp; delr2[2] = x[k][2] - ztmp; rsq2 = delr2[0]*delr2[0] + delr2[1]*delr2[1] + delr2[2]*delr2[2]; if (rsq2 > params[iparam_ijk].cutsq) continue; attractive(¶ms[iparam_ijk],prefactor, rsq1,rsq2,delr1,delr2,fi,fj,fk); 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] += fk[0]; f[k][1] += fk[1]; f[k][2] += fk[2]; if (vflag_atom) v_tally3(i,j,k,fj,fk,delr1,delr2); } } } if (vflag_fdotr) virial_compute(); } /* ---------------------------------------------------------------------- */ void PairTersoff::allocate() { allocated = 1; int n = atom->ntypes; memory->create(setflag,n+1,n+1,"pair:setflag"); memory->create(cutsq,n+1,n+1,"pair:cutsq"); map = new int[n+1]; } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairTersoff::settings(int narg, char **arg) { if (narg != 0) error->all("Illegal pair_style command"); } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairTersoff::coeff(int narg, char **arg) { int i,j,n; if (!allocated) allocate(); if (narg != 3 + atom->ntypes) error->all("Incorrect args for pair coefficients"); // insure I,J args are * * if (strcmp(arg[0],"*") != 0 || strcmp(arg[1],"*") != 0) error->all("Incorrect args for pair coefficients"); // read args that map atom types to elements in potential file // map[i] = which element the Ith atom type is, -1 if NULL // nelements = # of unique elements // elements = list of element names if (elements) { for (i = 0; i < nelements; i++) delete [] elements[i]; delete [] elements; } elements = new char*[atom->ntypes]; for (i = 0; i < atom->ntypes; i++) elements[i] = NULL; nelements = 0; for (i = 3; i < narg; i++) { if (strcmp(arg[i],"NULL") == 0) { map[i-2] = -1; continue; } for (j = 0; j < nelements; j++) if (strcmp(arg[i],elements[j]) == 0) break; map[i-2] = j; if (j == nelements) { n = strlen(arg[i]) + 1; elements[j] = new char[n]; strcpy(elements[j],arg[i]); nelements++; } } // read potential file and initialize potential parameters read_file(arg[2]); setup(); // clear setflag since coeff() called once with I,J = * * n = atom->ntypes; for (int i = 1; i <= n; i++) for (int j = i; j <= n; j++) setflag[i][j] = 0; // set setflag i,j for type pairs where both are mapped to elements int count = 0; for (int i = 1; i <= n; i++) for (int j = i; j <= n; j++) if (map[i] >= 0 && map[j] >= 0) { setflag[i][j] = 1; count++; } if (count == 0) error->all("Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairTersoff::init_style() { if (atom->tag_enable == 0) error->all("Pair style Tersoff requires atom IDs"); if (force->newton_pair == 0) error->all("Pair style Tersoff requires newton pair on"); // need a full neighbor list int irequest = neighbor->request(this); neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->full = 1; } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairTersoff::init_one(int i, int j) { if (setflag[i][j] == 0) error->all("All pair coeffs are not set"); return cutmax; } /* ---------------------------------------------------------------------- */ void PairTersoff::read_file(char *file) { int params_per_line = 17; char **words = new char*[params_per_line+1]; memory->sfree(params); params = NULL; nparams = maxparam = 0; // open file on proc 0 FILE *fp; if (comm->me == 0) { fp = fopen(file,"r"); if (fp == NULL) { char str[128]; sprintf(str,"Cannot open Tersoff potential file %s",file); error->one(str); } } // read each line out of file, skipping blank lines or leading '#' // store line of params if all 3 element tags are in element list int n,nwords,ielement,jelement,kelement; 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("Incorrect format in Tersoff 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; // ielement,jelement,kelement = 1st args // if all 3 args are in element list, then parse this line // else skip to next line for (ielement = 0; ielement < nelements; ielement++) if (strcmp(words[0],elements[ielement]) == 0) break; if (ielement == nelements) continue; for (jelement = 0; jelement < nelements; jelement++) if (strcmp(words[1],elements[jelement]) == 0) break; if (jelement == nelements) continue; for (kelement = 0; kelement < nelements; kelement++) if (strcmp(words[2],elements[kelement]) == 0) break; if (kelement == nelements) 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].ielement = ielement; params[nparams].jelement = jelement; params[nparams].kelement = kelement; params[nparams].powerm = atof(words[3]); params[nparams].gamma = atof(words[4]); params[nparams].lam3 = atof(words[5]); params[nparams].c = atof(words[6]); params[nparams].d = atof(words[7]); params[nparams].h = atof(words[8]); params[nparams].powern = atof(words[9]); params[nparams].beta = atof(words[10]); params[nparams].lam2 = atof(words[11]); params[nparams].bigb = atof(words[12]); params[nparams].bigr = atof(words[13]); params[nparams].bigd = atof(words[14]); params[nparams].lam1 = atof(words[15]); params[nparams].biga = atof(words[16]); // currently only allow m exponent of 1 or 3 params[nparams].powermint = int(params[nparams].powerm); if ( params[nparams].lam3 < 0.0 || params[nparams].c < 0.0 || params[nparams].d < 0.0 || params[nparams].powern < 0.0 || params[nparams].beta < 0.0 || params[nparams].lam2 < 0.0 || params[nparams].bigb < 0.0 || params[nparams].bigr < 0.0 || params[nparams].bigd < 0.0 || params[nparams].bigd > params[nparams].bigr || params[nparams].lam3 < 0.0 || params[nparams].biga < 0.0 || params[nparams].powerm - params[nparams].powermint != 0.0 || (params[nparams].powermint != 3 && params[nparams].powermint != 1) || params[nparams].gamma < 0.0) error->all("Illegal Tersoff parameter"); nparams++; } delete [] words; } /* ---------------------------------------------------------------------- */ void PairTersoff::setup() { int i,j,k,m,n; // set elem2param for all element triplet combinations // must be a single exact match to lines read from file // do not allow for ACB in place of ABC memory->destroy(elem2param); memory->create(elem2param,nelements,nelements,nelements,"pair:elem2param"); for (i = 0; i < nelements; i++) for (j = 0; j < nelements; j++) for (k = 0; k < nelements; k++) { n = -1; for (m = 0; m < nparams; m++) { if (i == params[m].ielement && j == params[m].jelement && k == params[m].kelement) { if (n >= 0) error->all("Potential file has duplicate entry"); n = m; } } if (n < 0) error->all("Potential file is missing an entry"); elem2param[i][j][k] = n; } // compute parameter values derived from inputs for (m = 0; m < nparams; m++) { params[m].cut = params[m].bigr + params[m].bigd; params[m].cutsq = params[m].cut*params[m].cut; params[m].c1 = pow(2.0*params[m].powern*1.0e-16,-1.0/params[m].powern); params[m].c2 = pow(2.0*params[m].powern*1.0e-8,-1.0/params[m].powern); params[m].c3 = 1.0/params[m].c2; params[m].c4 = 1.0/params[m].c1; } // set cutmax to max of all params cutmax = 0.0; for (m = 0; m < nparams; m++) if (params[m].cut > cutmax) cutmax = params[m].cut; } /* ---------------------------------------------------------------------- */ void PairTersoff::repulsive(Param *param, double rsq, double &fforce, int eflag, double &eng) { double r,tmp_fc,tmp_fc_d,tmp_exp; r = sqrt(rsq); tmp_fc = ters_fc(r,param); tmp_fc_d = ters_fc_d(r,param); tmp_exp = exp(-param->lam1 * r); fforce = -param->biga * tmp_exp * (tmp_fc_d - tmp_fc*param->lam1) / r; if (eflag) eng = tmp_fc * param->biga * tmp_exp; } /* ---------------------------------------------------------------------- */ double PairTersoff::zeta(Param *param, double rsqij, double rsqik, double *delrij, double *delrik) { double rij,rik,costheta,arg,ex_delr; rij = sqrt(rsqij); rik = sqrt(rsqik); costheta = (delrij[0]*delrik[0] + delrij[1]*delrik[1] + delrij[2]*delrik[2]) / (rij*rik); if (param->powermint == 3) arg = pow(param->lam3 * (rij-rik),3.0); else arg = param->lam3 * (rij-rik); if (arg > 69.0776) ex_delr = 1.e30; else if (arg < -69.0776) ex_delr = 0.0; else ex_delr = exp(arg); return ters_fc(rik,param) * ters_gijk(costheta,param) * ex_delr; } /* ---------------------------------------------------------------------- */ void PairTersoff::force_zeta(Param *param, double rsq, double zeta_ij, double &fforce, double &prefactor, int eflag, double &eng) { double r,fa,fa_d,bij; r = sqrt(rsq); fa = ters_fa(r,param); fa_d = ters_fa_d(r,param); bij = ters_bij(zeta_ij,param); fforce = 0.5*bij*fa_d / r; prefactor = -0.5*fa * ters_bij_d(zeta_ij,param); if (eflag) eng = 0.5*bij*fa; } /* ---------------------------------------------------------------------- attractive term use param_ij cutoff for rij test use param_ijk cutoff for rik test ------------------------------------------------------------------------- */ void PairTersoff::attractive(Param *param, double prefactor, double rsqij, double rsqik, double *delrij, double *delrik, double *fi, double *fj, double *fk) { double rij_hat[3],rik_hat[3]; double rij,rijinv,rik,rikinv; rij = sqrt(rsqij); rijinv = 1.0/rij; vec3_scale(rijinv,delrij,rij_hat); rik = sqrt(rsqik); rikinv = 1.0/rik; vec3_scale(rikinv,delrik,rik_hat); ters_zetaterm_d(prefactor,rij_hat,rij,rik_hat,rik,fi,fj,fk,param); } /* ---------------------------------------------------------------------- */ double PairTersoff::ters_fc(double r, Param *param) { double ters_R = param->bigr; double ters_D = param->bigd; if (r < ters_R-ters_D) return 1.0; if (r > ters_R+ters_D) return 0.0; return 0.5*(1.0 - sin(PI2*(r - ters_R)/ters_D)); } /* ---------------------------------------------------------------------- */ double PairTersoff::ters_fc_d(double r, Param *param) { double ters_R = param->bigr; double ters_D = param->bigd; if (r < ters_R-ters_D) return 0.0; if (r > ters_R+ters_D) return 0.0; return -(PI4/ters_D) * cos(PI2*(r - ters_R)/ters_D); } /* ---------------------------------------------------------------------- */ double PairTersoff::ters_fa(double r, Param *param) { if (r > param->bigr + param->bigd) return 0.0; return -param->bigb * exp(-param->lam2 * r) * ters_fc(r,param); } /* ---------------------------------------------------------------------- */ double PairTersoff::ters_fa_d(double r, Param *param) { if (r > param->bigr + param->bigd) return 0.0; return param->bigb * exp(-param->lam2 * r) * (param->lam2 * ters_fc(r,param) - ters_fc_d(r,param)); } /* ---------------------------------------------------------------------- */ double PairTersoff::ters_bij(double zeta, Param *param) { double tmp = param->beta * zeta; if (tmp > param->c1) return 1.0/sqrt(tmp); if (tmp > param->c2) return (1.0 - pow(tmp,-param->powern) / (2.0*param->powern))/sqrt(tmp); if (tmp < param->c4) return 1.0; if (tmp < param->c3) return 1.0 - pow(tmp,param->powern)/(2.0*param->powern); return pow(1.0 + pow(tmp,param->powern), -1.0/(2.0*param->powern)); } /* ---------------------------------------------------------------------- */ double PairTersoff::ters_bij_d(double zeta, Param *param) { double tmp = param->beta * zeta; if (tmp > param->c1) return param->beta * -0.5*pow(tmp,-1.5); if (tmp > param->c2) return param->beta * (-0.5*pow(tmp,-1.5) * (1.0 - 0.5*(1.0 + 1.0/(2.0*param->powern)) * pow(tmp,-param->powern))); if (tmp < param->c4) return 0.0; if (tmp < param->c3) return -0.5*param->beta * pow(tmp,param->powern-1.0); double tmp_n = pow(tmp,param->powern); return -0.5 * pow(1.0+tmp_n, -1.0-(1.0/(2.0*param->powern)))*tmp_n / zeta; } /* ---------------------------------------------------------------------- */ double PairTersoff::ters_gijk(double costheta, Param *param) { double ters_c = param->c; double ters_d = param->d; return param->gamma*(1.0 + pow(ters_c/ters_d,2.0) - pow(ters_c,2.0) / (pow(ters_d,2.0) + pow(param->h - costheta,2.0))); }; /* ---------------------------------------------------------------------- */ double PairTersoff::ters_gijk_d(double costheta, Param *param) { double numerator = -2.0 * pow(param->c,2) * (param->h - costheta); double denominator = pow(pow(param->d,2.0) + pow(param->h - costheta,2.0),2.0); return param->gamma*numerator/denominator; } /* ---------------------------------------------------------------------- */ void PairTersoff::ters_zetaterm_d(double prefactor, double *rij_hat, double rij, double *rik_hat, double rik, double *dri, double *drj, double *drk, Param *param) { double gijk,gijk_d,ex_delr,ex_delr_d,fc,dfc,cos_theta,tmp; double dcosdri[3],dcosdrj[3],dcosdrk[3]; fc = ters_fc(rik,param); dfc = ters_fc_d(rik,param); if (param->powermint == 3) tmp = pow(param->lam3 * (rij-rik),3.0); else tmp = param->lam3 * (rij-rik); if (tmp > 69.0776) ex_delr = 1.e30; else if (tmp < -69.0776) ex_delr = 0.0; else ex_delr = exp(tmp); if (param->powermint == 3) ex_delr_d = 3.0*pow(param->lam3,3.0) * pow(rij-rik,2.0)*ex_delr; else ex_delr_d = param->lam3 * ex_delr; cos_theta = vec3_dot(rij_hat,rik_hat); gijk = ters_gijk(cos_theta,param); gijk_d = ters_gijk_d(cos_theta,param); costheta_d(rij_hat,rij,rik_hat,rik,dcosdri,dcosdrj,dcosdrk); // compute the derivative wrt Ri // dri = -dfc*gijk*ex_delr*rik_hat; // dri += fc*gijk_d*ex_delr*dcosdri; // dri += fc*gijk*ex_delr_d*(rik_hat - rij_hat); vec3_scale(-dfc*gijk*ex_delr,rik_hat,dri); vec3_scaleadd(fc*gijk_d*ex_delr,dcosdri,dri,dri); vec3_scaleadd(fc*gijk*ex_delr_d,rik_hat,dri,dri); vec3_scaleadd(-fc*gijk*ex_delr_d,rij_hat,dri,dri); vec3_scale(prefactor,dri,dri); // compute the derivative wrt Rj // drj = fc*gijk_d*ex_delr*dcosdrj; // drj += fc*gijk*ex_delr_d*rij_hat; vec3_scale(fc*gijk_d*ex_delr,dcosdrj,drj); vec3_scaleadd(fc*gijk*ex_delr_d,rij_hat,drj,drj); vec3_scale(prefactor,drj,drj); // compute the derivative wrt Rk // drk = dfc*gijk*ex_delr*rik_hat; // drk += fc*gijk_d*ex_delr*dcosdrk; // drk += -fc*gijk*ex_delr_d*rik_hat; vec3_scale(dfc*gijk*ex_delr,rik_hat,drk); vec3_scaleadd(fc*gijk_d*ex_delr,dcosdrk,drk,drk); vec3_scaleadd(-fc*gijk*ex_delr_d,rik_hat,drk,drk); vec3_scale(prefactor,drk,drk); } /* ---------------------------------------------------------------------- */ void PairTersoff::costheta_d(double *rij_hat, double rij, double *rik_hat, double rik, double *dri, double *drj, double *drk) { // first element is devative wrt Ri, second wrt Rj, third wrt Rk double cos_theta = vec3_dot(rij_hat,rik_hat); vec3_scaleadd(-cos_theta,rij_hat,rik_hat,drj); vec3_scale(1.0/rij,drj,drj); vec3_scaleadd(-cos_theta,rik_hat,rij_hat,drk); vec3_scale(1.0/rik,drk,drk); vec3_add(drj,drk,dri); vec3_scale(-1.0,dri,dri); }; diff --git a/src/MEAM/pair_meam.cpp b/src/MEAM/pair_meam.cpp index d922a7527..d35cecc85 100644 --- a/src/MEAM/pair_meam.cpp +++ b/src/MEAM/pair_meam.cpp @@ -1,919 +1,948 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author: Greg Wagner (SNL) ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "pair_meam.h" #include "atom.h" #include "force.h" #include "comm.h" #include "memory.h" #include "neighbor.h" #include "neigh_list.h" #include "neigh_request.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define MAXLINE 1024 enum{FCC,BCC,HCP,DIM,DIAMOND,B1,C11,L12,B2}; int nkeywords = 19; char *keywords[] = {"Ec","alpha","rho0","delta","lattce", "attrac","repuls","nn2","Cmin","Cmax","rc","delr", "augt1","gsmooth_factor","re","ialloy","mixture_ref_t", "erose_form","zbl"}; /* ---------------------------------------------------------------------- */ PairMEAM::PairMEAM(LAMMPS *lmp) : Pair(lmp) { single_enable = 0; one_coeff = 1; nmax = 0; rho = rho0 = rho1 = rho2 = rho3 = frhop = NULL; gamma = dgamma1 = dgamma2 = dgamma3 = arho2b = NULL; arho1 = arho2 = arho3 = arho3b = t_ave = tsq_ave = NULL; maxneigh = 0; scrfcn = dscrfcn = fcpair = NULL; nelements = 0; elements = NULL; mass = NULL; // set comm size needed by this Pair comm_forward = 38; comm_reverse = 30; } /* ---------------------------------------------------------------------- free all arrays check if allocated, since class can be destructed when incomplete ------------------------------------------------------------------------- */ PairMEAM::~PairMEAM() { meam_cleanup_(); memory->destroy(rho); memory->destroy(rho0); memory->destroy(rho1); memory->destroy(rho2); memory->destroy(rho3); memory->destroy(frhop); memory->destroy(gamma); memory->destroy(dgamma1); memory->destroy(dgamma2); memory->destroy(dgamma3); memory->destroy(arho2b); memory->destroy(arho1); memory->destroy(arho2); memory->destroy(arho3); memory->destroy(arho3b); memory->destroy(t_ave); memory->destroy(tsq_ave); memory->destroy(scrfcn); memory->destroy(dscrfcn); memory->destroy(fcpair); for (int i = 0; i < nelements; i++) delete [] elements[i]; delete [] elements; delete [] mass; if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); delete [] map; delete [] fmap; } } /* ---------------------------------------------------------------------- */ void PairMEAM::compute(int eflag, int vflag) { int i,j,ii,n,inum_half,itype,jtype,errorflag; double evdwl; int *ilist_half,*jlist_half,*numneigh_half,**firstneigh_half; int *numneigh_full,**firstneigh_full; evdwl = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = eflag_global = vflag_global = eflag_atom = vflag_atom = 0; int newton_pair = force->newton_pair; // grow local arrays if necessary if (atom->nmax > nmax) { memory->destroy(rho); memory->destroy(rho0); memory->destroy(rho1); memory->destroy(rho2); memory->destroy(rho3); memory->destroy(frhop); memory->destroy(gamma); memory->destroy(dgamma1); memory->destroy(dgamma2); memory->destroy(dgamma3); memory->destroy(arho2b); memory->destroy(arho1); memory->destroy(arho2); memory->destroy(arho3); memory->destroy(arho3b); memory->destroy(t_ave); memory->destroy(tsq_ave); nmax = atom->nmax; memory->create(rho,nmax,"pair:rho"); memory->create(rho0,nmax,"pair:rho0"); memory->create(rho1,nmax,"pair:rho1"); memory->create(rho2,nmax,"pair:rho2"); memory->create(rho3,nmax,"pair:rho3"); memory->create(frhop,nmax,"pair:frhop"); memory->create(gamma,nmax,"pair:gamma"); memory->create(dgamma1,nmax,"pair:dgamma1"); memory->create(dgamma2,nmax,"pair:dgamma2"); memory->create(dgamma3,nmax,"pair:dgamma3"); memory->create(arho2b,nmax,"pair:arho2b"); memory->create(arho1,nmax,3,"pair:arho1"); memory->create(arho2,nmax,6,"pair:arho2"); memory->create(arho3,nmax,10,"pair:arho3"); memory->create(arho3b,nmax,3,"pair:arho3b"); memory->create(t_ave,nmax,3,"pair:t_ave"); memory->create(tsq_ave,nmax,3,"pair:tsq_ave"); } // neighbor list info inum_half = listhalf->inum; ilist_half = listhalf->ilist; numneigh_half = listhalf->numneigh; firstneigh_half = listhalf->firstneigh; numneigh_full = listfull->numneigh; firstneigh_full = listfull->firstneigh; + // strip neighbor lists of any special bond flags before using with MEAM + // necessary before doing neigh_f2c and neigh_c2f conversions each step + + if (neighbor->ago == 0) { + neigh_strip(inum_half,ilist_half,numneigh_half,firstneigh_half); + neigh_strip(inum_half,ilist_half,numneigh_full,firstneigh_full); + } + // check size of scrfcn based on half neighbor list int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; n = 0; for (ii = 0; ii < inum_half; ii++) n += numneigh_half[ilist_half[ii]]; if (n > maxneigh) { memory->destroy(scrfcn); memory->destroy(dscrfcn); memory->destroy(fcpair); maxneigh = n; memory->create(scrfcn,maxneigh,"pair:scrfcn"); memory->create(dscrfcn,maxneigh,"pair:dscrfcn"); memory->create(fcpair,maxneigh,"pair:fcpair"); } // zero out local arrays for (i = 0; i < nall; i++) { rho0[i] = 0.0; arho2b[i] = 0.0; arho1[i][0] = arho1[i][1] = arho1[i][2] = 0.0; for (j = 0; j < 6; j++) arho2[i][j] = 0.0; for (j = 0; j < 10; j++) arho3[i][j] = 0.0; arho3b[i][0] = arho3b[i][1] = arho3b[i][2] = 0.0; t_ave[i][0] = t_ave[i][1] = t_ave[i][2] = 0.0; tsq_ave[i][0] = tsq_ave[i][1] = tsq_ave[i][2] = 0.0; } double **x = atom->x; double **f = atom->f; int *type = atom->type; int ntype = atom->ntypes; // change neighbor list indices to Fortran indexing neigh_c2f(inum_half,ilist_half,numneigh_half,firstneigh_half); neigh_c2f(inum_half,ilist_half,numneigh_full,firstneigh_full); // 3 stages of MEAM calculation // loop over my atoms followed by communication int ifort; int offset = 0; errorflag = 0; for (ii = 0; ii < inum_half; ii++) { i = ilist_half[ii]; ifort = i+1; meam_dens_init_(&ifort,&nmax,&ntype,type,fmap,&x[0][0], &numneigh_half[i],firstneigh_half[i], &numneigh_full[i],firstneigh_full[i], &scrfcn[offset],&dscrfcn[offset],&fcpair[offset], rho0,&arho1[0][0],&arho2[0][0],arho2b, &arho3[0][0],&arho3b[0][0],&t_ave[0][0],&tsq_ave[0][0], &errorflag); if (errorflag) { char str[128]; sprintf(str,"MEAM library error %d",errorflag); error->one(str); } offset += numneigh_half[i]; } comm->reverse_comm_pair(this); meam_dens_final_(&nlocal,&nmax,&eflag_either,&eflag_global,&eflag_atom, &eng_vdwl,eatom,&ntype,type,fmap, &arho1[0][0],&arho2[0][0],arho2b,&arho3[0][0], &arho3b[0][0],&t_ave[0][0],&tsq_ave[0][0],gamma,dgamma1, dgamma2,dgamma3,rho,rho0,rho1,rho2,rho3,frhop,&errorflag); if (errorflag) { char str[128]; sprintf(str,"MEAM library error %d",errorflag); error->one(str); } comm->forward_comm_pair(this); offset = 0; // vptr is first value in vatom if it will be used by meam_force() // else vatom may not exist, so pass dummy ptr double *vptr; if (vflag_atom) vptr = &vatom[0][0]; else vptr = &cutmax; for (ii = 0; ii < inum_half; ii++) { i = ilist_half[ii]; ifort = i+1; meam_force_(&ifort,&nmax,&eflag_either,&eflag_global,&eflag_atom, &vflag_atom,&eng_vdwl,eatom,&ntype,type,fmap,&x[0][0], &numneigh_half[i],firstneigh_half[i], &numneigh_full[i],firstneigh_full[i], &scrfcn[offset],&dscrfcn[offset],&fcpair[offset], dgamma1,dgamma2,dgamma3,rho0,rho1,rho2,rho3,frhop, &arho1[0][0],&arho2[0][0],arho2b,&arho3[0][0],&arho3b[0][0], &t_ave[0][0],&tsq_ave[0][0],&f[0][0],vptr,&errorflag); if (errorflag) { char str[128]; sprintf(str,"MEAM library error %d",errorflag); error->one(str); } offset += numneigh_half[i]; } // change neighbor list indices back to C indexing neigh_f2c(inum_half,ilist_half,numneigh_half,firstneigh_half); neigh_f2c(inum_half,ilist_half,numneigh_full,firstneigh_full); if (vflag_fdotr) virial_compute(); } /* ---------------------------------------------------------------------- */ void PairMEAM::allocate() { allocated = 1; int n = atom->ntypes; memory->create(setflag,n+1,n+1,"pair:setflag"); memory->create(cutsq,n+1,n+1,"pair:cutsq"); map = new int[n+1]; fmap = new int[n]; } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairMEAM::settings(int narg, char **arg) { if (narg != 0) error->all("Illegal pair_style command"); } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairMEAM::coeff(int narg, char **arg) { int i,j,m,n; if (!allocated) allocate(); if (narg < 6) error->all("Incorrect args for pair coefficients"); // insure I,J args are * * if (strcmp(arg[0],"*") != 0 || strcmp(arg[1],"*") != 0) error->all("Incorrect args for pair coefficients"); // read MEAM element names between 2 filenames // nelements = # of MEAM elements // elements = list of unique element names if (nelements) { for (i = 0; i < nelements; i++) delete [] elements[i]; delete [] elements; delete [] mass; } nelements = narg - 4 - atom->ntypes; if (nelements < 1) error->all("Incorrect args for pair coefficients"); elements = new char*[nelements]; mass = new double[nelements]; for (i = 0; i < nelements; i++) { n = strlen(arg[i+3]) + 1; elements[i] = new char[n]; strcpy(elements[i],arg[i+3]); } // read MEAM library and parameter files // pass all parameters to MEAM package // tell MEAM package that setup is done read_files(arg[2],arg[2+nelements+1]); meam_setup_done_(&cutmax); // read args that map atom types to MEAM elements // map[i] = which element the Ith atom type is, -1 if not mapped for (i = 4 + nelements; i < narg; i++) { m = i - (4+nelements) + 1; for (j = 0; j < nelements; j++) if (strcmp(arg[i],elements[j]) == 0) break; if (j < nelements) map[m] = j; else if (strcmp(arg[i],"NULL") == 0) map[m] = -1; else error->all("Incorrect args for pair coefficients"); } // clear setflag since coeff() called once with I,J = * * n = atom->ntypes; for (int i = 1; i <= n; i++) for (int j = i; j <= n; j++) setflag[i][j] = 0; // set setflag i,j for type pairs where both are mapped to elements // set mass for i,i in atom class int count = 0; for (int i = 1; i <= n; i++) for (int j = i; j <= n; j++) if (map[i] >= 0 && map[j] >= 0) { setflag[i][j] = 1; if (i == j) atom->set_mass(i,mass[map[i]]); count++; } if (count == 0) error->all("Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairMEAM::init_style() { if (force->newton_pair == 0) error->all("Pair style MEAM requires newton pair on"); // need full and half neighbor list int irequest_full = neighbor->request(this); neighbor->requests[irequest_full]->id = 1; neighbor->requests[irequest_full]->half = 0; neighbor->requests[irequest_full]->full = 1; int irequest_half = neighbor->request(this); neighbor->requests[irequest_half]->id = 2; neighbor->requests[irequest_half]->half = 0; neighbor->requests[irequest_half]->half_from_full = 1; neighbor->requests[irequest_half]->otherlist = irequest_full; // setup Fortran-style mapping array needed by MEAM package // fmap is indexed from 1:ntypes by Fortran and stores a Fortran index // if type I is not a MEAM atom, fmap stores a 0 for (int i = 1; i <= atom->ntypes; i++) fmap[i-1] = map[i] + 1; } /* ---------------------------------------------------------------------- neighbor callback to inform pair style of neighbor list to use half or full ------------------------------------------------------------------------- */ void PairMEAM::init_list(int id, NeighList *ptr) { if (id == 1) listfull = ptr; else if (id == 2) listhalf = ptr; } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairMEAM::init_one(int i, int j) { return cutmax; } /* ---------------------------------------------------------------------- */ void PairMEAM::read_files(char *globalfile, char *userfile) { // open global meamf file on proc 0 FILE *fp; if (comm->me == 0) { fp = fopen(globalfile,"r"); if (fp == NULL) { char str[128]; sprintf(str,"Cannot open MEAM potential file %s",globalfile); error->one(str); } } // allocate parameter arrays int params_per_line = 19; int *lat = new int[nelements]; int *ielement = new int[nelements]; int *ibar = new int[nelements]; double *z = new double[nelements]; double *atwt = new double[nelements]; double *alpha = new double[nelements]; double *b0 = new double[nelements]; double *b1 = new double[nelements]; double *b2 = new double[nelements]; double *b3 = new double[nelements]; double *alat = new double[nelements]; double *esub = new double[nelements]; double *asub = new double[nelements]; double *t0 = new double[nelements]; double *t1 = new double[nelements]; double *t2 = new double[nelements]; double *t3 = new double[nelements]; double *rozero = new double[nelements]; bool *found = new bool[nelements]; for (int i = 0; i < nelements; i++) found[i] = false; // read each set of params from global MEAM file // one set of params can span multiple lines // store params if element name is in element list // if element name appears multiple times, only store 1st entry int i,n,nwords; char **words = new char*[params_per_line+1]; char line[MAXLINE],*ptr; int eof = 0; int nset = 0; while (1) { if (comm->me == 0) { ptr = fgets(line,MAXLINE,fp); if (ptr == NULL) { eof = 1; fclose(fp); } else n = strlen(line) + 1; } MPI_Bcast(&eof,1,MPI_INT,0,world); if (eof) break; MPI_Bcast(&n,1,MPI_INT,0,world); MPI_Bcast(line,n,MPI_CHAR,0,world); // strip comment, skip line if blank if (ptr = strchr(line,'#')) *ptr = '\0'; nwords = atom->count_words(line); if (nwords == 0) continue; // concatenate additional lines until have params_per_line words while (nwords < params_per_line) { n = strlen(line); if (comm->me == 0) { ptr = fgets(&line[n],MAXLINE-n,fp); if (ptr == NULL) { eof = 1; fclose(fp); } else n = strlen(line) + 1; } MPI_Bcast(&eof,1,MPI_INT,0,world); if (eof) break; MPI_Bcast(&n,1,MPI_INT,0,world); MPI_Bcast(line,n,MPI_CHAR,0,world); if (ptr = strchr(line,'#')) *ptr = '\0'; nwords = atom->count_words(line); } if (nwords != params_per_line) error->all("Incorrect format in MEAM potential file"); // words = ptrs to all words in line // strip single and double quotes from words nwords = 0; words[nwords++] = strtok(line,"' \t\n\r\f"); while (words[nwords++] = strtok(NULL,"' \t\n\r\f")) continue; // skip if element name isn't in element list for (i = 0; i < nelements; i++) if (strcmp(words[0],elements[i]) == 0) break; if (i == nelements) continue; // skip if element already appeared if (found[i] == true) continue; found[i] = true; // map lat string to an integer if (strcmp(words[1],"fcc") == 0) lat[i] = FCC; else if (strcmp(words[1],"bcc") == 0) lat[i] = BCC; else if (strcmp(words[1],"hcp") == 0) lat[i] = HCP; else if (strcmp(words[1],"dim") == 0) lat[i] = DIM; else if (strcmp(words[1],"dia") == 0) lat[i] = DIAMOND; else error->all("Unrecognized lattice type in MEAM file 1"); // store parameters z[i] = atof(words[2]); ielement[i] = atoi(words[3]); atwt[i] = atof(words[4]); alpha[i] = atof(words[5]); b0[i] = atof(words[6]); b1[i] = atof(words[7]); b2[i] = atof(words[8]); b3[i] = atof(words[9]); alat[i] = atof(words[10]); esub[i] = atof(words[11]); asub[i] = atof(words[12]); t0[i] = atof(words[13]); t1[i] = atof(words[14]); t2[i] = atof(words[15]); t3[i] = atof(words[16]); rozero[i] = atof(words[17]); ibar[i] = atoi(words[18]); nset++; } // error if didn't find all elements in file if (nset != nelements) error->all("Did not find all elements in MEAM library file"); // pass element parameters to MEAM package meam_setup_global_(&nelements,lat,z,ielement,atwt,alpha,b0,b1,b2,b3, alat,esub,asub,t0,t1,t2,t3,rozero,ibar); // set element masses for (i = 0; i < nelements; i++) mass[i] = atwt[i]; // clean-up memory delete [] words; delete [] lat; delete [] ielement; delete [] ibar; delete [] z; delete [] atwt; delete [] alpha; delete [] b0; delete [] b1; delete [] b2; delete [] b3; delete [] alat; delete [] esub; delete [] asub; delete [] t0; delete [] t1; delete [] t2; delete [] t3; delete [] rozero; delete [] found; // done if user param file is NULL if (strcmp(userfile,"NULL") == 0) return; // open user param file on proc 0 if (comm->me == 0) { fp = fopen(userfile,"r"); if (fp == NULL) { char str[128]; sprintf(str,"Cannot open MEAM potential file %s",userfile); error->one(str); } } // read settings // pass them one at a time to MEAM package // match strings to list of corresponding ints int which; double value; int nindex,index[3]; int maxparams = 6; char **params = new char*[maxparams]; int nparams; eof = 0; while (1) { if (comm->me == 0) { ptr = fgets(line,MAXLINE,fp); if (ptr == NULL) { eof = 1; fclose(fp); } else n = strlen(line) + 1; } MPI_Bcast(&eof,1,MPI_INT,0,world); if (eof) break; MPI_Bcast(&n,1,MPI_INT,0,world); MPI_Bcast(line,n,MPI_CHAR,0,world); // strip comment, skip line if blank if (ptr = strchr(line,'#')) *ptr = '\0'; nparams = atom->count_words(line); if (nparams == 0) continue; // words = ptrs to all words in line nparams = 0; params[nparams++] = strtok(line,"=(), '\t\n\r\f"); while (nparams < maxparams && (params[nparams++] = strtok(NULL,"=(), '\t\n\r\f"))) continue; nparams--; for (which = 0; which < nkeywords; which++) if (strcmp(params[0],keywords[which]) == 0) break; if (which == nkeywords) { char str[128]; sprintf(str,"Keyword %s in MEAM parameter file not recognized", params[0]); error->all(str); } nindex = nparams - 2; for (i = 0; i < nindex; i++) index[i] = atoi(params[i+1]); // map lattce_meam value to an integer if (which == 4) { if (strcmp(params[nparams-1],"fcc") == 0) value = FCC; else if (strcmp(params[nparams-1],"bcc") == 0) value = BCC; else if (strcmp(params[nparams-1],"hcp") == 0) value = HCP; else if (strcmp(params[nparams-1],"dim") == 0) value = DIM; else if (strcmp(params[nparams-1],"dia") == 0) value = DIAMOND; else if (strcmp(params[nparams-1],"b1") == 0) value = B1; else if (strcmp(params[nparams-1],"c11") == 0) value = C11; else if (strcmp(params[nparams-1],"l12") == 0) value = L12; else if (strcmp(params[nparams-1],"b2") == 0) value = B2; else error->all("Unrecognized lattice type in MEAM file 2"); } else value = atof(params[nparams-1]); // pass single setting to MEAM package int errorflag = 0; meam_setup_param_(&which,&value,&nindex,index,&errorflag); if (errorflag) { char str[128]; sprintf(str,"MEAM library error %d",errorflag); error->all(str); } } delete [] params; } /* ---------------------------------------------------------------------- */ int PairMEAM::pack_comm(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,k,m; m = 0; for (i = 0; i < n; i++) { j = list[i]; buf[m++] = rho0[j]; buf[m++] = rho1[j]; buf[m++] = rho2[j]; buf[m++] = rho3[j]; buf[m++] = frhop[j]; buf[m++] = gamma[j]; buf[m++] = dgamma1[j]; buf[m++] = dgamma2[j]; buf[m++] = dgamma3[j]; buf[m++] = arho2b[j]; buf[m++] = arho1[j][0]; buf[m++] = arho1[j][1]; buf[m++] = arho1[j][2]; buf[m++] = arho2[j][0]; buf[m++] = arho2[j][1]; buf[m++] = arho2[j][2]; buf[m++] = arho2[j][3]; buf[m++] = arho2[j][4]; buf[m++] = arho2[j][5]; for (k = 0; k < 10; k++) buf[m++] = arho3[j][k]; buf[m++] = arho3b[j][0]; buf[m++] = arho3b[j][1]; buf[m++] = arho3b[j][2]; buf[m++] = t_ave[j][0]; buf[m++] = t_ave[j][1]; buf[m++] = t_ave[j][2]; buf[m++] = tsq_ave[j][0]; buf[m++] = tsq_ave[j][1]; buf[m++] = tsq_ave[j][2]; } return comm_forward; } /* ---------------------------------------------------------------------- */ void PairMEAM::unpack_comm(int n, int first, double *buf) { int i,k,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { rho0[i] = buf[m++]; rho1[i] = buf[m++]; rho2[i] = buf[m++]; rho3[i] = buf[m++]; frhop[i] = buf[m++]; gamma[i] = buf[m++]; dgamma1[i] = buf[m++]; dgamma2[i] = buf[m++]; dgamma3[i] = buf[m++]; arho2b[i] = buf[m++]; arho1[i][0] = buf[m++]; arho1[i][1] = buf[m++]; arho1[i][2] = buf[m++]; arho2[i][0] = buf[m++]; arho2[i][1] = buf[m++]; arho2[i][2] = buf[m++]; arho2[i][3] = buf[m++]; arho2[i][4] = buf[m++]; arho2[i][5] = buf[m++]; for (k = 0; k < 10; k++) arho3[i][k] = buf[m++]; arho3b[i][0] = buf[m++]; arho3b[i][1] = buf[m++]; arho3b[i][2] = buf[m++]; t_ave[i][0] = buf[m++]; t_ave[i][1] = buf[m++]; t_ave[i][2] = buf[m++]; tsq_ave[i][0] = buf[m++]; tsq_ave[i][1] = buf[m++]; tsq_ave[i][2] = buf[m++]; } } /* ---------------------------------------------------------------------- */ int PairMEAM::pack_reverse_comm(int n, int first, double *buf) { int i,k,m,last,size; m = 0; last = first + n; for (i = first; i < last; i++) { buf[m++] = rho0[i]; buf[m++] = arho2b[i]; buf[m++] = arho1[i][0]; buf[m++] = arho1[i][1]; buf[m++] = arho1[i][2]; buf[m++] = arho2[i][0]; buf[m++] = arho2[i][1]; buf[m++] = arho2[i][2]; buf[m++] = arho2[i][3]; buf[m++] = arho2[i][4]; buf[m++] = arho2[i][5]; for (k = 0; k < 10; k++) buf[m++] = arho3[i][k]; buf[m++] = arho3b[i][0]; buf[m++] = arho3b[i][1]; buf[m++] = arho3b[i][2]; buf[m++] = t_ave[i][0]; buf[m++] = t_ave[i][1]; buf[m++] = t_ave[i][2]; buf[m++] = tsq_ave[i][0]; buf[m++] = tsq_ave[i][1]; buf[m++] = tsq_ave[i][2]; } return comm_reverse; } /* ---------------------------------------------------------------------- */ void PairMEAM::unpack_reverse_comm(int n, int *list, double *buf) { int i,j,k,m; m = 0; for (i = 0; i < n; i++) { j = list[i]; rho0[j] += buf[m++]; arho2b[j] += buf[m++]; arho1[j][0] += buf[m++]; arho1[j][1] += buf[m++]; arho1[j][2] += buf[m++]; arho2[j][0] += buf[m++]; arho2[j][1] += buf[m++]; arho2[j][2] += buf[m++]; arho2[j][3] += buf[m++]; arho2[j][4] += buf[m++]; arho2[j][5] += buf[m++]; for (k = 0; k < 10; k++) arho3[j][k] += buf[m++]; arho3b[j][0] += buf[m++]; arho3b[j][1] += buf[m++]; arho3b[j][2] += buf[m++]; t_ave[j][0] += buf[m++]; t_ave[j][1] += buf[m++]; t_ave[j][2] += buf[m++]; tsq_ave[j][0] += buf[m++]; tsq_ave[j][1] += buf[m++]; tsq_ave[j][2] += buf[m++]; } } /* ---------------------------------------------------------------------- memory usage of local atom-based arrays ------------------------------------------------------------------------- */ double PairMEAM::memory_usage() { double bytes = 11 * nmax * sizeof(double); bytes += (3 + 6 + 10 + 3 + 3 + 3) * nmax * sizeof(double); bytes += 3 * maxneigh * sizeof(double); return bytes; } +/* ---------------------------------------------------------------------- + strip special bond flags from neighbor list entries + are not used with MEAM + need to do here so Fortran lib doesn't see them + done once per reneighbor so that neigh_f2c and neigh_c2f don't see them +------------------------------------------------------------------------- */ + +void PairMEAM::neigh_strip(int inum, int *ilist, + int *numneigh, int **firstneigh) +{ + int i,j,ii,jnum; + int *jlist; + + for (ii = 0; ii < inum; ii++) { + i = ilist[ii]; + jlist = firstneigh[i]; + jnum = numneigh[i]; + for (j = 0; j < jnum; j++) jlist[j] &= NEIGHMASK; + } +} + /* ---------------------------------------------------------------------- toggle neighbor list indices between zero- and one-based values needed for access by MEAM Fortran library ------------------------------------------------------------------------- */ void PairMEAM::neigh_f2c(int inum, int *ilist, int *numneigh, int **firstneigh) { int i,j,ii,jnum; int *jlist; for (ii = 0; ii < inum; ii++) { i = ilist[ii]; jlist = firstneigh[i]; jnum = numneigh[i]; for (j = 0; j < jnum; j++) jlist[j]--; } } void PairMEAM::neigh_c2f(int inum, int *ilist, int *numneigh, int **firstneigh) { int i,j,ii,jnum; int *jlist; for (ii = 0; ii < inum; ii++) { i = ilist[ii]; jlist = firstneigh[i]; jnum = numneigh[i]; for (j = 0; j < jnum; j++) jlist[j]++; } } diff --git a/src/MEAM/pair_meam.h b/src/MEAM/pair_meam.h index 7c993b24c..267f0e3f3 100644 --- a/src/MEAM/pair_meam.h +++ b/src/MEAM/pair_meam.h @@ -1,104 +1,105 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #ifdef PAIR_CLASS PairStyle(meam,PairMEAM) #else #ifndef LMP_PAIR_MEAM_H #define LMP_PAIR_MEAM_H extern "C" { void meam_setup_global_(int *, int *, double *, int *, double *, double *, double *, double *, double *, double *, double *, double *, double *, double *, double *, double *, double *, double *, int *); void meam_setup_param_(int *, double *, int *, int *, int *); void meam_setup_done_(double *); void meam_dens_init_(int *, int *, int *, int *, int *, double *, int *, int *, int *, int *, double *, double *, double *, double *, double *, double *, double *, double *, double *, double *, double *, int *); void meam_dens_final_(int *, int *, int *, int *, int *, double *, double *, int *, int *, int *, double *, double *, double *, double *, double *, double *, double *, double *, double *, double *, double *, double *, double *, double *, double *, double *, double *, int *); void meam_force_(int *, int *, int *, int *, int *, int *, double *, double *, int *, int *, int *, double *, int *, int *, int *, int *, double *, double *, double *, double *, double *, double *, double *, double *, double *, double *, double *, double *, double *, double *, double *, double *, double *, double *, double *, double *, int *); void meam_cleanup_(); } #include "pair.h" namespace LAMMPS_NS { class PairMEAM : public Pair { public: PairMEAM(class LAMMPS *); ~PairMEAM(); void compute(int, int); void settings(int, char **); void coeff(int, char **); void init_style(); void init_list(int, class NeighList *); double init_one(int, int); int pack_comm(int, int *, double *, int, int *); void unpack_comm(int, int, double *); int pack_reverse_comm(int, int, double *); void unpack_reverse_comm(int, int *, double *); double memory_usage(); private: double cutmax; // max cutoff for all elements int nelements; // # of unique elements char **elements; // names of unique elements double *mass; // mass of each element int *map; // mapping from atom types to elements int *fmap; // Fortran version of map array for MEAM lib int maxneigh; double *scrfcn,*dscrfcn,*fcpair; int nmax; double *rho,*rho0,*rho1,*rho2,*rho3,*frhop; double *gamma,*dgamma1,*dgamma2,*dgamma3,*arho2b; double **arho1,**arho2,**arho3,**arho3b,**t_ave,**tsq_ave; void allocate(); void read_files(char *, char *); + void neigh_strip(int, int *, int *, int **); void neigh_f2c(int, int *, int *, int **); void neigh_c2f(int, int *, int *, int **); }; } #endif #endif diff --git a/src/MOLECULE/fix_bond_create.cpp b/src/MOLECULE/fix_bond_create.cpp index ec61cda05..68689c420 100755 --- a/src/MOLECULE/fix_bond_create.cpp +++ b/src/MOLECULE/fix_bond_create.cpp @@ -1,616 +1,617 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "math.h" #include "mpi.h" #include "string.h" #include "stdlib.h" #include "fix_bond_create.h" #include "update.h" #include "respa.h" #include "atom.h" #include "force.h" #include "pair.h" #include "comm.h" #include "neighbor.h" #include "neigh_list.h" #include "neigh_request.h" #include "random_mars.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define BIG 1.0e20 #define MIN(A,B) ((A) < (B)) ? (A) : (B) #define MAX(A,B) ((A) > (B)) ? (A) : (B) /* ---------------------------------------------------------------------- */ FixBondCreate::FixBondCreate(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg) { if (narg < 8) error->all("Illegal fix bond/create command"); MPI_Comm_rank(world,&me); nevery = atoi(arg[3]); if (nevery <= 0) error->all("Illegal fix bond/create command"); force_reneighbor = 1; next_reneighbor = -1; vector_flag = 1; size_vector = 2; global_freq = 1; extvector = 0; iatomtype = atoi(arg[4]); jatomtype = atoi(arg[5]); double cutoff = atof(arg[6]); btype = atoi(arg[7]); if (iatomtype < 1 || iatomtype > atom->ntypes || jatomtype < 1 || jatomtype > atom->ntypes) error->all("Invalid atom type in fix bond/create command"); if (cutoff < 0.0) error->all("Illegal fix bond/create command"); if (btype < 1 || btype > atom->nbondtypes) error->all("Invalid bond type in fix bond/create command"); cutsq = cutoff*cutoff; // optional keywords imaxbond = 0; inewtype = iatomtype; jmaxbond = 0; jnewtype = jatomtype; fraction = 1.0; int seed = 12345; int iarg = 8; while (iarg < narg) { if (strcmp(arg[iarg],"iparam") == 0) { if (iarg+3 > narg) error->all("Illegal fix bond/create command"); imaxbond = atoi(arg[iarg+1]); inewtype = atoi(arg[iarg+2]); if (imaxbond < 0) error->all("Illegal fix bond/create command"); if (inewtype < 1 || inewtype > atom->ntypes) error->all("Invalid atom type in fix bond/create command"); iarg += 3; } else if (strcmp(arg[iarg],"jparam") == 0) { if (iarg+3 > narg) error->all("Illegal fix bond/create command"); jmaxbond = atoi(arg[iarg+1]); jnewtype = atoi(arg[iarg+2]); if (jmaxbond < 0) error->all("Illegal fix bond/create command"); if (jnewtype < 1 || jnewtype > atom->ntypes) error->all("Invalid atom type in fix bond/create command"); iarg += 3; } else if (strcmp(arg[iarg],"prob") == 0) { if (iarg+3 > narg) error->all("Illegal fix bond/create command"); fraction = atof(arg[iarg+1]); seed = atoi(arg[iarg+2]); if (fraction < 0.0 || fraction > 1.0) error->all("Illegal fix bond/create command"); if (seed <= 0) error->all("Illegal fix bond/create command"); iarg += 3; } else error->all("Illegal fix bond/create command"); } // error check if (atom->molecular == 0) error->all("Cannot use fix bond/create with non-molecular systems"); if (iatomtype == jatomtype && ((imaxbond != jmaxbond) || (inewtype != jnewtype))) error->all("Inconsistent iparam/jparam values in fix bond/create command"); // initialize Marsaglia RNG with processor-unique seed random = new RanMars(lmp,seed + me); // perform initial allocation of atom-based arrays // register with Atom class // bondcount values will be initialized in setup() bondcount = NULL; grow_arrays(atom->nmax); atom->add_callback(0); countflag = 0; // set comm sizes needed by this fix comm_forward = 2; comm_reverse = 2; // allocate arrays local to this fix nmax = 0; partner = NULL; distsq = NULL; // zero out stats createcount = 0; createcounttotal = 0; } /* ---------------------------------------------------------------------- */ FixBondCreate::~FixBondCreate() { // unregister callbacks to this fix from Atom class atom->delete_callback(id,0); delete random; // delete locally stored arrays memory->destroy(bondcount); memory->destroy(partner); memory->destroy(distsq); } /* ---------------------------------------------------------------------- */ int FixBondCreate::setmask() { int mask = 0; mask |= POST_INTEGRATE; mask |= POST_INTEGRATE_RESPA; return mask; } /* ---------------------------------------------------------------------- */ void FixBondCreate::init() { // check cutoff for iatomtype,jatomtype if (force->pair == NULL || cutsq > force->pair->cutsq[iatomtype][jatomtype]) error->all("Fix bond/create cutoff is longer than pairwise cutoff"); // require special bonds = 0,1,1 if (force->special_lj[1] != 0.0 || force->special_lj[2] != 1.0 || force->special_lj[3] != 1.0) error->all("Fix bond/create requires special_bonds lj = 0,1,1"); if (atom->q_flag) if (force->special_coul[1] != 0.0 || force->special_coul[2] != 1.0 || force->special_coul[3] != 1.0) error->all("Fix bond/create requires special_bonds coul = 0,1,1"); // warn if angles, dihedrals, impropers are being used if (force->angle || force->dihedral || force->improper) { if (me == 0) error->warning("Created bonds will not create angles, " "dihedrals, or impropers"); } // need a half neighbor list, built when ever re-neighboring occurs int irequest = neighbor->request((void *) this); neighbor->requests[irequest]->pair = 0; neighbor->requests[irequest]->fix = 1; if (strcmp(update->integrate_style,"respa") == 0) nlevels_respa = ((Respa *) update->integrate)->nlevels; } /* ---------------------------------------------------------------------- */ void FixBondCreate::init_list(int id, NeighList *ptr) { list = ptr; } /* ---------------------------------------------------------------------- */ void FixBondCreate::setup(int vflag) { int i,j,m; // compute initial bondcount if this is first run // can't do this earlier, like in constructor or init, b/c need ghost info if (countflag) return; countflag = 1; // count bonds stored with each bond I own // if newton bond is not set, just increment count on atom I // if newton bond is set, also increment count on atom J even if ghost // bondcount is long enough to tally ghost atom counts int *num_bond = atom->num_bond; int **bond_type = atom->bond_type; int **bond_atom = atom->bond_atom; int nlocal = atom->nlocal; int nghost = atom->nghost; int nall = nlocal + nghost; int newton_bond = force->newton_bond; for (i = 0; i < nall; i++) bondcount[i] = 0; for (i = 0; i < nlocal; i++) for (j = 0; j < num_bond[i]; j++) { if (bond_type[i][j] == btype) { bondcount[i]++; if (newton_bond) { m = atom->map(bond_atom[i][j]); if (m < 0) error->one("Could not count initial bonds in fix bond/create"); bondcount[m]++; } } } // if newton_bond is set, need to sum bondcount commflag = 0; if (newton_bond) comm->reverse_comm_fix(this); } /* ---------------------------------------------------------------------- */ void FixBondCreate::post_integrate() { int i,j,m,ii,jj,inum,jnum,itype,jtype,n1,n3,possible; double xtmp,ytmp,ztmp,delx,dely,delz,rsq,min,max; int *ilist,*jlist,*numneigh,**firstneigh,*slist; if (update->ntimestep % nevery) return; // need updated ghost atom positions comm->forward_comm(); // forward comm of bondcount, so ghosts have it commflag = 0; comm->forward_comm_fix(this); // resize bond partner list and initialize it // probability array overlays distsq array // needs to be atom->nmax in length if (atom->nmax > nmax) { memory->destroy(partner); memory->destroy(distsq); nmax = atom->nmax; memory->create(partner,nmax,"bond/create:partner"); memory->create(distsq,nmax,"bond/create:distsq"); probability = distsq; } int nlocal = atom->nlocal; int nall = atom->nlocal + atom->nghost; for (i = 0; i < nall; i++) { partner[i] = 0; distsq[i] = BIG; } // loop over neighbors of my atoms // each atom sets one closest eligible partner atom ID to bond with double **x = atom->x; int *tag = atom->tag; int *mask = atom->mask; int *type = atom->type; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; for (ii = 0; ii < inum; ii++) { i = ilist[ii]; if (!(mask[i] & groupbit)) continue; itype = type[i]; 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; if (!(mask[j] & groupbit)) continue; jtype = type[j]; possible = 0; if (itype == iatomtype && jtype == jatomtype) { if ((imaxbond == 0 || bondcount[i] < imaxbond) && (jmaxbond == 0 || bondcount[j] < jmaxbond)) possible = 1; } else if (itype == jatomtype && jtype == iatomtype) { if ((jmaxbond == 0 || bondcount[i] < jmaxbond) && (imaxbond == 0 || bondcount[j] < imaxbond)) possible = 1; } if (!possible) continue; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; if (rsq >= cutsq) continue; if (rsq < distsq[i]) { partner[i] = tag[j]; distsq[i] = rsq; } if (rsq < distsq[j]) { partner[j] = tag[i]; distsq[j] = rsq; } } } // reverse comm of distsq and partner // not needed if newton_pair off since I,J pair was seen by both procs commflag = 1; if (force->newton_pair) comm->reverse_comm_fix(this); // each atom now knows its winning partner // for prob check, generate random value for each atom with a bond partner // forward comm of partner and random value, so ghosts have it if (fraction < 1.0) { for (i = 0; i < nlocal; i++) if (partner[i]) probability[i] = random->uniform(); } commflag = 1; comm->forward_comm_fix(this); // create bonds for atoms I own // if other atom is owned by another proc, it should create same bond // if both atoms list each other as winning bond partner // and probability constraint is satisfied int **bond_type = atom->bond_type; int **bond_atom = atom->bond_atom; int *num_bond = atom->num_bond; int **nspecial = atom->nspecial; int **special = atom->special; int newton_bond = force->newton_bond; int ncreate = 0; for (i = 0; i < nlocal; i++) { if (partner[i] == 0) continue; j = atom->map(partner[i]); if (partner[j] != tag[i]) continue; // apply probability constraint // MIN,MAX insures values are added in same order on different procs if (fraction < 1.0) { min = MIN(probability[i],probability[j]); max = MAX(probability[i],probability[j]); if (0.5*(min+max) >= fraction) continue; } // if newton_bond is set, only store with I or J // if not newton_bond, store bond with both I and J if (!newton_bond || tag[i] < tag[j]) { if (num_bond[i] == atom->bond_per_atom) error->one("New bond exceeded bonds per atom in fix bond/create"); bond_type[i][num_bond[i]] = btype; bond_atom[i][num_bond[i]] = tag[j]; num_bond[i]++; } // add a 1-2 neighbor to special bond list for atom I // atom J will also do this slist = atom->special[i]; n1 = nspecial[i][0]; n3 = nspecial[i][2]; if (n3 == atom->maxspecial) error->one("New bond exceeded special list size in fix bond/create"); for (m = n3; m > n1; m--) slist[m+1] = slist[m]; slist[n1] = tag[j]; nspecial[i][0]++; nspecial[i][1]++; nspecial[i][2]++; // increment bondcount, convert atom to new type if limit reached bondcount[i]++; if (type[i] == iatomtype) { if (bondcount[i] == imaxbond) type[i] = inewtype; } else { if (bondcount[i] == jmaxbond) type[i] = jnewtype; } // count the created bond once if (tag[i] < tag[j]) ncreate++; } // tally stats MPI_Allreduce(&ncreate,&createcount,1,MPI_INT,MPI_SUM,world); createcounttotal += createcount; atom->nbonds += createcount; // trigger reneighboring if any bonds were formed if (createcount) next_reneighbor = update->ntimestep; } /* ---------------------------------------------------------------------- */ void FixBondCreate::post_integrate_respa(int ilevel, int iloop) { if (ilevel == nlevels_respa-1) post_integrate(); } /* ---------------------------------------------------------------------- */ int FixBondCreate::pack_comm(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; m = 0; if (commflag == 0) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = bondcount[j]; } return 1; } else { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = partner[j]; buf[m++] = probability[j]; } return 2; } } /* ---------------------------------------------------------------------- */ void FixBondCreate::unpack_comm(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; if (commflag == 0) { for (i = first; i < last; i++) bondcount[i] = static_cast (buf[m++]); } else { for (i = first; i < last; i++) { partner[i] = static_cast (buf[m++]); probability[i] = buf[m++]; } } } /* ---------------------------------------------------------------------- */ int FixBondCreate::pack_reverse_comm(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; if (commflag == 0) { for (i = first; i < last; i++) buf[m++] = bondcount[i]; return 1; } else { for (i = first; i < last; i++) { buf[m++] = distsq[i]; buf[m++] = partner[i]; } return 2; } } /* ---------------------------------------------------------------------- */ void FixBondCreate::unpack_reverse_comm(int n, int *list, double *buf) { int i,j,m; m = 0; if (commflag == 0) { for (i = 0; i < n; i++) { j = list[i]; bondcount[j] += static_cast (buf[m++]); } } else { for (i = 0; i < n; i++) { j = list[i]; if (buf[m] < distsq[j]) { distsq[j] = buf[m++]; partner[j] = static_cast (buf[m++]); } else m += 2; } } } /* ---------------------------------------------------------------------- allocate local atom-based arrays ------------------------------------------------------------------------- */ void FixBondCreate::grow_arrays(int nmax) { memory->grow(bondcount,nmax,"bond/create:bondcount"); } /* ---------------------------------------------------------------------- copy values within local atom-based arrays ------------------------------------------------------------------------- */ void FixBondCreate::copy_arrays(int i, int j) { bondcount[j] = bondcount[i]; } /* ---------------------------------------------------------------------- pack values in local atom-based arrays for exchange with another proc ------------------------------------------------------------------------- */ int FixBondCreate::pack_exchange(int i, double *buf) { buf[0] = bondcount[i]; return 1; } /* ---------------------------------------------------------------------- unpack values in local atom-based arrays from exchange with another proc ------------------------------------------------------------------------- */ int FixBondCreate::unpack_exchange(int nlocal, double *buf) { bondcount[nlocal] = static_cast (buf[0]); return 1; } /* ---------------------------------------------------------------------- */ double FixBondCreate::compute_vector(int n) { if (n == 1) return (double) createcount; return (double) createcounttotal; } /* ---------------------------------------------------------------------- memory usage of local atom-based arrays ------------------------------------------------------------------------- */ double FixBondCreate::memory_usage() { int nmax = atom->nmax; double bytes = nmax*2 * sizeof(int); bytes += nmax * sizeof(double); return bytes; } diff --git a/src/MOLECULE/fix_bond_swap.cpp b/src/MOLECULE/fix_bond_swap.cpp index cc49eb7c9..daf9b1350 100644 --- a/src/MOLECULE/fix_bond_swap.cpp +++ b/src/MOLECULE/fix_bond_swap.cpp @@ -1,688 +1,689 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "math.h" #include "stdlib.h" #include "string.h" #include "fix_bond_swap.h" #include "atom.h" #include "force.h" #include "pair.h" #include "bond.h" #include "angle.h" #include "neighbor.h" #include "neigh_list.h" #include "neigh_request.h" #include "group.h" #include "comm.h" #include "domain.h" #include "modify.h" #include "compute.h" #include "random_mars.h" #include "memory.h" #include "error.h" #include "update.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ FixBondSwap::FixBondSwap(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg) { if (narg != 6) error->all("Illegal fix bond/swap command"); vector_flag = 1; size_vector = 2; global_freq = 1; extvector = 0; fraction = atof(arg[3]); double cutoff = atof(arg[4]); cutsq = cutoff*cutoff; // initialize Marsaglia RNG with processor-unique seed int seed = atoi(arg[5]); random = new RanMars(lmp,seed + comm->me); // create a new compute temp style // id = fix-ID + temp, compute group = fix group int n = strlen(id) + 6; id_temp = new char[n]; strcpy(id_temp,id); strcat(id_temp,"_temp"); char **newarg = new char*[3]; newarg[0] = id_temp; newarg[1] = "all"; newarg[2] = "temp"; modify->add_compute(3,newarg); delete [] newarg; tflag = 1; // initialize atom list nmax = 0; alist = NULL; naccept = foursome = 0; } /* ---------------------------------------------------------------------- */ FixBondSwap::~FixBondSwap() { delete random; // delete temperature if fix created it if (tflag) modify->delete_compute(id_temp); delete [] id_temp; memory->destroy(alist); } /* ---------------------------------------------------------------------- */ int FixBondSwap::setmask() { int mask = 0; mask |= PRE_NEIGHBOR; return mask; } /* ---------------------------------------------------------------------- */ void FixBondSwap::init() { // require an atom style with molecule IDs if (atom->molecule == NULL) error->all("Must use atom style with molecule IDs with fix bond/swap"); int icompute = modify->find_compute(id_temp); if (icompute < 0) error->all("Temperature ID for fix bond/swap does not exist"); temperature = modify->compute[icompute]; // pair and bonds must be defined // no dihedral or improper potentials allowed // special bonds must be 0 1 1 if (force->pair == NULL || force->bond == NULL) error->all("Fix bond/swap requires pair and bond styles"); if (force->pair->single_enable == 0) error->all("Pair style does not support fix bond/swap"); if (force->angle == NULL && atom->nangles > 0 && comm->me == 0) error->warning("Fix bond/swap will ignore defined angles"); if (force->dihedral || force->improper) error->all("Fix bond/swap cannot use dihedral or improper styles"); if (force->special_lj[1] != 0.0 || force->special_lj[2] != 1.0 || force->special_lj[3] != 1.0) error->all("Fix bond/swap requires special_bonds = 0,1,1"); // need a half neighbor list, built when ever re-neighboring occurs int irequest = neighbor->request((void *) this); neighbor->requests[irequest]->pair = 0; neighbor->requests[irequest]->fix = 1; // zero out stats naccept = foursome = 0; angleflag = 0; if (force->angle) angleflag = 1; } /* ---------------------------------------------------------------------- */ void FixBondSwap::init_list(int id, NeighList *ptr) { list = ptr; } /* ---------------------------------------------------------------------- */ void FixBondSwap::pre_neighbor() { int i,j,ii,jj,m,inum,jnum; int inext,iprev,ilast,jnext,jprev,jlast,ibond,iangle,jbond,jangle; int itag,inexttag,iprevtag,ilasttag,jtag,jnexttag,jprevtag,jlasttag; int ibondtype,jbondtype,iangletype,inextangletype,jangletype,jnextangletype; int i1,i2,i3,j1,j2,j3,tmp; int *ilist,*jlist,*numneigh,**firstneigh; double delta,factor; // compute current temp for Boltzmann factor test double t_current = temperature->compute_scalar(); // local ptrs to atom arrays int *tag = atom->tag; int *mask = atom->mask; int *molecule = atom->molecule; int *num_bond = atom->num_bond; int **bond_atom = atom->bond_atom; int **bond_type = atom->bond_type; int *num_angle = atom->num_angle; int **angle_atom1 = atom->angle_atom1; int **angle_atom2 = atom->angle_atom2; int **angle_atom3 = atom->angle_atom3; int **angle_type = atom->angle_type; int **nspecial = atom->nspecial; int **special = atom->special; int newton_bond = force->newton_bond; int nlocal = atom->nlocal; type = atom->type; x = atom->x; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // randomize list of my owned atoms that are in fix group // grow atom list if necessary if (nlocal > nmax) { memory->destroy(alist); nmax = atom->nmax; memory->create(alist,nmax,"bondswap:alist"); } int neligible = 0; for (ii = 0; ii < inum; ii++) { i = ilist[ii]; if (mask[i] & groupbit) alist[neligible++] = i; } for (i = 0; i < neligible; i++) { j = static_cast (random->uniform() * neligible); tmp = alist[i]; alist[i] = alist[j]; alist[j] = tmp; } // examine ntest of my eligible atoms for potential swaps // atom i is randomly selected via atom list // look at all j neighbors of atom i // atom j must be on-processor (j < nlocal) // atom j must be in fix group // i and j must be same distance from chain end (mol[i] = mol[j]) // NOTE: must use extra parens in if test on mask[j] & groupbit int ntest = static_cast (fraction * neligible); int accept = 0; for (int itest = 0; itest < ntest; itest++) { i = alist[itest]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; + j &= NEIGHMASK; if (j >= nlocal) continue; if ((mask[j] & groupbit) == 0) continue; if (molecule[i] != molecule[j]) continue; // look at all bond partners of atoms i and j // use num_bond for this, not special list, so also find bondtypes // inext,jnext = bonded atoms // inext,jnext must be on-processor (inext,jnext < nlocal) // inext,jnext must be same dist from chain end (mol[inext] = mol[jnext]) // since swaps may occur between two ends of a single chain, insure // the 4 atoms are unique (no duplicates): inext != jnext, inext != j // all 4 old and new bonds must have length < cutoff for (ibond = 0; ibond < num_bond[i]; ibond++) { inext = atom->map(bond_atom[i][ibond]); if (inext >= nlocal || inext < 0) continue; ibondtype = bond_type[i][ibond]; for (jbond = 0; jbond < num_bond[j]; jbond++) { jnext = atom->map(bond_atom[j][jbond]); if (jnext >= nlocal || jnext < 0) continue; jbondtype = bond_type[j][jbond]; if (molecule[inext] != molecule[jnext]) continue; if (inext == jnext || inext == j) continue; if (dist_rsq(i,inext) >= cutsq) continue; if (dist_rsq(j,jnext) >= cutsq) continue; if (dist_rsq(i,jnext) >= cutsq) continue; if (dist_rsq(j,inext) >= cutsq) continue; // if angles are enabled: // find other atoms i,inext,j,jnext are in angles with // and angletypes: i/j angletype, i/j nextangletype // use num_angle for this, not special list, so also find angletypes // 4 atoms consecutively along 1st chain: iprev,i,inext,ilast // 4 atoms consecutively along 2nd chain: jprev,j,jnext,jlast // prev or last atom can be non-existent at end of chain // set prev/last = -1 in this case // if newton bond = 0, then angles are stored by all 4 atoms // so require that iprev,ilast,jprev,jlast be owned by this proc // so all copies of angles can be updated if a swap takes place if (angleflag) { itag = tag[i]; inexttag = tag[inext]; jtag = tag[j]; jnexttag = tag[jnext]; iprev = -1; for (iangle = 0; iangle < num_angle[i]; iangle++) { i1 = angle_atom1[i][iangle]; i2 = angle_atom2[i][iangle]; i3 = angle_atom3[i][iangle]; if (i2 == itag && i3 == inexttag) iprev = atom->map(i1); else if (i1 == inexttag && i2 == itag) iprev = atom->map(i3); if (iprev >= 0) { iangletype = angle_type[i][iangle]; break; } } if (!newton_bond && iprev >= nlocal) continue; ilast = -1; for (iangle = 0; iangle < num_angle[inext]; iangle++) { i1 = angle_atom1[inext][iangle]; i2 = angle_atom2[inext][iangle]; i3 = angle_atom3[inext][iangle]; if (i1 == itag && i2 == inexttag) ilast = atom->map(i3); else if (i2 == inexttag && i3 == itag) ilast = atom->map(i1); if (ilast >= 0) { inextangletype = angle_type[inext][iangle]; break; } } if (!newton_bond && ilast >= nlocal) continue; jprev = -1; for (jangle = 0; jangle < num_angle[j]; jangle++) { j1 = angle_atom1[j][jangle]; j2 = angle_atom2[j][jangle]; j3 = angle_atom3[j][jangle]; if (j2 == jtag && j3 == jnexttag) jprev = atom->map(j1); else if (j1 == jnexttag && j2 == jtag) jprev = atom->map(j3); if (jprev >= 0) { jangletype = angle_type[j][jangle]; break; } } if (!newton_bond && jprev >= nlocal) continue; jlast = -1; for (jangle = 0; jangle < num_angle[jnext]; jangle++) { j1 = angle_atom1[jnext][jangle]; j2 = angle_atom2[jnext][jangle]; j3 = angle_atom3[jnext][jangle]; if (j1 == jtag && j2 == jnexttag) jlast = atom->map(j3); else if (j2 == jnexttag && j3 == jtag) jlast = atom->map(j1); if (jlast >= 0) { jnextangletype = angle_type[jnext][jangle]; break; } } if (!newton_bond && jlast >= nlocal) continue; } // valid foursome found between 2 chains: // chains = iprev-i-inext-ilast and jprev-j-jnext-jlast // prev or last values are -1 if do not exist due to end of chain // OK to call angle_eng with -1 atom, since just return 0.0 // current energy of foursome = // E_nb(i,j) + E_nb(i,jnext) + E_nb(inext,j) + E_nb(inext,jnext) + // E_bond(i,inext) + E_bond(j,jnext) + // E_angle(iprev,i,inext) + E_angle(i,inext,ilast) + // E_angle(jprev,j,jnext) + E_angle(j,jnext,jlast) // new energy of foursome with swapped bonds = // E_nb(i,j) + E_nb(i,inext) + E_nb(j,jnext) + E_nb(inext,jnext) + // E_bond(i,jnext) + E_bond(j,inext) + // E_angle(iprev,i,jnext) + E_angle(i,jnext,jlast) + // E_angle(jprev,j,inext) + E_angle(j,inext,ilast) // energy delta = add/subtract differing terms between 2 formulas foursome++; delta = pair_eng(i,inext) + pair_eng(j,jnext) - pair_eng(i,jnext) - pair_eng(inext,j); delta += bond_eng(ibondtype,i,jnext) + bond_eng(jbondtype,j,inext) - bond_eng(ibondtype,i,inext) - bond_eng(jbondtype,j,jnext); if (angleflag) delta += angle_eng(iangletype,iprev,i,jnext) + angle_eng(jnextangletype,i,jnext,jlast) + angle_eng(jangletype,jprev,j,inext) + angle_eng(inextangletype,j,inext,ilast) - angle_eng(iangletype,iprev,i,inext) - angle_eng(inextangletype,i,inext,ilast) - angle_eng(jangletype,jprev,j,jnext) - angle_eng(jnextangletype,j,jnext,jlast); // if delta <= 0, accept swap // if delta > 0, compute Boltzmann factor with current temperature // only accept if greater than random value // whether accept or not, exit test loop if (delta < 0.0) accept = 1; else { factor = exp(-delta/force->boltz/t_current); if (random->uniform() < factor) accept = 1; } goto done; } } } } done: if (!accept) return; naccept++; // change bond partners of affected atoms // on atom i: bond i-inext changes to i-jnext // on atom j: bond j-jnext changes to j-inext // on atom inext: bond inext-i changes to inext-j // on atom jnext: bond jnext-j changes to jnext-i for (ibond = 0; ibond < num_bond[i]; ibond++) if (bond_atom[i][ibond] == tag[inext]) bond_atom[i][ibond] = tag[jnext]; for (jbond = 0; jbond < num_bond[j]; jbond++) if (bond_atom[j][jbond] == tag[jnext]) bond_atom[j][jbond] = tag[inext]; for (ibond = 0; ibond < num_bond[inext]; ibond++) if (bond_atom[inext][ibond] == tag[i]) bond_atom[inext][ibond] = tag[j]; for (jbond = 0; jbond < num_bond[jnext]; jbond++) if (bond_atom[jnext][jbond] == tag[j]) bond_atom[jnext][jbond] = tag[i]; // set global tags of 4 atoms in bonds itag = tag[i]; inexttag = tag[inext]; jtag = tag[j]; jnexttag = tag[jnext]; // change 1st special neighbors of affected atoms: i,j,inext,jnext // don't need to change 2nd/3rd special neighbors for any atom // since special bonds = 0 1 1 means they are never used for (m = 0; m < nspecial[i][0]; m++) if (special[i][m] == inexttag) special[i][m] = jnexttag; for (m = 0; m < nspecial[j][0]; m++) if (special[j][m] == jnexttag) special[j][m] = inexttag; for (m = 0; m < nspecial[inext][0]; m++) if (special[inext][m] == itag) special[inext][m] = jtag; for (m = 0; m < nspecial[jnext][0]; m++) if (special[jnext][m] == jtag) special[jnext][m] = itag; // done if no angles if (!angleflag) return; // set global tags of 4 additional atoms in angles, 0 if no angle if (iprev >= 0) iprevtag = tag[iprev]; else iprevtag = 0; if (ilast >= 0) ilasttag = tag[ilast]; else ilasttag = 0; if (jprev >= 0) jprevtag = tag[jprev]; else jprevtag = 0; if (jlast >= 0) jlasttag = tag[jlast]; else jlasttag = 0; // change angle partners of affected atoms // must check if each angle is stored as a-b-c or c-b-a // on atom i: // angle iprev-i-inext changes to iprev-i-jnext // angle i-inext-ilast changes to i-jnext-jlast // on atom j: // angle jprev-j-jnext changes to jprev-j-inext // angle j-jnext-jlast changes to j-inext-ilast // on atom inext: // angle iprev-i-inext changes to jprev-j-inext // angle i-inext-ilast changes to j-inext-ilast // on atom jnext: // angle jprev-j-jnext changes to iprev-i-jnext // angle j-jnext-jlast changes to i-jnext-jlast for (iangle = 0; iangle < num_angle[i]; iangle++) { i1 = angle_atom1[i][iangle]; i2 = angle_atom2[i][iangle]; i3 = angle_atom3[i][iangle]; if (i1 == iprevtag && i2 == itag && i3 == inexttag) angle_atom3[i][iangle] = jnexttag; else if (i1 == inexttag && i2 == itag && i3 == iprevtag) angle_atom1[i][iangle] = jnexttag; else if (i1 == itag && i2 == inexttag && i3 == ilasttag) { angle_atom2[i][iangle] = jnexttag; angle_atom3[i][iangle] = jlasttag; } else if (i1 == ilasttag && i2 == inexttag && i3 == itag) { angle_atom1[i][iangle] = jlasttag; angle_atom2[i][iangle] = jnexttag; } } for (jangle = 0; jangle < num_angle[j]; jangle++) { j1 = angle_atom1[j][jangle]; j2 = angle_atom2[j][jangle]; j3 = angle_atom3[j][jangle]; if (j1 == jprevtag && j2 == jtag && j3 == jnexttag) angle_atom3[j][jangle] = inexttag; else if (j1 == jnexttag && j2 == jtag && j3 == jprevtag) angle_atom1[j][jangle] = inexttag; else if (j1 == jtag && j2 == jnexttag && j3 == jlasttag) { angle_atom2[j][jangle] = inexttag; angle_atom3[j][jangle] = ilasttag; } else if (j1 == jlasttag && j2 == jnexttag && j3 == jtag) { angle_atom1[j][jangle] = ilasttag; angle_atom2[j][jangle] = inexttag; } } for (iangle = 0; iangle < num_angle[inext]; iangle++) { i1 = angle_atom1[inext][iangle]; i2 = angle_atom2[inext][iangle]; i3 = angle_atom3[inext][iangle]; if (i1 == iprevtag && i2 == itag && i3 == inexttag) { angle_atom1[inext][iangle] = jprevtag; angle_atom2[inext][iangle] = jtag; } else if (i1 == inexttag && i2 == itag && i3 == iprevtag) { angle_atom2[inext][iangle] = jtag; angle_atom3[inext][iangle] = jprevtag; } else if (i1 == itag && i2 == inexttag && i3 == ilasttag) angle_atom1[inext][iangle] = jtag; else if (i1 == ilasttag && i2 == inexttag && i3 == itag) angle_atom3[inext][iangle] = jtag; } for (jangle = 0; jangle < num_angle[jnext]; jangle++) { j1 = angle_atom1[jnext][jangle]; j2 = angle_atom2[jnext][jangle]; j3 = angle_atom3[jnext][jangle]; if (j1 == jprevtag && j2 == jtag && j3 == jnexttag) { angle_atom1[jnext][jangle] = iprevtag; angle_atom2[jnext][jangle] = itag; } else if (j1 == jnexttag && j2 == jtag && j3 == jprevtag) { angle_atom2[jnext][jangle] = itag; angle_atom3[jnext][jangle] = iprevtag; } else if (j1 == jtag && j2 == jnexttag && j3 == jlasttag) angle_atom1[jnext][jangle] = itag; else if (j1 == jlasttag && j2 == jnexttag && j3 == jtag) angle_atom3[jnext][jangle] = itag; } // done if newton bond set if (newton_bond) return; // change angles stored by iprev,ilast,jprev,jlast // on atom iprev: angle iprev-i-inext changes to iprev-i-jnext // on atom jprev: angle jprev-j-jnext changes to jprev-j-inext // on atom ilast: angle i-inext-ilast changes to j-inext-ilast // on atom jlast: angle j-jnext-jlast changes to i-jnext-jlast for (iangle = 0; iangle < num_angle[iprev]; iangle++) { i1 = angle_atom1[iprev][iangle]; i2 = angle_atom2[iprev][iangle]; i3 = angle_atom3[iprev][iangle]; if (i1 == iprevtag && i2 == itag && i3 == inexttag) angle_atom3[iprev][iangle] = jnexttag; else if (i1 == inexttag && i2 == itag && i3 == iprevtag) angle_atom1[iprev][iangle] = jnexttag; } for (jangle = 0; jangle < num_angle[jprev]; jangle++) { j1 = angle_atom1[jprev][jangle]; j2 = angle_atom2[jprev][jangle]; j3 = angle_atom3[jprev][jangle]; if (j1 == jprevtag && j2 == jtag && j3 == jnexttag) angle_atom3[jprev][jangle] = inexttag; else if (j1 == jnexttag && j2 == jtag && j3 == jprevtag) angle_atom1[jprev][jangle] = inexttag; } for (iangle = 0; iangle < num_angle[ilast]; iangle++) { i1 = angle_atom1[ilast][iangle]; i2 = angle_atom2[ilast][iangle]; i3 = angle_atom3[ilast][iangle]; if (i1 == itag && i2 == inexttag && i3 == ilasttag) angle_atom1[ilast][iangle] = jtag; else if (i1 == ilasttag && i2 == inexttag && i3 == itag) angle_atom3[ilast][iangle] = jtag; } for (jangle = 0; jangle < num_angle[jlast]; jangle++) { j1 = angle_atom1[jlast][jangle]; j2 = angle_atom2[jlast][jangle]; j3 = angle_atom3[jlast][jangle]; if (j1 == jtag && j2 == jnexttag && j3 == jlasttag) angle_atom1[jlast][jangle] = itag; else if (j1 == jlasttag && j2 == jnexttag && j3 == jtag) angle_atom3[jlast][jangle] = itag; } } /* ---------------------------------------------------------------------- */ int FixBondSwap::modify_param(int narg, char **arg) { if (strcmp(arg[0],"temp") == 0) { if (narg < 2) error->all("Illegal fix_modify command"); if (tflag) { modify->delete_compute(id_temp); tflag = 0; } delete [] id_temp; int n = strlen(arg[1]) + 1; id_temp = new char[n]; strcpy(id_temp,arg[1]); int icompute = modify->find_compute(id_temp); if (icompute < 0) error->all("Could not find fix_modify temperature ID"); temperature = modify->compute[icompute]; if (temperature->tempflag == 0) error->all("Fix_modify temperature ID does not compute temperature"); if (temperature->igroup != igroup && comm->me == 0) error->warning("Group for fix_modify temp != fix group"); return 2; } return 0; } /* ---------------------------------------------------------------------- compute squared distance between atoms I,J must use minimum_image since J was found thru atom->map() ------------------------------------------------------------------------- */ double FixBondSwap::dist_rsq(int i, int j) { double delx = x[i][0] - x[j][0]; double dely = x[i][1] - x[j][1]; double delz = x[i][2] - x[j][2]; domain->minimum_image(delx,dely,delz); return (delx*delx + dely*dely + delz*delz); } /* ---------------------------------------------------------------------- return pairwise interaction energy between atoms I,J will always be full non-bond interaction, so factors = 1 in single() call ------------------------------------------------------------------------- */ double FixBondSwap::pair_eng(int i, int j) { double tmp; double rsq = dist_rsq(i,j); return force->pair->single(i,j,type[i],type[j],rsq,1.0,1.0,tmp); } /* ---------------------------------------------------------------------- */ double FixBondSwap::bond_eng(int btype, int i, int j) { double rsq = dist_rsq(i,j); return force->bond->single(btype,rsq,i,j); } /* ---------------------------------------------------------------------- */ double FixBondSwap::angle_eng(int atype, int i, int j, int k) { // test for non-existent angle at end of chain if (i == -1 || k == -1) return 0.0; return force->angle->single(atype,i,j,k); } /* ---------------------------------------------------------------------- return bond swapping stats n = 1 is # of swaps n = 2 is # of attempted swaps ------------------------------------------------------------------------- */ double FixBondSwap::compute_vector(int n) { double one,all; if (n == 0) one = naccept; else one = foursome; MPI_Allreduce(&one,&all,1,MPI_DOUBLE,MPI_SUM,world); return all; } /* ---------------------------------------------------------------------- memory usage of alist ------------------------------------------------------------------------- */ double FixBondSwap::memory_usage() { double bytes = nmax * sizeof(int); return bytes; } diff --git a/src/MOLECULE/pair_hbond_dreiding_lj.cpp b/src/MOLECULE/pair_hbond_dreiding_lj.cpp index b97e2969c..81eb85005 100644 --- a/src/MOLECULE/pair_hbond_dreiding_lj.cpp +++ b/src/MOLECULE/pair_hbond_dreiding_lj.cpp @@ -1,417 +1,414 @@ /* ---------------------------------------------------------------------- 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 "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "pair_hbond_dreiding_lj.h" #include "atom.h" #include "comm.h" #include "force.h" #include "neighbor.h" #include "neigh_request.h" #include "neigh_list.h" #include "memory.h" #include "error.h" #include "domain.h" using namespace LAMMPS_NS; #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define SMALL 0.001 #define CHUNK 8 /* ---------------------------------------------------------------------- */ PairHbondDreidingLJ::PairHbondDreidingLJ(LAMMPS *lmp) : Pair(lmp) { single_enable = 0; // 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_compute = 1; PI = 4.0*atan(1.0); nparams = maxparam = 0; params = NULL; nextra = 1; pvector = new double[1]; } /* ---------------------------------------------------------------------- */ 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; double delx,dely,delz,rsq,rsq1,rsq2,r1,r2; double factor_hb,force_angle,force_kernel,evdwl; double c,s,a,b,ac,a11,a12,a22,vx1,vx2,vy1,vy2,vz1,vz2; double fi[3],fj[3],delr1[3],delr2[3]; double r2inv,r10inv; int *ilist,*jlist,*klist,*numneigh,**firstneigh; Param *pm; evdwl = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; double **x = atom->x; double **f = atom->f; int **special = atom->special; int *type = atom->type; int **nspecial = atom->nspecial; int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; double *special_lj = force->special_lj; 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; klist = special[i]; knum = nspecial[i][0]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; - if (j < nall) factor_hb = 1.0; - else { - factor_hb = special_lj[j/nall]; - j %= nall; - } + 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++) { k = atom->map(klist[kk]); if (k < 0) continue; ktype = type[k]; m = type2param[itype][jtype][ktype]; if (m < 0) continue; pm = ¶ms[m]; if (rsq < pm->cutsq) { 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*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 * pow(c,pm->ap); force_angle = pm->ap * r10inv*(pm->lj3*r2inv - pm->lj4) * pow(c,pm->ap-1)*s; if (eflag) { evdwl = r10inv*(pm->lj3*r2inv - pm->lj4) * pow(c,pm->ap) - pm->offset; evdwl *= factor_hb; } a = factor_hb*force_angle/s; b = factor_hb*force_kernel; 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; fi[1] = vy1 + b*dely; fi[2] = vz1 + b*delz; fj[0] = vx2 - b*delx; fj[1] = vy2 - b*dely; fj[2] = vz2 - b*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; } /* ---------------------------------------------------------------------- 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 != 3) error->all("Illegal pair_style command"); ap_global = force->inumeric(arg[0]); cut_global = force->numeric(arg[1]); cut_angle_global = force->numeric(arg[2]) * PI/180.0; } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairHbondDreidingLJ::coeff(int narg, char **arg) { if (narg < 6 || narg > 9) error->all("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); 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("Incorrect args for pair coefficients"); double epsilon_one = force->numeric(arg[4]); double sigma_one = force->numeric(arg[5]); int ap_one = ap_global; if (narg == 7) ap_one = force->inumeric(arg[6]); double cut_one = cut_global; if (narg == 8) cut_one = force->numeric(arg[7]); double cut_angle_one = cut_angle_global; if (narg == 9) cut_angle_one = force->numeric(arg[8]) * 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 = cut_one; params[nparams].cutsq = cut_one*cut_one; params[nparams].cut_angle = cut_angle_one; // 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("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("Pair style hbond/dreiding requires molecular system"); if (atom->tag_enable == 0) error->all("Pair style hbond/dreiding requires atom IDs"); if (atom->map_style == 0) error->all("Pair style hbond/dreiding requires an atom map, " "see atom_modify"); if (force->newton_pair == 0) error->all("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("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; 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); 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); m = type2param[j][i][k]; if (m >= 0) cut = MAX(cut,params[m].cut); } return cut; } diff --git a/src/MOLECULE/pair_hbond_dreiding_morse.cpp b/src/MOLECULE/pair_hbond_dreiding_morse.cpp index 084d84c5d..2740e1b61 100644 --- a/src/MOLECULE/pair_hbond_dreiding_morse.cpp +++ b/src/MOLECULE/pair_hbond_dreiding_morse.cpp @@ -1,318 +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: Tod A Pascal (Caltech) ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "pair_hbond_dreiding_morse.h" #include "atom.h" #include "comm.h" #include "force.h" #include "neighbor.h" #include "neigh_request.h" #include "neigh_list.h" #include "memory.h" #include "error.h" #include "domain.h" using namespace LAMMPS_NS; #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) #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; double delx,dely,delz,rsq,rsq1,rsq2,r1,r2; double factor_hb,force_angle,force_kernel,evdwl; double c,s,a,b,ac,a11,a12,a22,vx1,vx2,vy1,vy2,vz1,vz2; double fi[3],fj[3],delr1[3],delr2[3]; double r,dr,dexp,emorse; int *ilist,*jlist,*klist,*numneigh,**firstneigh; Param *pm; evdwl = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; double **x = atom->x; double **f = atom->f; int **special = atom->special; int *type = atom->type; int **nspecial = atom->nspecial; int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; double *special_lj = force->special_lj; 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; klist = special[i]; knum = nspecial[i][0]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; - if (j < nall) factor_hb = 1.0; - else { - factor_hb = special_lj[j/nall]; - j %= nall; - } + 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++) { k = atom->map(klist[kk]); if (k < 0) continue; ktype = type[k]; m = type2param[itype][jtype][ktype]; if (m < 0) continue; pm = ¶ms[m]; if (rsq < pm->cutsq) { 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*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); force_kernel = pm->morse1*(dexp*dexp - dexp)/r * pow(c,pm->ap); emorse = pm->d0 * (dexp*dexp - 2.0*dexp) - pm->offset; force_angle = pm->ap * emorse * pow(c,pm->ap-1)*s; if (eflag) { evdwl = emorse * pow(c,params[m].ap); evdwl *= factor_hb; } a = factor_hb*force_angle/s; b = factor_hb*force_kernel; 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; fi[1] = vy1 + b*dely; fi[2] = vz1 + b*delz; fj[0] = vx2 - b*delx; fj[1] = vy2 - b*dely; fj[2] = vz2 - b*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++; } } } } } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairHbondDreidingMorse::coeff(int narg, char **arg) { if (narg < 7 || narg > 10) error->all("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); 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("Incorrect args for pair coefficients"); double d0_one = force->numeric(arg[4]); double alpha_one = force->numeric(arg[5]); double r0_one = force->numeric(arg[6]); int ap_one = ap_global; if (narg == 8) ap_one = force->inumeric(arg[7]); double cut_one = cut_global; if (narg == 9) cut_one = force->numeric(arg[8]); double cut_angle_one = cut_angle_global; if (narg == 10) cut_angle_one = force->numeric(arg[9]) * 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 = cut_one; params[nparams].cutsq = cut_one*cut_one; params[nparams].cut_angle = cut_angle_one; // 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("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("Pair style hbond/dreiding requires molecular system"); if (atom->tag_enable == 0) error->all("Pair style hbond/dreiding requires atom IDs"); if (atom->map_style == 0) error->all("Pair style hbond/dreiding requires an atom map, " "see atom_modify"); if (force->newton_pair == 0) error->all("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("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); neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->full = 1; } diff --git a/src/MOLECULE/pair_lj_charmm_coul_charmm.cpp b/src/MOLECULE/pair_lj_charmm_coul_charmm.cpp index b8f2ffa62..bf8e713a0 100644 --- a/src/MOLECULE/pair_lj_charmm_coul_charmm.cpp +++ b/src/MOLECULE/pair_lj_charmm_coul_charmm.cpp @@ -1,515 +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: Paul Crozier (SNL) ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "pair_lj_charmm_coul_charmm.h" #include "atom.h" #include "comm.h" #include "force.h" #include "neighbor.h" #include "neigh_list.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; enum{GEOMETRIC,ARITHMETIC,SIXTHPOWER}; // same as in pair.cpp #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) /* ---------------------------------------------------------------------- */ PairLJCharmmCoulCharmm::PairLJCharmmCoulCharmm(LAMMPS *lmp) : Pair(lmp) { implicit = 0; mix_flag = ARITHMETIC; } /* ---------------------------------------------------------------------- */ PairLJCharmmCoulCharmm::~PairLJCharmmCoulCharmm() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(epsilon); memory->destroy(sigma); memory->destroy(eps14); memory->destroy(sigma14); memory->destroy(lj1); memory->destroy(lj2); memory->destroy(lj3); memory->destroy(lj4); memory->destroy(lj14_1); memory->destroy(lj14_2); memory->destroy(lj14_3); memory->destroy(lj14_4); } } /* ---------------------------------------------------------------------- */ void PairLJCharmmCoulCharmm::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair; double rsq,r2inv,r6inv,forcecoul,forcelj,factor_coul,factor_lj; double philj,switch1,switch2; int *ilist,*jlist,*numneigh,**firstneigh; evdwl = ecoul = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; double **x = atom->x; double **f = atom->f; double *q = atom->q; int *type = atom->type; int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; 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]; - - if (j < nall) factor_coul = factor_lj = 1.0; - else { - factor_coul = special_coul[j/nall]; - factor_lj = special_lj[j/nall]; - j %= nall; - } + factor_lj = special_lj[sbmask(j)]; + factor_coul = special_coul[sbmask(j)]; + j &= NEIGHMASK; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; if (rsq < cut_bothsq) { r2inv = 1.0/rsq; if (rsq < cut_coulsq) { forcecoul = qqrd2e * qtmp*q[j]*sqrt(r2inv); if (rsq > cut_coul_innersq) { switch1 = (cut_coulsq-rsq) * (cut_coulsq-rsq) * (cut_coulsq + 2.0*rsq - 3.0*cut_coul_innersq) / denom_coul; switch2 = 12.0*rsq * (cut_coulsq-rsq) * (rsq-cut_coul_innersq) / denom_coul; forcecoul *= switch1 + switch2; } } else forcecoul = 0.0; if (rsq < cut_ljsq) { r6inv = r2inv*r2inv*r2inv; jtype = type[j]; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); if (rsq > cut_lj_innersq) { switch1 = (cut_ljsq-rsq) * (cut_ljsq-rsq) * (cut_ljsq + 2.0*rsq - 3.0*cut_lj_innersq) / denom_lj; switch2 = 12.0*rsq * (cut_ljsq-rsq) * (rsq-cut_lj_innersq) / denom_lj; philj = r6inv * (lj3[itype][jtype]*r6inv - lj4[itype][jtype]); forcelj = forcelj*switch1 + philj*switch2; } } else forcelj = 0.0; fpair = (factor_coul*forcecoul + factor_lj*forcelj) * r2inv; f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; if (newton_pair || j < nlocal) { f[j][0] -= delx*fpair; f[j][1] -= dely*fpair; f[j][2] -= delz*fpair; } if (eflag) { if (rsq < cut_coulsq) { ecoul = qqrd2e * qtmp*q[j]*sqrt(r2inv); if (rsq > cut_coul_innersq) { switch1 = (cut_coulsq-rsq) * (cut_coulsq-rsq) * (cut_coulsq + 2.0*rsq - 3.0*cut_coul_innersq) / denom_coul; ecoul *= switch1; } ecoul *= factor_coul; } else ecoul = 0.0; if (rsq < cut_ljsq) { evdwl = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]); if (rsq > cut_lj_innersq) { switch1 = (cut_ljsq-rsq) * (cut_ljsq-rsq) * (cut_ljsq + 2.0*rsq - 3.0*cut_lj_innersq) / denom_lj; evdwl *= switch1; } evdwl *= factor_lj; } else evdwl = 0.0; } if (evflag) ev_tally(i,j,nlocal,newton_pair, evdwl,ecoul,fpair,delx,dely,delz); } } } if (vflag_fdotr) virial_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("Illegal pair_style command"); cut_lj_inner = force->numeric(arg[0]); cut_lj = force->numeric(arg[1]); if (narg == 2) { cut_coul_inner = cut_lj_inner; cut_coul = cut_lj; } else { cut_coul_inner = force->numeric(arg[2]); cut_coul = force->numeric(arg[3]); } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairLJCharmmCoulCharmm::coeff(int narg, char **arg) { if (narg != 4 && narg != 6) error->all("Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(arg[2]); double sigma_one = force->numeric(arg[3]); double eps14_one = epsilon_one; double sigma14_one = sigma_one; if (narg == 6) { eps14_one = force->numeric(arg[4]); sigma14_one = force->numeric(arg[5]); } int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { epsilon[i][j] = epsilon_one; sigma[i][j] = sigma_one; eps14[i][j] = eps14_one; sigma14[i][j] = sigma14_one; setflag[i][j] = 1; count++; } } if (count == 0) error->all("Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairLJCharmmCoulCharmm::init_style() { if (!atom->q_flag) error->all("Pair style lj/charmm/coul/charmm requires atom attribute q"); int irequest = neighbor->request(this); // require cut_lj_inner < cut_lj, cut_coul_inner < cut_coul if (cut_lj_inner >= cut_lj || cut_coul_inner >= cut_coul) error->all("Pair inner cutoff >= Pair outer cutoff"); cut_lj_innersq = cut_lj_inner * cut_lj_inner; cut_ljsq = cut_lj * cut_lj; cut_coul_innersq = cut_coul_inner * cut_coul_inner; cut_coulsq = cut_coul * cut_coul; cut_bothsq = MAX(cut_ljsq,cut_coulsq); denom_lj = (cut_ljsq-cut_lj_innersq) * (cut_ljsq-cut_lj_innersq) * (cut_ljsq-cut_lj_innersq); denom_coul = (cut_coulsq-cut_coul_innersq) * (cut_coulsq-cut_coul_innersq) * (cut_coulsq-cut_coul_innersq); } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairLJCharmmCoulCharmm::init_one(int i, int j) { if (setflag[i][j] == 0) { epsilon[i][j] = mix_energy(epsilon[i][i],epsilon[j][j], sigma[i][i],sigma[j][j]); sigma[i][j] = mix_distance(sigma[i][i],sigma[j][j]); eps14[i][j] = mix_energy(eps14[i][i],eps14[j][j], sigma14[i][i],sigma14[j][j]); sigma14[i][j] = mix_distance(sigma14[i][i],sigma14[j][j]); } double cut = MAX(cut_lj,cut_coul); lj1[i][j] = 48.0 * epsilon[i][j] * pow(sigma[i][j],12.0); lj2[i][j] = 24.0 * epsilon[i][j] * pow(sigma[i][j],6.0); lj3[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],12.0); lj4[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],6.0); lj14_1[i][j] = 48.0 * eps14[i][j] * pow(sigma14[i][j],12.0); lj14_2[i][j] = 24.0 * eps14[i][j] * pow(sigma14[i][j],6.0); lj14_3[i][j] = 4.0 * eps14[i][j] * pow(sigma14[i][j],12.0); lj14_4[i][j] = 4.0 * eps14[i][j] * pow(sigma14[i][j],6.0); lj1[j][i] = lj1[i][j]; lj2[j][i] = lj2[i][j]; lj3[j][i] = lj3[i][j]; lj4[j][i] = lj4[i][j]; lj14_1[j][i] = lj14_1[i][j]; lj14_2[j][i] = lj14_2[i][j]; lj14_3[j][i] = lj14_3[i][j]; lj14_4[j][i] = lj14_4[i][j]; return cut; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJCharmmCoulCharmm::write_restart(FILE *fp) { write_restart_settings(fp); int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { fwrite(&setflag[i][j],sizeof(int),1,fp); if (setflag[i][j]) { fwrite(&epsilon[i][j],sizeof(double),1,fp); fwrite(&sigma[i][j],sizeof(double),1,fp); fwrite(&eps14[i][j],sizeof(double),1,fp); fwrite(&sigma14[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJCharmmCoulCharmm::read_restart(FILE *fp) { read_restart_settings(fp); allocate(); int i,j; int me = comm->me; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp); MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world); if (setflag[i][j]) { if (me == 0) { fread(&epsilon[i][j],sizeof(double),1,fp); fread(&sigma[i][j],sizeof(double),1,fp); fread(&eps14[i][j],sizeof(double),1,fp); fread(&sigma14[i][j],sizeof(double),1,fp); } MPI_Bcast(&epsilon[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&eps14[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&sigma14[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJCharmmCoulCharmm::write_restart_settings(FILE *fp) { fwrite(&cut_lj_inner,sizeof(double),1,fp); fwrite(&cut_lj,sizeof(double),1,fp); fwrite(&cut_coul_inner,sizeof(double),1,fp); fwrite(&cut_coul,sizeof(double),1,fp); fwrite(&offset_flag,sizeof(int),1,fp); fwrite(&mix_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJCharmmCoulCharmm::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&cut_lj_inner,sizeof(double),1,fp); fread(&cut_lj,sizeof(double),1,fp); fread(&cut_coul_inner,sizeof(double),1,fp); fread(&cut_coul,sizeof(double),1,fp); fread(&offset_flag,sizeof(int),1,fp); fread(&mix_flag,sizeof(int),1,fp); } MPI_Bcast(&cut_lj_inner,1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_lj,1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_coul_inner,1,MPI_DOUBLE,0,world); MPI_Bcast(&cut_coul,1,MPI_DOUBLE,0,world); MPI_Bcast(&offset_flag,1,MPI_INT,0,world); MPI_Bcast(&mix_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- */ double PairLJCharmmCoulCharmm::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r2inv,r6inv,forcecoul,forcelj,phicoul,philj; double switch1,switch2; r2inv = 1.0/rsq; if (rsq < cut_coulsq) { forcecoul = force->qqrd2e * atom->q[i]*atom->q[j]*sqrt(r2inv); if (rsq > cut_coul_innersq) { switch1 = (cut_coulsq-rsq) * (cut_coulsq-rsq) * (cut_coulsq + 2.0*rsq - 3.0*cut_coul_innersq) / denom_coul; switch2 = 12.0*rsq * (cut_coulsq-rsq) * (rsq-cut_coul_innersq) / denom_coul; forcecoul *= switch1 + switch2; } } else forcecoul = 0.0; if (rsq < cut_ljsq) { r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); if (rsq > cut_lj_innersq) { switch1 = (cut_ljsq-rsq) * (cut_ljsq-rsq) * (cut_ljsq + 2.0*rsq - 3.0*cut_lj_innersq) / denom_lj; switch2 = 12.0*rsq * (cut_ljsq-rsq) * (rsq-cut_lj_innersq) / denom_lj; philj = r6inv * (lj3[itype][jtype]*r6inv - lj4[itype][jtype]); forcelj = forcelj*switch1 + philj*switch2; } } else forcelj = 0.0; fforce = (factor_coul*forcecoul + factor_lj*forcelj) * r2inv; double eng = 0.0; if (rsq < cut_coulsq) { phicoul = force->qqrd2e * atom->q[i]*atom->q[j]*sqrt(r2inv); if (rsq > cut_coul_innersq) { switch1 = (cut_coulsq-rsq) * (cut_coulsq-rsq) * (cut_coulsq + 2.0*rsq - 3.0*cut_coul_innersq) / denom_coul; phicoul *= switch1; } eng += factor_coul*phicoul; } if (rsq < cut_ljsq) { philj = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]); if (rsq > cut_lj_innersq) { switch1 = (cut_ljsq-rsq) * (cut_ljsq-rsq) * (cut_ljsq + 2.0*rsq - 3.0*cut_lj_innersq) / denom_lj; philj *= switch1; } eng += factor_lj*philj; } return eng; } /* ---------------------------------------------------------------------- */ void *PairLJCharmmCoulCharmm::extract(char *str, int &dim) { dim = 2; if (strcmp(str,"lj14_1") == 0) return (void *) lj14_1; if (strcmp(str,"lj14_2") == 0) return (void *) lj14_2; if (strcmp(str,"lj14_3") == 0) return (void *) lj14_3; if (strcmp(str,"lj14_4") == 0) return (void *) lj14_4; dim = 0; if (strcmp(str,"implicit") == 0) return (void *) &implicit; return NULL; } diff --git a/src/MOLECULE/pair_lj_charmm_coul_charmm_implicit.cpp b/src/MOLECULE/pair_lj_charmm_coul_charmm_implicit.cpp index d81b4f9d1..990392fa0 100644 --- a/src/MOLECULE/pair_lj_charmm_coul_charmm_implicit.cpp +++ b/src/MOLECULE/pair_lj_charmm_coul_charmm_implicit.cpp @@ -1,216 +1,211 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "math.h" #include "string.h" #include "pair_lj_charmm_coul_charmm_implicit.h" #include "atom.h" #include "force.h" #include "neigh_list.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ PairLJCharmmCoulCharmmImplicit::PairLJCharmmCoulCharmmImplicit(LAMMPS *lmp) : PairLJCharmmCoulCharmm(lmp) { implicit = 1; } /* ---------------------------------------------------------------------- */ void PairLJCharmmCoulCharmmImplicit::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; - int nall = nlocal + atom->nghost; 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]; - - if (j < nall) factor_coul = factor_lj = 1.0; - else { - factor_coul = special_coul[j/nall]; - factor_lj = special_lj[j/nall]; - j %= nall; - } + factor_lj = special_lj[sbmask(j)]; + factor_coul = special_coul[sbmask(j)]; + j &= NEIGHMASK; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; if (rsq < cut_bothsq) { r2inv = 1.0/rsq; if (rsq < cut_coulsq) { forcecoul = 2.0 * qqrd2e * qtmp*q[j]*r2inv; if (rsq > cut_coul_innersq) { switch1 = (cut_coulsq-rsq) * (cut_coulsq-rsq) * (cut_coulsq + 2.0*rsq - 3.0*cut_coul_innersq) / denom_coul; switch2 = 12.0*rsq * (cut_coulsq-rsq) * (rsq-cut_coul_innersq) / denom_coul; forcecoul *= switch1 + switch2; } } else forcecoul = 0.0; if (rsq < cut_ljsq) { r6inv = r2inv*r2inv*r2inv; jtype = type[j]; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); if (rsq > cut_lj_innersq) { switch1 = (cut_ljsq-rsq) * (cut_ljsq-rsq) * (cut_ljsq + 2.0*rsq - 3.0*cut_lj_innersq) / denom_lj; switch2 = 12.0*rsq * (cut_ljsq-rsq) * (rsq-cut_lj_innersq) / denom_lj; philj = r6inv * (lj3[itype][jtype]*r6inv - lj4[itype][jtype]); forcelj = forcelj*switch1 + philj*switch2; } } else forcelj = 0.0; fpair = (factor_coul*forcecoul + factor_lj*forcelj) * r2inv; f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; if (newton_pair || j < nlocal) { f[j][0] -= delx*fpair; f[j][1] -= dely*fpair; f[j][2] -= delz*fpair; } if (eflag) { if (rsq < cut_coulsq) { ecoul = qqrd2e * qtmp*q[j]*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_compute(); } /* ---------------------------------------------------------------------- */ double PairLJCharmmCoulCharmmImplicit::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r2inv,r6inv,switch1,switch2,forcecoul,forcelj,phicoul,philj; r2inv = 1.0/rsq; if (rsq < cut_coulsq) { forcecoul = 2.0 * force->qqrd2e * atom->q[i]*atom->q[j]*r2inv; if (rsq > cut_coul_innersq) { switch1 = (cut_coulsq-rsq) * (cut_coulsq-rsq) * (cut_coulsq + 2.0*rsq - 3.0*cut_coul_innersq) / denom_coul; switch2 = 12.0*rsq * (cut_coulsq-rsq) * (rsq-cut_coul_innersq) / denom_coul; forcecoul *= switch1 + switch2; } } else forcecoul = 0.0; if (rsq < cut_ljsq) { r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); if (rsq > cut_lj_innersq) { switch1 = (cut_ljsq-rsq) * (cut_ljsq-rsq) * (cut_ljsq + 2.0*rsq - 3.0*cut_lj_innersq) / denom_lj; switch2 = 12.0*rsq * (cut_ljsq-rsq) * (rsq-cut_lj_innersq) / denom_lj; philj = r6inv * (lj3[itype][jtype]*r6inv - lj4[itype][jtype]); forcelj = forcelj*switch1 + philj*switch2; } } else forcelj = 0.0; fforce = (factor_coul*forcecoul + factor_lj*forcelj) * r2inv; double eng = 0.0; if (rsq < cut_coulsq) { phicoul = force->qqrd2e * atom->q[i]*atom->q[j]*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; } diff --git a/src/OPT/pair_lj_charmm_coul_long_opt.h b/src/OPT/pair_lj_charmm_coul_long_opt.h index bc1171e5a..583f2d57e 100644 --- a/src/OPT/pair_lj_charmm_coul_long_opt.h +++ b/src/OPT/pair_lj_charmm_coul_long_opt.h @@ -1,347 +1,347 @@ /* ---------------------------------------------------------------------- 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 Fischer, High Performance Technologies, Inc. David Richie, Stone Ridge Technology Vincent Natol, Stone Ridge Technology ------------------------------------------------------------------------- */ #ifdef PAIR_CLASS PairStyle(lj/charmm/coul/long/opt,PairLJCharmmCoulLongOpt) #else #ifndef LMP_PAIR_LJ_CHARMM_COUL_LONG_OPT_H #define LMP_PAIR_LJ_CHARMM_COUL_LONG_OPT_H #include "math.h" #include "stdlib.h" #include "pair_lj_charmm_coul_long.h" #include "atom.h" #include "force.h" #include "neigh_list.h" namespace LAMMPS_NS { #define EWALD_F 1.12837917 #define EWALD_P 0.3275911 #define EWALD_A1 0.254829592 #define EWALD_A2 -0.284496736 #define EWALD_A3 1.421413741 #define EWALD_A4 -1.453152027 #define EWALD_A5 1.061405429 #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) class PairLJCharmmCoulLongOpt : public PairLJCharmmCoulLong { public: PairLJCharmmCoulLongOpt(class LAMMPS *); void compute(int, int); private: template < int EVFLAG, int EFLAG, int NEWTON_PAIR > void eval(); }; template < int EVFLAG, int EFLAG, int NEWTON_PAIR > void PairLJCharmmCoulLongOpt::eval() { typedef struct { double x,y,z; } vec3_t; typedef struct { double cutsq,lj1,lj2,lj3,lj4,offset; double _pad[2]; } fast_alpha_t; int i,j,ii,jj,inum,jnum,itype,jtype,itable; double fraction,table; double r,r2inv,r6inv,forcecoul,forcelj,factor_coul,factor_lj; double grij,expm2,prefactor,t,erfc; double philj,switch1,switch2; double rsq; double evdwl = 0.0; double ecoul = 0.0; double** __restrict__ x = atom->x; double** __restrict__ f = atom->f; double* __restrict__ q = atom->q; int* __restrict__ type = atom->type; int nlocal = atom->nlocal; - int nall = atom->nlocal + atom->nghost; double* __restrict__ special_coul = force->special_coul; double* __restrict__ special_lj = force->special_lj; double qqrd2e = force->qqrd2e; inum = list->inum; int* __restrict__ ilist = list->ilist; int** __restrict__ firstneigh = list->firstneigh; int* __restrict__ numneigh = list->numneigh; vec3_t* __restrict__ xx = (vec3_t*)x[0]; vec3_t* __restrict__ ff = (vec3_t*)f[0]; int ntypes = atom->ntypes; int ntypes2 = ntypes*ntypes; double tmp_coef1 = 1.0/denom_lj; double tmp_coef2 = cut_ljsq - 3.0*cut_lj_innersq; fast_alpha_t* __restrict__ fast_alpha = (fast_alpha_t*)malloc(ntypes2*sizeof(fast_alpha_t)); for (i = 0; i < ntypes; i++) for (j = 0; j < ntypes; j++) { fast_alpha_t& a = fast_alpha[i*ntypes+j]; a.cutsq = cutsq[i+1][j+1]; a.lj1 = lj1[i+1][j+1]; a.lj2 = lj2[i+1][j+1]; a.lj3 = lj3[i+1][j+1]; a.lj4 = lj4[i+1][j+1]; } fast_alpha_t* __restrict__ tabsix = fast_alpha; // loop over neighbors of my atoms for (ii = 0; ii < inum; ii++) { i = ilist[ii]; double qtmp = q[i]; double xtmp = xx[i].x; double ytmp = xx[i].y; double ztmp = xx[i].z; itype = type[i] - 1; int* __restrict__ jlist = firstneigh[i]; jnum = numneigh[i]; double tmpfx = 0.0; double tmpfy = 0.0; double tmpfz = 0.0; fast_alpha_t* __restrict__ tabsixi = (fast_alpha_t*) &tabsix[itype*ntypes]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; - if (j < nall) { + if (j <= NEIGHMASK) { double delx = xtmp - xx[j].x; double dely = ytmp - xx[j].y; double delz = ztmp - xx[j].z; rsq = delx*delx + dely*dely + delz*delz; double tmp_coef3 = qtmp*q[j]; if (rsq < cut_bothsq) { r2inv = 1.0/rsq; forcecoul = 0.0; 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 * (EWALD_A1+t*(EWALD_A2+t*(EWALD_A3+t*(EWALD_A4+t*EWALD_A5)))) * expm2; prefactor = qqrd2e * tmp_coef3/r; forcecoul = prefactor * (erfc + EWALD_F*grij*expm2); } 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 = tmp_coef3 * table; } } forcelj = 0.0; if (rsq < cut_ljsq) { r6inv = r2inv*r2inv*r2inv; jtype = type[j] - 1; fast_alpha_t& a = tabsixi[jtype]; forcelj = r6inv * (a.lj1*r6inv - a.lj2); if (rsq > cut_lj_innersq) { switch1 = (cut_ljsq-rsq) * (cut_ljsq-rsq) * (tmp_coef2 + 2.0*rsq) * tmp_coef1; switch2 = 12.0*rsq * (cut_ljsq-rsq) * (rsq-cut_lj_innersq) * tmp_coef1; philj = r6inv * (a.lj3*r6inv - a.lj4); forcelj = forcelj*switch1 + philj*switch2; } } double fpair = (forcecoul + forcelj) * r2inv; tmpfx += delx*fpair; tmpfy += dely*fpair; tmpfz += delz*fpair; if (NEWTON_PAIR || j < nlocal) { ff[j].x -= delx*fpair; ff[j].y -= dely*fpair; ff[j].z -= delz*fpair; } if (EFLAG) { if (rsq < cut_coulsq) { if (!ncoultablebits || rsq <= tabinnersq) ecoul = prefactor*erfc; else { table = etable[itable] + fraction*detable[itable]; ecoul = tmp_coef3 * table; } } else ecoul = 0.0; if (rsq < cut_ljsq) { fast_alpha_t& a = tabsixi[jtype]; evdwl = r6inv*(a.lj3*r6inv-a.lj4); if (rsq > cut_lj_innersq) { switch1 = (cut_ljsq-rsq) * (cut_ljsq-rsq) * (tmp_coef2 + 2.0*rsq) * tmp_coef1; evdwl *= switch1; } } else evdwl = 0.0; } if (EVFLAG) ev_tally(i,j,nlocal,NEWTON_PAIR, evdwl,ecoul,fpair,delx,dely,delz); } } else { - factor_coul = special_coul[j/nall]; - factor_lj = special_lj[j/nall]; - j %= nall; + factor_lj = special_lj[sbmask(j)]; + factor_coul = special_coul[sbmask(j)]; + j &= NEIGHMASK; + double delx = xtmp - xx[j].x; double dely = ytmp - xx[j].y; double delz = ztmp - xx[j].z; rsq = delx*delx + dely*dely + delz*delz; double tmp_coef3 = qtmp*q[j]; if (rsq < cut_bothsq) { r2inv = 1.0/rsq; forcecoul = 0.0; 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 * (EWALD_A1+t*(EWALD_A2+t*(EWALD_A3+t*(EWALD_A4+t*EWALD_A5)))) * expm2; prefactor = qqrd2e * tmp_coef3/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 = tmp_coef3 * table; if (factor_coul < 1.0) { table = ctable[itable] + fraction*dctable[itable]; prefactor = tmp_coef3 * table; forcecoul -= (1.0-factor_coul)*prefactor; } } } forcelj = 0.0; if (rsq < cut_ljsq) { r6inv = r2inv*r2inv*r2inv; jtype = type[j] - 1; fast_alpha_t& a = tabsixi[jtype]; forcelj = r6inv * (a.lj1*r6inv - a.lj2); if (rsq > cut_lj_innersq) { switch1 = (cut_ljsq-rsq) * (cut_ljsq-rsq) * (tmp_coef2 + 2.0*rsq) * tmp_coef1; switch2 = 12.0*rsq * (cut_ljsq-rsq) * (rsq-cut_lj_innersq) * tmp_coef1; fast_alpha_t& a = tabsixi[jtype]; philj = r6inv * (a.lj3*r6inv - a.lj4); forcelj = forcelj*switch1 + philj*switch2; } } double fpair = (forcecoul + factor_lj*forcelj) * r2inv; tmpfx += delx*fpair; tmpfy += dely*fpair; tmpfz += delz*fpair; if (NEWTON_PAIR || j < nlocal) { ff[j].x -= delx*fpair; ff[j].y -= dely*fpair; ff[j].z -= delz*fpair; } if (EFLAG) { if (rsq < cut_coulsq) { if (!ncoultablebits || rsq <= tabinnersq) ecoul = prefactor*erfc; else { table = etable[itable] + fraction*detable[itable]; ecoul = tmp_coef3 * table; } if (factor_coul < 1.0) ecoul -= (1.0-factor_coul)*prefactor; } else ecoul = 0.0; if (rsq < cut_ljsq) { fast_alpha_t& a = tabsixi[jtype]; evdwl = r6inv*(a.lj3*r6inv-a.lj4); if (rsq > cut_lj_innersq) { switch1 = (cut_ljsq-rsq) * (cut_ljsq-rsq) * (tmp_coef2 + 2.0*rsq) * tmp_coef1; evdwl *= switch1; } evdwl *= factor_lj; } else evdwl = 0.0; } if (EVFLAG) ev_tally(i,j,nlocal,NEWTON_PAIR, evdwl,ecoul,fpair,delx,dely,delz); } } } ff[i].x += tmpfx; ff[i].y += tmpfy; ff[i].z += tmpfz; } free(fast_alpha); fast_alpha = 0; if (vflag_fdotr) virial_compute(); } #undef EWALD_F #undef EWALD_P #undef EWALD_A1 #undef EWALD_A2 #undef EWALD_A3 #undef EWALD_A4 #undef EWALD_A5 #undef MIN #undef MAX } #endif #endif diff --git a/src/OPT/pair_lj_cut_opt.h b/src/OPT/pair_lj_cut_opt.h index c5122f6d7..dce90b024 100644 --- a/src/OPT/pair_lj_cut_opt.h +++ b/src/OPT/pair_lj_cut_opt.h @@ -1,197 +1,196 @@ /* ---------------------------------------------------------------------- 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 Fischer, High Performance Technologies, Inc. David Richie, Stone Ridge Technology Vincent Natol, Stone Ridge Technology ------------------------------------------------------------------------- */ #ifdef PAIR_CLASS PairStyle(lj/cut/opt,PairLJCutOpt) #else #ifndef LMP_PAIR_LJ_CUT_OPT_H #define LMP_PAIR_LJ_CUT_OPT_H #include "stdlib.h" #include "pair_lj_cut.h" #include "atom.h" #include "force.h" #include "neigh_list.h" namespace LAMMPS_NS { class PairLJCutOpt : public PairLJCut { public: PairLJCutOpt(class LAMMPS *); void compute(int, int); private: template < int EVFLAG, int EFLAG, int NEWTON_PAIR > void eval(); }; template < int EVFLAG, int EFLAG, int NEWTON_PAIR > void PairLJCutOpt::eval() { typedef struct { double x,y,z; } vec3_t; typedef struct { double cutsq,lj1,lj2,lj3,lj4,offset; double _pad[2]; } fast_alpha_t; int i,j,ii,jj,inum,jnum,itype,jtype; double evdwl = 0.0; double** __restrict__ x = atom->x; double** __restrict__ f = atom->f; int* __restrict__ type = atom->type; int nlocal = atom->nlocal; - int nall = atom->nlocal + atom->nghost; double* __restrict__ special_lj = force->special_lj; inum = list->inum; int* __restrict__ ilist = list->ilist; int** __restrict__ firstneigh = list->firstneigh; int* __restrict__ numneigh = list->numneigh; vec3_t* __restrict__ xx = (vec3_t*)x[0]; vec3_t* __restrict__ ff = (vec3_t*)f[0]; int ntypes = atom->ntypes; int ntypes2 = ntypes*ntypes; fast_alpha_t* __restrict__ fast_alpha = (fast_alpha_t*) malloc(ntypes2*sizeof(fast_alpha_t)); for (i = 0; i < ntypes; i++) for (j = 0; j < ntypes; j++) { fast_alpha_t& a = fast_alpha[i*ntypes+j]; a.cutsq = cutsq[i+1][j+1]; a.lj1 = lj1[i+1][j+1]; a.lj2 = lj2[i+1][j+1]; a.lj3 = lj3[i+1][j+1]; a.lj4 = lj4[i+1][j+1]; a.offset = offset[i+1][j+1]; } fast_alpha_t* __restrict__ tabsix = fast_alpha; // loop over neighbors of my atoms for (ii = 0; ii < inum; ii++) { i = ilist[ii]; double xtmp = xx[i].x; double ytmp = xx[i].y; double ztmp = xx[i].z; itype = type[i] - 1; int* __restrict__ jlist = firstneigh[i]; jnum = numneigh[i]; double tmpfx = 0.0; double tmpfy = 0.0; double tmpfz = 0.0; fast_alpha_t* __restrict__ tabsixi = (fast_alpha_t*)&tabsix[itype*ntypes]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; double factor_lj; - if (j < nall) { + if (j <= NEIGHMASK) { double delx = xtmp - xx[j].x; double dely = ytmp - xx[j].y; double delz = ztmp - xx[j].z; double rsq = delx*delx + dely*dely + delz*delz; jtype = type[j] - 1; fast_alpha_t& a = tabsixi[jtype]; if (rsq < a.cutsq) { double r2inv = 1.0/rsq; double r6inv = r2inv*r2inv*r2inv; double forcelj = r6inv * (a.lj1*r6inv - a.lj2); double fpair = forcelj*r2inv; tmpfx += delx*fpair; tmpfy += dely*fpair; tmpfz += delz*fpair; if (NEWTON_PAIR || j < nlocal) { ff[j].x -= delx*fpair; ff[j].y -= dely*fpair; ff[j].z -= delz*fpair; } if (EFLAG) evdwl = r6inv*(a.lj3*r6inv-a.lj4) - a.offset; if (EVFLAG) ev_tally(i,j,nlocal,NEWTON_PAIR, evdwl,0.0,fpair,delx,dely,delz); } } else { - factor_lj = special_lj[j/nall]; - j = j % nall; + factor_lj = special_lj[sbmask(j)]; + j &= NEIGHMASK; double delx = xtmp - xx[j].x; double dely = ytmp - xx[j].y; double delz = ztmp - xx[j].z; double rsq = delx*delx + dely*dely + delz*delz; int jtype1 = type[j]; jtype = jtype1 - 1; fast_alpha_t& a = tabsixi[jtype]; if (rsq < a.cutsq) { double r2inv = 1.0/rsq; double r6inv = r2inv*r2inv*r2inv; fast_alpha_t& a = tabsixi[jtype]; double forcelj = r6inv * (a.lj1*r6inv - a.lj2); double fpair = factor_lj*forcelj*r2inv; tmpfx += delx*fpair; tmpfy += dely*fpair; tmpfz += delz*fpair; if (NEWTON_PAIR || j < nlocal) { ff[j].x -= delx*fpair; ff[j].y -= dely*fpair; ff[j].z -= delz*fpair; } if (EFLAG) { evdwl = r6inv*(a.lj3*r6inv-a.lj4) - a.offset; evdwl *= factor_lj; } if (EVFLAG) ev_tally(i,j,nlocal,NEWTON_PAIR, evdwl,0.0,fpair,delx,dely,delz); } } } ff[i].x += tmpfx; ff[i].y += tmpfy; ff[i].z += tmpfz; } free(fast_alpha); fast_alpha = 0; if (vflag_fdotr) virial_compute(); } } #endif #endif diff --git a/src/OPT/pair_morse_opt.h b/src/OPT/pair_morse_opt.h index a8bfa1ec4..0e92408e1 100644 --- a/src/OPT/pair_morse_opt.h +++ b/src/OPT/pair_morse_opt.h @@ -1,194 +1,193 @@ /* ---------------------------------------------------------------------- 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 Fischer, High Performance Technologies, Inc. David Richie, Stone Ridge Technology Vincent Natol, Stone Ridge Technology ------------------------------------------------------------------------- */ #ifdef PAIR_CLASS PairStyle(morse/opt,PairMorseOpt) #else #ifndef LMP_PAIR_MORSE_OPT_H #define LMP_PAIR_MORSE_OPT_H #include "math.h" #include "stdlib.h" #include "pair_morse.h" #include "atom.h" #include "force.h" #include "neigh_list.h" namespace LAMMPS_NS { class PairMorseOpt : public PairMorse { public: PairMorseOpt(class LAMMPS *); void compute(int, int); private: template < int EVFLAG, int EFLAG, int NEWTON_PAIR > void eval(); }; template < int EVFLAG, int EFLAG, int NEWTON_PAIR > void PairMorseOpt::eval() { typedef struct { double x,y,z; } vec3_t; typedef struct { double cutsq,r0,alpha,morse1,d0,offset; double _pad[2]; } fast_alpha_t; int i,j,ii,jj,inum,jnum,itype,jtype; double evdwl = 0.0; double** __restrict__ x = atom->x; double** __restrict__ f = atom->f; int* __restrict__ type = atom->type; int nlocal = atom->nlocal; - int nall = atom->nlocal + atom->nghost; double* __restrict__ special_lj = force->special_lj; inum = list->inum; int* __restrict__ ilist = list->ilist; int** __restrict__ firstneigh = list->firstneigh; int* __restrict__ numneigh = list->numneigh; vec3_t* __restrict__ xx = (vec3_t*)x[0]; vec3_t* __restrict__ ff = (vec3_t*)f[0]; int ntypes = atom->ntypes; int ntypes2 = ntypes*ntypes; fast_alpha_t* __restrict__ fast_alpha = (fast_alpha_t*) malloc(ntypes2*sizeof(fast_alpha_t)); for (i = 0; i < ntypes; i++) for (j = 0; j < ntypes; j++) { fast_alpha_t& a = fast_alpha[i*ntypes+j]; a.cutsq = cutsq[i+1][j+1]; a.r0 = r0[i+1][j+1]; a.alpha = alpha[i+1][j+1]; a.morse1 = morse1[i+1][j+1]; a.d0 = d0[i+1][j+1]; a.offset = offset[i+1][j+1]; } fast_alpha_t* __restrict__ tabsix = fast_alpha; // loop over neighbors of my atoms for (ii = 0; ii < inum; ii++) { i = ilist[ii]; double xtmp = xx[i].x; double ytmp = xx[i].y; double ztmp = xx[i].z; itype = type[i] - 1; int* __restrict__ jlist = firstneigh[i]; jnum = numneigh[i]; double tmpfx = 0.0; double tmpfy = 0.0; double tmpfz = 0.0; fast_alpha_t* __restrict__ tabsixi = (fast_alpha_t*)&tabsix[itype*ntypes]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; double factor_lj; - if (j < nall) { + if (j <= NEIGHMASK) { double delx = xtmp - xx[j].x; double dely = ytmp - xx[j].y; double delz = ztmp - xx[j].z; double rsq = delx*delx + dely*dely + delz*delz; jtype = type[j] - 1; fast_alpha_t& a = tabsixi[jtype]; if (rsq < a.cutsq) { double r = sqrt(rsq); double dr = r - a.r0; double dexp = exp(-a.alpha * dr); double fpair = a.morse1 * (dexp*dexp - dexp) / r; tmpfx += delx*fpair; tmpfy += dely*fpair; tmpfz += delz*fpair; if (NEWTON_PAIR || j < nlocal) { ff[j].x -= delx*fpair; ff[j].y -= dely*fpair; ff[j].z -= delz*fpair; } if (EFLAG) evdwl = a.d0 * (dexp*dexp - 2.0*dexp) - a.offset; if (EVFLAG) ev_tally(i,j,nlocal,NEWTON_PAIR, evdwl,0.0,fpair,delx,dely,delz); } } else { - factor_lj = special_lj[j/nall]; - j = j % nall; + factor_lj = special_lj[sbmask(j)]; + j &= NEIGHMASK; double delx = xtmp - xx[j].x; double dely = ytmp - xx[j].y; double delz = ztmp - xx[j].z; double rsq = delx*delx + dely*dely + delz*delz; jtype = type[j] - 1; fast_alpha_t& a = tabsixi[jtype]; if (rsq < a.cutsq) { double r = sqrt(rsq); double dr = r - a.r0; double dexp = exp(-a.alpha * dr); double fpair = factor_lj * a.morse1 * (dexp*dexp - dexp) / r; tmpfx += delx*fpair; tmpfy += dely*fpair; tmpfz += delz*fpair; if (NEWTON_PAIR || j < nlocal) { ff[j].x -= delx*fpair; ff[j].y -= dely*fpair; ff[j].z -= delz*fpair; } if (EFLAG) { evdwl = a.d0 * (dexp*dexp - 2.0*dexp) - a.offset; evdwl *= factor_lj; } if (EVFLAG) ev_tally(i,j,nlocal,NEWTON_PAIR, evdwl,0.0,fpair,delx,dely,delz); } } } ff[i].x += tmpfx; ff[i].y += tmpfy; ff[i].z += tmpfz; } free(fast_alpha); fast_alpha = 0; if (vflag_fdotr) virial_compute(); } } #endif #endif diff --git a/src/PERI/fix_peri_neigh.cpp b/src/PERI/fix_peri_neigh.cpp index f006809d7..666a27697 100644 --- a/src/PERI/fix_peri_neigh.cpp +++ b/src/PERI/fix_peri_neigh.cpp @@ -1,539 +1,541 @@ /* ---------------------------------------------------------------------- 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 "math.h" #include "fix_peri_neigh.h" #include "pair_peri_pmb.h" #include "pair_peri_lps.h" #include "atom.h" #include "domain.h" #include "force.h" #include "comm.h" #include "update.h" #include "neighbor.h" #include "neigh_list.h" #include "neigh_request.h" #include "pair.h" #include "lattice.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define MIN(A,B) ((A) < (B)) ? (A) : (B) #define MAX(A,B) ((A) > (B)) ? (A) : (B) /* ---------------------------------------------------------------------- */ FixPeriNeigh::FixPeriNeigh(LAMMPS *lmp,int narg, char **arg) : Fix(lmp, narg, arg) { restart_global = 1; restart_peratom = 1; first = 1; // perform initial allocation of atom-based arrays // register with atom class // set maxpartner = 1 as placeholder maxpartner = 1; npartner = NULL; partner = NULL; r0 = NULL; vinter = NULL; wvolume = NULL; grow_arrays(atom->nmax); atom->add_callback(0); atom->add_callback(1); // initialize npartner to 0 so atom migration is OK the 1st time int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) npartner[i] = 0; // set comm sizes needed by this fix comm_forward = 1; } /* ---------------------------------------------------------------------- */ FixPeriNeigh::~FixPeriNeigh() { // unregister this fix so atom class doesn't invoke it any more atom->delete_callback(id,0); atom->delete_callback(id,1); // delete locally stored arrays memory->destroy(npartner); memory->destroy(partner); memory->destroy(r0); memory->destroy(vinter); memory->destroy(wvolume); } /* ---------------------------------------------------------------------- */ int FixPeriNeigh::setmask() { int mask = 0; return mask; } /* ---------------------------------------------------------------------- */ void FixPeriNeigh::init() { if (!first) return; // need a full neighbor list once int irequest = neighbor->request((void *) this); neighbor->requests[irequest]->pair = 0; neighbor->requests[irequest]->fix = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->full = 1; neighbor->requests[irequest]->occasional = 1; } /* ---------------------------------------------------------------------- */ void FixPeriNeigh::init_list(int id, NeighList *ptr) { list = ptr; } /* ---------------------------------------------------------------------- For minimization: setup as with dynamics ------------------------------------------------------------------------- */ void FixPeriNeigh::min_setup(int vflag) { setup(vflag); } /* ---------------------------------------------------------------------- create initial list of neighbor partners via call to neighbor->build() must be done in setup (not init) since fix init comes before neigh init ------------------------------------------------------------------------- */ void FixPeriNeigh::setup(int vflag) { int i,j,ii,jj,itype,jtype,inum,jnum; double xtmp,ytmp,ztmp,delx,dely,delz,rsq; int *ilist,*jlist,*numneigh; int **firstneigh; double **x = atom->x; double *vfrac = atom->vfrac; int *type = atom->type; int *tag = atom->tag; int nlocal = atom->nlocal; // only build list of bonds on very first run if (!first) return; first = 0; // invoke full neighbor list (will copy or build if necessary) neighbor->build_one(list->index); inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // scan neighbor list to set maxpartner Pair *anypair = force->pair_match("peri",0); double **cutsq = anypair->cutsq; 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]) npartner[i]++; } } maxpartner = 0; for (i = 0; i < nlocal; i++) maxpartner = MAX(maxpartner,npartner[i]); int maxall; MPI_Allreduce(&maxpartner,&maxall,1,MPI_INT,MPI_MAX,world); maxpartner = maxall; // realloc arrays with correct value for maxpartner memory->destroy(partner); memory->destroy(r0); memory->destroy(npartner); npartner = NULL; partner = NULL; r0 = NULL; grow_arrays(atom->nmax); // create partner list and r0 values from neighbor list // compute vinter for each atom for (i = 0; i < nlocal; i++) { npartner[i] = 0; vinter[i] = 0.0; wvolume[i] = 0.0; } 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]) { partner[i][npartner[i]] = tag[j]; r0[i][npartner[i]] = sqrt(rsq); npartner[i]++; vinter[i] += vfrac[j]; } } } // sanity check: does any atom appear twice in any neigborlist? // should only be possible if using pbc and domain < 2*delta if (domain->xperiodic || domain->yperiodic || domain->zperiodic) { for (i = 0; i < nlocal; i++) { jnum = npartner[i]; for (jj = 0; jj < jnum; jj++) { for (int kk = jj+1; kk < jnum; kk++) { if (partner[i][jj] == partner[i][kk]) error->one("Duplicate particle in PeriDynamic bond - " "simulation box is too small"); } } } } // compute wvolume for each atom double **x0 = atom->x0; double half_lc = 0.5*(domain->lattice->xlattice); double vfrac_scale; PairPeriLPS *pairlps = dynamic_cast(anypair); PairPeriPMB *pairpmb = dynamic_cast(anypair); for (i = 0; i < nlocal; i++) { double xtmp0 = x0[i][0]; double ytmp0 = x0[i][1]; double ztmp0 = x0[i][2]; jnum = npartner[i]; itype = type[i]; // loop over partners of particle i for (jj = 0; jj < jnum; jj++) { // if bond already broken, skip this partner if (partner[i][jj] == 0) continue; // lookup local index of partner particle j = atom->map(partner[i][jj]); // skip if particle is "lost" if (j < 0) continue; double delx0 = xtmp0 - x0[j][0]; double dely0 = ytmp0 - x0[j][1]; double delz0 = ztmp0 - x0[j][2]; double rsq0 = delx0*delx0 + dely0*dely0 + delz0*delz0; jtype = type[j]; double delta = sqrt(cutsq[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; if (pairpmb != NULL) // define influence function to be 1.0 wvolume[i] += 1.0 * rsq0 * vfrac[j] * vfrac_scale; else if (pairlps != NULL) // call the PairPeriLPS influence function wvolume[i] += pairlps->influence_function(delx0,dely0,delz0) * rsq0 * vfrac[j] * vfrac_scale; } } // communicate wvolume to ghosts comm->forward_comm_fix(this); // bond statistics int n = 0; for (i = 0; i < nlocal; i++) n += npartner[i]; int nall; MPI_Allreduce(&n,&nall,1,MPI_INT,MPI_SUM,world); if (comm->me == 0) { if (screen) { fprintf(screen,"Peridynamic bonds:\n"); fprintf(screen," total # of bonds = %d\n",nall); fprintf(screen," bonds/atom = %g\n",(double)nall/atom->natoms); } if (logfile) { fprintf(logfile,"Peridynamic bonds:\n"); fprintf(logfile," total # of bonds = %d\n",nall); fprintf(logfile," bonds/atom = %g\n",(double)nall/atom->natoms); } } } /* ---------------------------------------------------------------------- memory usage of local atom-based arrays ------------------------------------------------------------------------- */ double FixPeriNeigh::memory_usage() { int nmax = atom->nmax; int bytes = nmax * sizeof(int); bytes += nmax*maxpartner * sizeof(int); bytes += nmax*maxpartner * sizeof(double); bytes += nmax * sizeof(double); bytes += nmax * sizeof(double); return bytes; } /* ---------------------------------------------------------------------- allocate local atom-based arrays ------------------------------------------------------------------------- */ void FixPeriNeigh::grow_arrays(int nmax) { memory->grow(npartner,nmax,"peri_neigh:npartner"); memory->grow(partner,nmax,maxpartner,"peri_neigh:partner"); memory->grow(r0,nmax,maxpartner,"peri_neigh:r0"); memory->grow(vinter,nmax,"peri_neigh:vinter"); memory->grow(wvolume,nmax,"peri_neigh:wvolume"); } /* ---------------------------------------------------------------------- copy values within local atom-based arrays ------------------------------------------------------------------------- */ void FixPeriNeigh::copy_arrays(int i, int j) { npartner[j] = npartner[i]; for (int m = 0; m < npartner[j]; m++) { partner[j][m] = partner[i][m]; r0[j][m] = r0[i][m]; } vinter[j] = vinter[i]; wvolume[j] = wvolume[i]; } /* ---------------------------------------------------------------------- pack values in local atom-based arrays for exchange with another proc ------------------------------------------------------------------------- */ int FixPeriNeigh::pack_exchange(int i, double *buf) { // compact list by eliminating partner = 0 entries // set buf[0] after compaction int m = 1; for (int n = 0; n < npartner[i]; n++) { if (partner[i][n] == 0) continue; buf[m++] = partner[i][n]; buf[m++] = r0[i][n]; } buf[0] = m/2; buf[m++] = vinter[i]; buf[m++] = wvolume[i]; return m; } /* ---------------------------------------------------------------------- unpack values in local atom-based arrays from exchange with another proc ------------------------------------------------------------------------- */ int FixPeriNeigh::unpack_exchange(int nlocal, double *buf) { int m = 0; npartner[nlocal] = static_cast (buf[m++]); for (int n = 0; n < npartner[nlocal]; n++) { partner[nlocal][n] = static_cast (buf[m++]); r0[nlocal][n] = buf[m++]; } vinter[nlocal] = buf[m++]; wvolume[nlocal] = buf[m++]; return m; } /* ---------------------------------------------------------------------- */ int FixPeriNeigh::pack_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++] = wvolume[j]; } return 1; } /* ---------------------------------------------------------------------- */ void FixPeriNeigh::unpack_comm(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) wvolume[i] = buf[m++]; } /* ---------------------------------------------------------------------- pack entire state of Fix into one write ------------------------------------------------------------------------- */ void FixPeriNeigh::write_restart(FILE *fp) { int n = 0; double list[2]; list[n++] = first; list[n++] = maxpartner; if (comm->me == 0) { int size = n * sizeof(double); fwrite(&size,sizeof(int),1,fp); fwrite(list,sizeof(double),n,fp); } } /* ---------------------------------------------------------------------- use state info from restart file to restart the Fix ------------------------------------------------------------------------- */ void FixPeriNeigh::restart(char *buf) { int n = 0; double *list = (double *) buf; first = static_cast (list[n++]); maxpartner = static_cast (list[n++]); // grow 2D arrays now, cannot change size of 2nd array index later grow_arrays(atom->nmax); } /* ---------------------------------------------------------------------- pack values in local atom-based arrays for restart file ------------------------------------------------------------------------- */ int FixPeriNeigh::pack_restart(int i, double *buf) { int m = 0; buf[m++] = 2*npartner[i] + 4; buf[m++] = npartner[i]; for (int n = 0; n < npartner[i]; n++) { buf[m++] = partner[i][n]; buf[m++] = r0[i][n]; } buf[m++] = vinter[i]; buf[m++] = wvolume[i]; return m; } /* ---------------------------------------------------------------------- unpack values from atom->extra array to restart the fix ------------------------------------------------------------------------- */ void FixPeriNeigh::unpack_restart(int nlocal, int nth) { double **extra = atom->extra; // skip to Nth set of extra values int m = 0; for (int i = 0; i < nth; i++) m += static_cast (extra[nlocal][m]); m++; npartner[nlocal] = static_cast (extra[nlocal][m++]); for (int n = 0; n < npartner[nlocal]; n++) { partner[nlocal][n] = static_cast (extra[nlocal][m++]); r0[nlocal][n] = extra[nlocal][m++]; } vinter[nlocal] = extra[nlocal][m++]; wvolume[nlocal] = extra[nlocal][m++]; } /* ---------------------------------------------------------------------- maxsize of any atom's restart data ------------------------------------------------------------------------- */ int FixPeriNeigh::maxsize_restart() { return 2*maxpartner + 4; } /* ---------------------------------------------------------------------- size of atom nlocal's restart data ------------------------------------------------------------------------- */ int FixPeriNeigh::size_restart(int nlocal) { return 2*npartner[nlocal] + 4; } diff --git a/src/PERI/pair_peri_lps.cpp b/src/PERI/pair_peri_lps.cpp index a3d353c2f..c4a5cdcae 100644 --- a/src/PERI/pair_peri_lps.cpp +++ b/src/PERI/pair_peri_lps.cpp @@ -1,753 +1,752 @@ /* ---------------------------------------------------------------------- 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 "math.h" #include "stdlib.h" #include "string.h" #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; #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) /* ---------------------------------------------------------------------- */ PairPeriLPS::PairPeriLPS(LAMMPS *lmp) : Pair(lmp) { for (int i = 0; i < 6; i++) virial[i] = 0.0; no_virial_compute=1; 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; int **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 nall = atom->nlocal + atom->nghost; 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; double dt = update->dt; // 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 %= nall; + 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 / sqrt(cutsq[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 for (i = 0; i < nlocal; i++) { itype = type[i]; if (eflag) { 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 = sqrt(cutsq[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("Illegal pair_style command"); } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairPeriLPS::coeff(int narg, char **arg) { if (narg != 7) error->all("Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); double 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]); 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("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("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]; return cut[i][j]; } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairPeriLPS::init_style() { // error checks if (atom->map_style == 0) error->all("Pair peri requires an atom map, see atom_modify"); if (atom->style_match("peri") == 0) error->all("Pair style peri_lps requires atom style peri"); if (domain->lattice == NULL) error->all("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("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("Fix peri neigh does not exist"); int irequest = neighbor->request(this); } /* ---------------------------------------------------------------------- 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); } } } /* ---------------------------------------------------------------------- */ double PairPeriLPS::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; int **partner = ((FixPeriNeigh *) modify->fix[ifix_peri])->partner; int *npartner = ((FixPeriNeigh *) modify->fix[ifix_peri])->npartner; double *wvolume = ((FixPeriNeigh *) modify->fix[ifix_peri])->wvolume; double lc = domain->lattice->xlattice; double half_lc = 0.5*lc; double kshort; 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; // kshort resembles short-range force constant of bond-based theory in 3d kshort = (15.0 * 18.0 * bulkmodulus[itype][itype]) / ( 3.141592653589793 * cutsq[itype][jtype] * cutsq[itype][jtype]); rk = ( kshort * vfrac[j]) * (dr / sqrt(cutsq[itype][jtype])); if (r > 0.0) fforce += -(rk/r); energy += 0.5*rk*dr; } if (atom->nmax > nmax) { memory->destroy(theta); nmax = atom->nmax; 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]); double omega_plus, omega_minus; 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; // scale vfrac[j] if particle j near the horizon 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; 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) fforce += -(rk/r); energy += 0.5 * 15 * (shearmodulus[itype][itype]/wvolume[i]) * omega_plus * ( dr - theta[i]* r0[i][jj] / 3.0 ) * ( dr - theta[i]* r0[i][jj] / 3.0 ) * vfrac[j] * vfrac_scale; } } return energy; } /* ---------------------------------------------------------------------- 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("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; int **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 = sqrt(cutsq[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_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 1; } /* ---------------------------------------------------------------------- */ void PairPeriLPS::unpack_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 fcbc8d154..3ee46cb93 100644 --- a/src/PERI/pair_peri_pmb.cpp +++ b/src/PERI/pair_peri_pmb.cpp @@ -1,514 +1,513 @@ /* ---------------------------------------------------------------------- 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 "math.h" #include "float.h" #include "stdlib.h" #include "string.h" #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; #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) /* ---------------------------------------------------------------------- */ PairPeriPMB::PairPeriPMB(LAMMPS *lmp) : Pair(lmp) { for (int i = 0; i < 6; i++) virial[i] = 0.0; no_virial_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; int **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 nall = atom->nlocal + atom->nghost; 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 %= nall; + 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 / sqrt(cutsq[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 (nlocal > 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 = sqrt(cutsq[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("Illegal pair_style command"); } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairPeriPMB::coeff(int narg, char **arg) { if (narg != 6) error->all("Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); double kspring_one = force->numeric(arg[2]); double cut_one = force->numeric(arg[3]); double s00_one = force->numeric(arg[4]); double alpha_one = force->numeric(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("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("All pair coeffs are not set"); kspring[j][i] = kspring[i][j]; alpha[j][i] = alpha[i][j]; s00[j][i] = s00[i][j]; return cut[i][j]; } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairPeriPMB::init_style() { // error checks if (atom->map_style == 0) error->all("Pair peri requires an atom map, see atom_modify"); if (atom->style_match("peri") == 0) error->all("Pair style peri_pmb requires atom style peri"); if (domain->lattice == NULL) error->all("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("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("Fix peri neigh does not exist"); int irequest = neighbor->request(this); } /* ---------------------------------------------------------------------- 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; int **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/REAX/pair_reax.cpp b/src/REAX/pair_reax.cpp index c162212ed..775993183 100644 --- a/src/REAX/pair_reax.cpp +++ b/src/REAX/pair_reax.cpp @@ -1,1072 +1,1072 @@ /* ---------------------------------------------------------------------- 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: Aidan Thompson (Sandia, athomps@sandia.gov) Hansohl Cho (MIT, hansohl@mit.edu) LAMMPS implementation of the Reactive Force Field (ReaxFF) is based on Aidan Thompson's GRASP code (General Reactive Atomistic Simulation Program) and Ardi Van Duin's original ReaxFF code ------------------------------------------------------------------------- */ #include "mpi.h" #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "pair_reax.h" #include "pair_reax_fortran.h" #include "atom.h" #include "update.h" #include "force.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 MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define SMALL 0.0001 /* ---------------------------------------------------------------------- */ PairREAX::PairREAX(LAMMPS *lmp) : Pair(lmp) { single_enable = 0; one_coeff = 1; no_virial_compute = 1; nextra = 14; pvector = new double[nextra]; cutmax = 0.0; hbcut = 6.0; ihbnew = 1; itripstaball = 1; iprune = 4; ihb = 1; chpot = 0; nmax = 0; arow_ptr = NULL; ch = NULL; elcvec = NULL; rcg = NULL; wcg = NULL; pcg = NULL; poldcg = NULL; qcg = NULL; matmax = 0; aval = NULL; acol_ind = NULL; comm_forward = 1; comm_reverse = 1; precision = 1.0e-6; } /* ---------------------------------------------------------------------- free all arrays check if allocated, since class can be destructed when incomplete ------------------------------------------------------------------------- */ PairREAX::~PairREAX() { delete [] pvector; if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); for (int i = 1; i <= atom->ntypes; i++) delete [] param_list[i].params; delete [] param_list; delete [] map; } memory->destroy(arow_ptr); memory->destroy(ch); memory->destroy(elcvec); memory->destroy(rcg); memory->destroy(wcg); memory->destroy(pcg); memory->destroy(poldcg); memory->destroy(qcg); memory->destroy(aval); memory->destroy(acol_ind); } /* ---------------------------------------------------------------------- */ void PairREAX::compute(int eflag, int vflag) { int i,j; double evdwl,ecoul; double energy_charge_equilibration; evdwl = ecoul = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = eflag_global = vflag_global = eflag_atom = vflag_atom = 0; if (vflag_global) FORTRAN(cbkvirial, CBKVIRIAL).Lvirial = 1; else FORTRAN(cbkvirial, CBKVIRIAL).Lvirial = 0; if (vflag_atom) FORTRAN(cbkvirial, CBKVIRIAL).Latomvirial = 1; else FORTRAN(cbkvirial, CBKVIRIAL).Latomvirial = 0; // reallocate charge equilibration and CG arrays if necessary if (atom->nmax > nmax) { memory->destroy(rcg); memory->destroy(wcg); memory->destroy(pcg); memory->destroy(poldcg); memory->destroy(qcg); nmax = atom->nmax; int n = nmax+1; memory->create(arow_ptr,n,"reax:arow_ptr"); memory->create(ch,n,"reax:ch"); memory->create(elcvec,n,"reax:elcvec"); memory->create(rcg,n,"reax:rcg"); memory->create(wcg,n,"reax:wcg"); memory->create(pcg,n,"reax:pcg"); memory->create(poldcg,n,"reax:poldcg"); memory->create(qcg,n,"reax:qcg"); } // calculate the atomic charge distribution compute_charge(energy_charge_equilibration); // transfer LAMMPS positions and neighbor lists to REAX write_reax_positions(); write_reax_vlist(); // determine whether this bond is owned by the processor or not FORTRAN(srtbon1, SRTBON1)(&iprune, &ihb, &hbcut, &ihbnew, &itripstaball); // communicate with other processors for the atomic bond order calculations FORTRAN(cbkabo, CBKABO).abo; // communicate local atomic bond order to ghost atomic bond order packflag = 0; comm->forward_comm_pair(this); FORTRAN(molec, MOLEC)(); FORTRAN(encalc, ENCALC)(); FORTRAN(mdsav, MDSAV)(&comm->me); // read forces from ReaxFF Fortran read_reax_forces(); // extract global and per-atom energy from ReaxFF Fortran // compute_charge already contributed to eatom if (eflag_global) { evdwl += FORTRAN(cbkenergies, CBKENERGIES).eb; evdwl += FORTRAN(cbkenergies, CBKENERGIES).ea; evdwl += FORTRAN(cbkenergies, CBKENERGIES).elp; evdwl += FORTRAN(cbkenergies, CBKENERGIES).emol; evdwl += FORTRAN(cbkenergies, CBKENERGIES).ev; evdwl += FORTRAN(cbkenergies, CBKENERGIES).epen; evdwl += FORTRAN(cbkenergies, CBKENERGIES).ecoa; evdwl += FORTRAN(cbkenergies, CBKENERGIES).ehb; evdwl += FORTRAN(cbkenergies, CBKENERGIES).et; evdwl += FORTRAN(cbkenergies, CBKENERGIES).eco; evdwl += FORTRAN(cbkenergies, CBKENERGIES).ew; evdwl += FORTRAN(cbkenergies, CBKENERGIES).efi; ecoul += FORTRAN(cbkenergies, CBKENERGIES).ep; ecoul += energy_charge_equilibration; eng_vdwl += evdwl; eng_coul += ecoul; // Store the different parts of the energy // in a list for output by compute pair command pvector[0] = FORTRAN(cbkenergies, CBKENERGIES).eb; pvector[1] = FORTRAN(cbkenergies, CBKENERGIES).ea; pvector[2] = FORTRAN(cbkenergies, CBKENERGIES).elp; pvector[3] = FORTRAN(cbkenergies, CBKENERGIES).emol; pvector[4] = FORTRAN(cbkenergies, CBKENERGIES).ev; pvector[5] = FORTRAN(cbkenergies, CBKENERGIES).epen; pvector[6] = FORTRAN(cbkenergies, CBKENERGIES).ecoa; pvector[7] = FORTRAN(cbkenergies, CBKENERGIES).ehb; pvector[8] = FORTRAN(cbkenergies, CBKENERGIES).et; pvector[9] = FORTRAN(cbkenergies, CBKENERGIES).eco; pvector[10] = FORTRAN(cbkenergies, CBKENERGIES).ew; pvector[11] = FORTRAN(cbkenergies, CBKENERGIES).ep; pvector[12] = FORTRAN(cbkenergies, CBKENERGIES).efi; pvector[13] = energy_charge_equilibration; } if (eflag_atom) { int ntotal = atom->nlocal + atom->nghost; for (i = 0; i < ntotal; i++) eatom[i] += FORTRAN(cbkd,CBKD).estrain[i]; } // extract global and per-atom virial from ReaxFF Fortran if (vflag_global) { virial[0] = -FORTRAN(cbkvirial, CBKVIRIAL).virial[0]; virial[1] = -FORTRAN(cbkvirial, CBKVIRIAL).virial[1]; virial[2] = -FORTRAN(cbkvirial, CBKVIRIAL).virial[2]; virial[3] = -FORTRAN(cbkvirial, CBKVIRIAL).virial[3]; virial[4] = -FORTRAN(cbkvirial, CBKVIRIAL).virial[4]; virial[5] = -FORTRAN(cbkvirial, CBKVIRIAL).virial[5]; } if (vflag_atom) { int ntotal = atom->nlocal + atom->nghost; j = 0; for (i = 0; i < ntotal; i++) { vatom[i][0] = -FORTRAN(cbkvirial, CBKVIRIAL).atomvirial[j+0]; vatom[i][1] = -FORTRAN(cbkvirial, CBKVIRIAL).atomvirial[j+1]; vatom[i][2] = -FORTRAN(cbkvirial, CBKVIRIAL).atomvirial[j+2]; vatom[i][3] = -FORTRAN(cbkvirial, CBKVIRIAL).atomvirial[j+3]; vatom[i][4] = -FORTRAN(cbkvirial, CBKVIRIAL).atomvirial[j+4]; vatom[i][5] = -FORTRAN(cbkvirial, CBKVIRIAL).atomvirial[j+5]; j += 6; } } } /* ---------------------------------------------------------------------- */ void PairREAX::write_reax_positions() { double xtmp, ytmp, ztmp; int j, jx, jy, jz, jia; double **x = atom->x; double *q = atom->q; int *type = atom->type; int *tag = atom->tag; int nlocal = atom->nlocal; int nghost = atom->nghost; FORTRAN(rsmall, RSMALL).na = nlocal+nghost; FORTRAN(rsmall, RSMALL).na_local = nlocal; if (nlocal+nghost > ReaxParams::nat) error->one("Reax_defs.h setting for NATDEF is too small"); jx = 0; jy = ReaxParams::nat; jz = 2*ReaxParams::nat; jia = 0; j = 0; for (int i = 0; i < nlocal+nghost; i++, j++) { FORTRAN(cbkc, CBKC).c[j+jx] = x[i][0]; FORTRAN(cbkc, CBKC).c[j+jy] = x[i][1]; FORTRAN(cbkc, CBKC).c[j+jz] = x[i][2]; FORTRAN(cbkch, CBKCH).ch[j] = q[i]; FORTRAN(cbkia, CBKIA).ia[j+jia] = map[type[i]]; FORTRAN(cbkia, CBKIA).iag[j+jia] = map[type[i]]; FORTRAN(cbkc, CBKC).itag[j] = tag[i]; } } /* ---------------------------------------------------------------------- */ void PairREAX::write_reax_vlist() { int ii, jj, i, j, iii, jjj; double xitmp, yitmp, zitmp; double xjtmp, yjtmp, zjtmp; int itag,jtag; int nvpair, nvlself, nvpairmax; int nbond; int inum,jnum; - int *ilist; - int *jlist; - int *numneigh,**firstneigh; + int *ilist,*jlist,*numneigh,**firstneigh; double delr2; double delx, dely, delz; double rtmp[3]; double **x = atom->x; int *tag = atom->tag; int nlocal = atom->nlocal; int nghost = atom->nghost; nvpairmax = ReaxParams::nneighmax * ReaxParams::nat; nvpair = 0; nvlself =0; nbond = 0; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; for (ii = 0; ii < inum; ii++) { i = ilist[ii]; xitmp = x[i][0]; yitmp = x[i][1]; zitmp = x[i][2]; itag = tag[i]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; + j &= NEIGHMASK; + xjtmp = x[j][0]; yjtmp = x[j][1]; zjtmp = x[j][2]; jtag = tag[j]; delx = xitmp - xjtmp; dely = yitmp - yjtmp; delz = zitmp - zjtmp; delr2 = delx*delx+dely*dely+delz*delz; if (delr2 <= rcutvsq) { if (i < j) { iii = i+1; jjj = j+1; } else { iii = j+1; jjj = i+1; } if (nvpair >= nvpairmax) error->one("Reax_defs.h setting for NNEIGHMAXDEF is too small"); FORTRAN(cbkpairs, CBKPAIRS).nvl1[nvpair] = iii; FORTRAN(cbkpairs, CBKPAIRS).nvl2[nvpair] = jjj; FORTRAN(cbknvlbo, CBKNVLBO).nvlbo[nvpair] = 0; if (delr2 <= rcutbsq) { FORTRAN(cbknvlbo, CBKNVLBO).nvlbo[nvpair] = 1; nbond++; } FORTRAN(cbknvlown, CBKNVLOWN).nvlown[nvpair] = 0; if (j < nlocal) FORTRAN(cbknvlown, CBKNVLOWN).nvlown[nvpair] = 1; else if (itag < jtag) FORTRAN(cbknvlown, CBKNVLOWN).nvlown[nvpair] = 1; else if (itag == jtag) { if (delz > SMALL) FORTRAN(cbknvlown, CBKNVLOWN).nvlown[nvpair] = 1; else if (fabs(delz) < SMALL) { if (dely > SMALL) FORTRAN(cbknvlown, CBKNVLOWN).nvlown[nvpair] = 1; else if (fabs(dely) < SMALL && delx > SMALL) FORTRAN(cbknvlown, CBKNVLOWN).nvlown[nvpair] = 1; } } nvpair++; } } } int ntotal = nlocal + nghost; for (int i = nlocal; i < ntotal; i++) { xitmp = x[i][0]; yitmp = x[i][1]; zitmp = x[i][2]; itag = tag[i]; for (int j = i+1; j < ntotal; j++) { xjtmp = x[j][0]; yjtmp = x[j][1]; zjtmp = x[j][2]; jtag = tag[j]; delx = xitmp - xjtmp; dely = yitmp - yjtmp; delz = zitmp - zjtmp; delr2 = delx*delx+dely*dely+delz*delz; // don't need to check the double count since i < j in the ghost region if (delr2 <= rcutvsq) { iii = i+1; jjj = j+1; if (nvpair >= nvpairmax) error->one("Reax_defs.h setting for NNEIGHMAXDEF is too small"); FORTRAN(cbkpairs, CBKPAIRS).nvl1[nvpair] = iii; FORTRAN(cbkpairs, CBKPAIRS).nvl2[nvpair] = jjj; FORTRAN(cbknvlbo, CBKNVLBO).nvlbo[nvpair] = 0; if (delr2 <= rcutbsq) { FORTRAN(cbknvlbo, CBKNVLBO).nvlbo[nvpair] = 1; nbond++; } FORTRAN(cbknvlown, CBKNVLOWN).nvlown[nvpair] = 0; nvpair++; } } } FORTRAN(cbkpairs, CBKPAIRS).nvpair = nvpair; FORTRAN(cbkpairs, CBKPAIRS).nvlself = nvlself; } /* ---------------------------------------------------------------------- */ void PairREAX::read_reax_forces() { double ftmp[3]; double **f = atom->f; int ntotal = atom->nlocal + atom->nghost; int j = 0; for (int i = 0; i < ntotal; i++) { ftmp[0] = -FORTRAN(cbkd, CBKD).d[j]; ftmp[1] = -FORTRAN(cbkd, CBKD).d[j+1]; ftmp[2] = -FORTRAN(cbkd, CBKD).d[j+2]; f[i][0] = ftmp[0]; f[i][1] = ftmp[1]; f[i][2] = ftmp[2]; j += 3; } } /* ---------------------------------------------------------------------- */ void PairREAX::allocate() { allocated = 1; int n = atom->ntypes; memory->create(setflag,n+1,n+1,"pair:setflag"); memory->create(cutsq,n+1,n+1,"pair:cutsq"); param_list = new ff_params[n+1]; for (int i = 1; i <= n; i++) param_list[i].params = new double[5]; map = new int[n+1]; } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairREAX::settings(int narg, char **arg) { if (narg != 0 && narg !=4) error->all("Illegal pair_style command"); if (narg == 4) { hbcut = force->numeric(arg[0]); ihbnew = static_cast (force->numeric(arg[1])); itripstaball = static_cast (force->numeric(arg[2])); precision = force->numeric(arg[3]); if (hbcut <= 0.0 || (ihbnew != 0 && ihbnew != 1) || (itripstaball != 0 && itripstaball != 1) || precision <= 0.0) error->all("Illegal pair_style command"); } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairREAX::coeff(int narg, char **arg) { if (!allocated) allocate(); if (narg != 3 + atom->ntypes) error->all("Incorrect args for pair coefficients"); // insure I,J args are * * if (strcmp(arg[0],"*") != 0 || strcmp(arg[1],"*") != 0) error->all("Incorrect args for pair coefficients"); // insure filename is ffield.reax if (strcmp(arg[2],"ffield.reax") != 0) error->all("Incorrect args for pair coefficients"); // read args that map atom types to elements in potential file // map[i] = which element the Ith atom type is, -1 if NULL // NOTE: for now throw an error if NULL is used to disallow use with hybrid // qEq atrix solver needs to be modified to exclude atoms for (int i = 3; i < narg; i++) { if (strcmp(arg[i],"NULL") == 0) { map[i-2] = -1; error->all("Cannot currently use pair reax with pair hybrid"); continue; } map[i-2] = force->inumeric(arg[i]); } int n = atom->ntypes; int count = 0; for (int i = 1; i <= n; i++) for (int j = i; j <= n; j++) { setflag[i][j] = 1; count++; } if (count == 0) error->all("Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairREAX::init_style() { if (atom->tag_enable == 0) error->all("Pair style reax requires atom IDs"); if (force->newton_pair == 0) error->all("Pair style reax requires newton pair on"); if (strcmp(update->unit_style,"real") != 0 && comm->me == 0) error->warning("Not using real units with pair reax"); int irequest = neighbor->request(this); neighbor->requests[irequest]->newton = 2; FORTRAN(readc, READC)(); FORTRAN(reaxinit, REAXINIT)(); FORTRAN(ffinpt, FFINPT)(); FORTRAN(tap7th, TAP7TH)(); // turn off read_in by fort.3 in REAX Fortran int ngeofor_tmp = -1; FORTRAN(setngeofor, SETNGEOFOR)(&ngeofor_tmp); if (comm->me == 0) FORTRAN(readgeo, READGEO)(); // initial setup for cutoff radius of VLIST and BLIST in ReaxFF double vlbora; FORTRAN(getswb, GETSWB)(&swb); cutmax=MAX(swb, hbcut); rcutvsq=cutmax*cutmax; FORTRAN(getvlbora, GETVLBORA)(&vlbora); rcutbsq=vlbora*vlbora; // parameters for charge equilibration from ReaxFF input, fort.4 // verify that no LAMMPS type to REAX type mapping was invalid int nelements; FORTRAN(getnso, GETNSO)(&nelements); FORTRAN(getswa, GETSWA)(&swa); double chi, eta, gamma; for (int itype = 1; itype <= atom->ntypes; itype++) { if (map[itype] < 1 || map[itype] > nelements) error->all("Invalid REAX atom type"); chi = FORTRAN(cbkchb, CBKCHB).chi[map[itype]-1]; eta = FORTRAN(cbkchb, CBKCHB).eta[map[itype]-1]; gamma = FORTRAN(cbkchb, CBKCHB).gam[map[itype]-1]; param_list[itype].np = 5; param_list[itype].rcutsq = cutmax; param_list[itype].params[0] = chi; param_list[itype].params[1] = eta; param_list[itype].params[2] = gamma; param_list[itype].params[3] = swa; param_list[itype].params[4] = swb; } taper_setup(); } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairREAX::init_one(int i, int j) { return cutmax; } /* ---------------------------------------------------------------------- */ int PairREAX::pack_comm(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; m = 0; if (packflag == 0) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = FORTRAN(cbkabo, CBKABO).abo[j]; } } else { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = wcg[j]; } } return 1; } /* ---------------------------------------------------------------------- */ void PairREAX::unpack_comm(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; if (packflag == 0) { for (i = first; i < last; i++) FORTRAN(cbkabo, CBKABO).abo[i] = buf[m++]; } else { for (i = first; i < last; i++) wcg[i] = buf[m++]; } } /* ---------------------------------------------------------------------- */ int PairREAX::pack_reverse_comm(int n, int first, double *buf) { int i,k,m,last,size; m = 0; last = first + n; for (i = first; i < last; i++) buf[m++] = wcg[i]; return 1; } /* ---------------------------------------------------------------------- */ void PairREAX::unpack_reverse_comm(int n, int *list, double *buf) { int i,j,k,m; m = 0; for (i = 0; i < n; i++) { j = list[i]; wcg[j] += buf[m++]; } } /* ---------------------------------------------------------------------- charge equilibration routines ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */ void PairREAX::taper_setup() { double swb2,swa2,swb3,swa3,d1,d7; d1=swb-swa; d7=pow(d1,7); swa2=swa*swa; swa3=swa2*swa; swb2=swb*swb; swb3=swb2*swb; swc7= 20.0e0/d7; swc6= -70.0e0*(swa+swb)/d7; swc5= 84.0e0*(swa2+3.0e0*swa*swb+swb2)/d7; swc4= -35.0e0*(swa3+9.0e0*swa2*swb+9.0e0*swa*swb2+swb3)/d7; swc3= 140.0e0*(swa3*swb+3.0e0*swa2*swb2+swa*swb3)/d7; swc2=-210.0e0*(swa3*swb2+swa2*swb3)/d7; swc1= 140.0e0*swa3*swb3/d7; swc0=(-35.0e0*swa3*swb2*swb2+21.0e0*swa2*swb3*swb2+ 7.0e0*swa*swb3*swb3+swb3*swb3*swb)/d7; } /* ---------------------------------------------------------------------- */ double PairREAX::taper_E(const double &r, const double &r2) { double r3=r2*r; return swc7*r3*r3*r+swc6*r3*r3+swc5*r3*r2+swc4*r2*r2+swc3*r3+swc2*r2+ swc1*r+swc0; } /* ---------------------------------------------------------------------- */ double PairREAX::taper_F(const double &r, const double &r2) { double r3=r2*r; return 7.0e0*swc7*r3*r3+6.0e0*swc6*r3*r2+5.0e0*swc5*r2*r2+ 4.0e0*swc4*r3+3.0e0*swc3*r2+2.0e0*swc2*r+swc1; } /* ---------------------------------------------------------------------- compute current charge distributions based on the charge equilibration ------------------------------------------------------------------------- */ void PairREAX::compute_charge(double &energy_charge_equilibration) { double xitmp, yitmp, zitmp; double xjtmp, yjtmp, zjtmp; int itype, jtype, itag, jtag; int ii, jj, i, j; double delr2, delr_norm, gamt, hulp1, hulp2; double delx, dely, delz; double qsum,qi; int nmatentries; double sw; double rtmp[3]; int inum,jnum; - int *ilist; - int *jlist; - int *numneigh,**firstneigh; + int *ilist,*jlist,*numneigh,**firstneigh; double **x = atom->x; double *q = atom->q; int *type = atom->type; int *tag = atom->tag; int nlocal = atom->nlocal; int nghost = atom->nghost; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // realloc neighbor based arrays if necessary int numneigh_total = 0; for (ii = 0; ii < inum; ii++) numneigh_total += numneigh[ilist[ii]]; if (numneigh_total + 2*nlocal > matmax) { memory->destroy(aval); memory->destroy(acol_ind); matmax = numneigh_total + 2*nlocal; memory->create(aval,matmax,"reax:aval"); memory->create(acol_ind,matmax,"reax:acol_ind"); } // build linear system nmatentries = 0; for (ii = 0; ii < inum; ii++) { i = ilist[ii]; xitmp = x[i][0]; yitmp = x[i][1]; zitmp = x[i][2]; itype = type[i]; itag = tag[i]; jlist = firstneigh[i]; jnum = numneigh[i]; arow_ptr[i] = nmatentries; aval[nmatentries] = 2.0*param_list[itype].params[1]; acol_ind[nmatentries] = i; nmatentries++; aval[nmatentries] = 1.0; acol_ind[nmatentries] = nlocal + nghost; nmatentries++; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; + j &= NEIGHMASK; + xjtmp = x[j][0]; yjtmp = x[j][1]; zjtmp = x[j][2]; jtype = type[j]; jtag = tag[j]; delx = xitmp - xjtmp; dely = yitmp - yjtmp; delz = zitmp - zjtmp; delr2 = delx*delx+dely*dely+delz*delz; // avoid counting local-ghost pair twice since // ReaxFF uses half neigh list with newton off if (j >= nlocal) { if (itag > jtag) { if ((itag+jtag) % 2 == 0) continue; } else if (itag < jtag) { if ((itag+jtag) % 2 == 1) continue; } else { if (zjtmp < zitmp) continue; if (zjtmp == zitmp && yjtmp < yitmp) continue; if (zjtmp == zitmp && yjtmp == yitmp && xjtmp < xitmp) continue; } } // rcutvsq = cutmax*cutmax, in ReaxFF if (delr2 <= rcutvsq) { gamt = sqrt(param_list[itype].params[2]*param_list[jtype].params[2]); delr_norm = sqrt(delr2); sw = taper_E(delr_norm, delr2); hulp1=(delr_norm*delr2+(1.0/(gamt*gamt*gamt))); hulp2=sw*14.40/cbrt(hulp1); aval[nmatentries] = hulp2; acol_ind[nmatentries] = j; nmatentries++; } } } // in this case, we don't use Midpoint method // so, we don't need to consider ghost-ghost interactions // but, need to fill the arow_ptr[] arrays for the ghost atoms for (i = nlocal; i < nlocal+nghost; i++) arow_ptr[i] = nmatentries; arow_ptr[nlocal+nghost] = nmatentries; // add rhs matentries to linear system for (ii =0; iireverse_comm_pair(this); comm->forward_comm_pair(this); MPI_Allreduce(&w[n-1], &sumtmp, 1, MPI_DOUBLE, MPI_SUM, world); w[n-1] = sumtmp; rho_old = one; for (iter = 1; iter < maxiter; iter++) { rho = 0.0; for (int i=0; i 1) { beta = rho/rho_old; for (int i = 0; ireverse_comm_pair(this); comm->forward_comm_pair(this); MPI_Allreduce(&w[n-1], &sumtmp, 1, MPI_DOUBLE, MPI_SUM, world); w[n-1] = sumtmp; for (int i=0; i using namespace LAMMPS_NS; enum{UNKNOWN,BCC,FCC,HCP,ICO}; /* ---------------------------------------------------------------------- */ ComputeAcklandAtom::ComputeAcklandAtom(LAMMPS *lmp, int narg, char **arg) : Compute(lmp, narg, arg) { if (narg != 3) error->all("Illegal compute ackland/atom command"); peratom_flag = 1; size_peratom_cols = 0; nmax = 0; structure = NULL; maxneigh = 0; distsq = NULL; nearest = NULL; nearest_n0 = NULL; nearest_n1 = NULL; } /* ---------------------------------------------------------------------- */ ComputeAcklandAtom::~ComputeAcklandAtom() { memory->destroy(structure); memory->destroy(distsq); memory->destroy(nearest); memory->destroy(nearest_n0); memory->destroy(nearest_n1); } /* ---------------------------------------------------------------------- */ void ComputeAcklandAtom::init() { // need an occasional full neighbor list int irequest = neighbor->request((void *) this); 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,"ackland/atom") == 0) count++; if (count > 1 && comm->me == 0) error->warning("More than one compute ackland/atom"); } /* ---------------------------------------------------------------------- */ void ComputeAcklandAtom::init_list(int id, NeighList *ptr) { list = ptr; } /* ---------------------------------------------------------------------- */ void ComputeAcklandAtom::compute_peratom() { int i,j,ii,jj,k,n,inum,jnum; double xtmp,ytmp,ztmp,delx,dely,delz,rsq; int *ilist,*jlist,*numneigh,**firstneigh; int chi[8]; invoked_peratom = update->ntimestep; // grow structure array if necessary if (atom->nlocal > nmax) { memory->destroy(structure); nmax = atom->nmax; memory->create(structure,nmax,"compute/ackland/atom:ackland"); vector_atom = structure; } // invoke full neighbor list (will copy or build if necessary) neighbor->build_one(list->index); inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // compute structure parameter for each atom in group // use full neighbor list double **x = atom->x; int *mask = atom->mask; - int nall = atom->nlocal + atom->nghost; double cutsq = force->pair->cutforce * force->pair->cutforce; 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]; // ensure distsq and nearest arrays are long enough if (jnum > maxneigh) { memory->destroy(distsq); memory->destroy(nearest); memory->destroy(nearest_n0); memory->destroy(nearest_n1); maxneigh = jnum; memory->create(distsq,maxneigh,"compute/ackland/atom:distsq"); memory->create(nearest,maxneigh,"compute/ackland/atom:nearest"); memory->create(nearest_n0,maxneigh,"compute/ackland/atom:nearest_n0"); memory->create(nearest_n1,maxneigh,"compute/ackland/atom:nearest_n1"); } // loop over list of all neighbors within force cutoff // distsq[] = distance sq to each // nearest[] = atom indices of neighbors n = 0; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; - if (j >= nall) j %= nall; + 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 < cutsq) { distsq[n] = rsq; nearest[n++] = j; } } // Select 6 nearest neighbors select2(6,n,distsq,nearest); // Mean squared separation double r0_sq = 0.; for (j = 0; j < 6; j++) r0_sq += distsq[j]; r0_sq /= 6.; // n0 near neighbors with: distsq<1.45*r0_sq // n1 near neighbors with: distsq<1.55*r0_sq double n0_dist_sq = 1.45*r0_sq, n1_dist_sq = 1.55*r0_sq; int n0 = 0, n1 = 0; for (j = 0; j < n; j++) { if (distsq[j] < n1_dist_sq) { nearest_n1[n1++] = nearest[j]; if (distsq[j] < n0_dist_sq) { nearest_n0[n0++] = nearest[j]; } } } // Evaluate all angles <(r_ij,rik) forall n0 particles with: distsq<1.45*r0_sq double bond_angle; double norm_j, norm_k; chi[0] = chi[1] = chi[2] = chi[3] = chi[4] = chi[5] = chi[6] = chi[7] = 0; double x_ij, y_ij, z_ij, x_ik, y_ik, z_ik; for (j = 0; j < n0; j++) { x_ij = x[i][0]-x[nearest_n0[j]][0]; y_ij = x[i][1]-x[nearest_n0[j]][1]; z_ij = x[i][2]-x[nearest_n0[j]][2]; norm_j = sqrt (x_ij*x_ij + y_ij*y_ij + z_ij*z_ij); if (norm_j <= 0.) continue; for (k = j+1; k < n0; k++) { x_ik = x[i][0]-x[nearest_n0[k]][0]; y_ik = x[i][1]-x[nearest_n0[k]][1]; z_ik = x[i][2]-x[nearest_n0[k]][2]; norm_k = sqrt (x_ik*x_ik + y_ik*y_ik + z_ik*z_ik); if (norm_k <= 0.) continue; bond_angle = (x_ij*x_ik + y_ij*y_ik + z_ij*z_ik) / (norm_j*norm_k); // Histogram for identifying the relevant peaks if (-1. <= bond_angle && bond_angle < -0.945) { chi[0]++; } else if (-0.945 <= bond_angle && bond_angle < -0.915) { chi[1]++; } else if (-0.915 <= bond_angle && bond_angle < -0.755) { chi[2]++; } else if (-0.755 <= bond_angle && bond_angle < -0.195) { chi[3]++; } else if (-0.195 <= bond_angle && bond_angle < 0.195) { chi[4]++; } else if (0.195 <= bond_angle && bond_angle < 0.245) { chi[5]++; } else if (0.245 <= bond_angle && bond_angle < 0.795) { chi[6]++; } else if (0.795 <= bond_angle && bond_angle < 1.) { chi[7]++; } } } // Deviations from the different lattice structures double delta_bcc = 0.35*chi[4]/(double)(chi[5]+chi[6]-chi[4]), delta_cp = fabs(1.-(double)chi[6]/24.), delta_fcc = 0.61*(fabs((double)(chi[0]+chi[1]-6.))+(double)chi[2])/6., delta_hcp = (fabs((double)chi[0]-3.)+fabs((double)chi[0]+(double)chi[1]+(double)chi[2]+(double)chi[3]-9.))/12.; // Identification of the local structure according to the reference if (chi[0] == 7) { delta_bcc = 0.; } else if (chi[0] == 6) { delta_fcc = 0.; } else if (chi[0] <= 3) { delta_hcp = 0.; } if (chi[7] > 0.) structure[i] = UNKNOWN; else if (chi[4] < 3.) { if (n1 > 13 || n1 < 11) structure[i] = UNKNOWN; else structure[i] = ICO; } else if (delta_bcc <= delta_cp) { if (n1 < 11) structure[i] = UNKNOWN; else structure[i] = BCC; } else if (n1 > 12 || n1 < 11) structure[i] = UNKNOWN; else if (delta_fcc < delta_hcp) structure[i] = FCC; else structure[i] = HCP; } else structure[i] = 0.0; } } /* ---------------------------------------------------------------------- 2 select routines from Numerical Recipes (slightly modified) find k smallest values in array of length n 2nd routine sorts auxiliary array at same time ------------------------------------------------------------------------- */ #define SWAP(a,b) tmp = a; a = b; b = tmp; #define ISWAP(a,b) itmp = a; a = b; b = itmp; void ComputeAcklandAtom::select(int k, int n, double *arr) { int i,ir,j,l,mid; double a,tmp; arr--; l = 1; ir = n; for (;;) { if (ir <= l+1) { if (ir == l+1 && arr[ir] < arr[l]) { SWAP(arr[l],arr[ir]) } return; } else { mid=(l+ir) >> 1; SWAP(arr[mid],arr[l+1]) if (arr[l] > arr[ir]) { SWAP(arr[l],arr[ir]) } if (arr[l+1] > arr[ir]) { SWAP(arr[l+1],arr[ir]) } if (arr[l] > arr[l+1]) { SWAP(arr[l],arr[l+1]) } i = l+1; j = ir; a = arr[l+1]; for (;;) { do i++; while (arr[i] < a); do j--; while (arr[j] > a); if (j < i) break; SWAP(arr[i],arr[j]) } arr[l+1] = arr[j]; arr[j] = a; if (j >= k) ir = j-1; if (j <= k) l = i; } } } /* ---------------------------------------------------------------------- */ void ComputeAcklandAtom::select2(int k, int n, double *arr, int *iarr) { int i,ir,j,l,mid,ia,itmp; double a,tmp; arr--; iarr--; l = 1; ir = n; for (;;) { if (ir <= l+1) { if (ir == l+1 && arr[ir] < arr[l]) { SWAP(arr[l],arr[ir]) ISWAP(iarr[l],iarr[ir]) } return; } else { mid=(l+ir) >> 1; SWAP(arr[mid],arr[l+1]) ISWAP(iarr[mid],iarr[l+1]) if (arr[l] > arr[ir]) { SWAP(arr[l],arr[ir]) ISWAP(iarr[l],iarr[ir]) } if (arr[l+1] > arr[ir]) { SWAP(arr[l+1],arr[ir]) ISWAP(iarr[l+1],iarr[ir]) } if (arr[l] > arr[l+1]) { SWAP(arr[l],arr[l+1]) ISWAP(iarr[l],iarr[l+1]) } i = l+1; j = ir; a = arr[l+1]; ia = iarr[l+1]; for (;;) { do i++; while (arr[i] < a); do j--; while (arr[j] > a); if (j < i) break; SWAP(arr[i],arr[j]) ISWAP(iarr[i],iarr[j]) } arr[l+1] = arr[j]; arr[j] = a; iarr[l+1] = iarr[j]; iarr[j] = ia; if (j >= k) ir = j-1; if (j <= k) l = i; } } } /* ---------------------------------------------------------------------- memory usage of local atom-based array ------------------------------------------------------------------------- */ double ComputeAcklandAtom::memory_usage() { double bytes = nmax * sizeof(double); return bytes; } diff --git a/src/USER-CD-EAM/pair_cdeam.cpp b/src/USER-CD-EAM/pair_cdeam.cpp index efa829f80..5dc2ede1a 100644 --- a/src/USER-CD-EAM/pair_cdeam.cpp +++ b/src/USER-CD-EAM/pair_cdeam.cpp @@ -1,639 +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 author: Alexander Stukowski Technical University of Darmstadt, Germany Department of Materials Science ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "pair_cdeam.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; // This is for debugging purposes. The ASSERT() macro is used in the code to check // if everything runs as expected. Change this to #if 0 if you don't need the checking. #if 0 #define ASSERT(cond) ((!(cond)) ? my_failure(error,__FILE__,__LINE__) : my_noop()) inline void my_noop() {} inline void my_failure(Error* error, const char* file, int line) { char str[1024]; sprintf(str,"Assertion failure: File %s, line %i", file, line); error->one(str); } #else #define ASSERT(cond) #endif #define MAXLINE 1024 // This sets the maximum line length in EAM input files. PairCDEAM::PairCDEAM(LAMMPS *lmp, int _cdeamVersion) : PairEAM(lmp), PairEAMAlloy(lmp), cdeamVersion(_cdeamVersion) { single_enable = 0; rhoB = NULL; D_values = NULL; hcoeff = NULL; // Set communication buffer sizes needed by this pair style. if(cdeamVersion == 1) { comm_forward = 4; comm_reverse = 3; } else if(cdeamVersion == 2) { comm_forward = 3; comm_reverse = 2; } else { error->all("Invalid CD-EAM potential version."); } } PairCDEAM::~PairCDEAM() { memory->destroy(rhoB); memory->destroy(D_values); if(hcoeff) delete[] hcoeff; } void PairCDEAM::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,rhoip,rhojp,recip,phi; 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 per-atom arrays if necessary if(atom->nmax > nmax) { memory->destroy(rho); memory->destroy(fp); memory->destroy(rhoB); memory->destroy(D_values); nmax = atom->nmax; memory->create(rho,nmax,"pair:rho"); memory->create(rhoB,nmax,"pair:rhoB"); memory->create(fp,nmax,"pair:fp"); memory->create(D_values,nmax,"pair:D_values"); } 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; // Zero out per-atom arrays. int m = nlocal + atom->nghost; for(i = 0; i < m; i++) { rho[i] = 0.0; rhoB[i] = 0.0; D_values[i] = 0.0; } // Stage I // Compute rho and rhoB at each local atom site. // Additionally calculate the D_i values here if we are using the one-site formulation. // For the two-site formulation we have to calculate the D values in an extra loop (Stage II). 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]; double r = sqrt(rsq); const EAMTableIndex index = radiusToTableIndex(r); double localrho = RhoOfR(index, jtype, itype); rho[i] += localrho; if(jtype == speciesB) rhoB[i] += localrho; if(newton_pair || j < nlocal) { localrho = RhoOfR(index, itype, jtype); rho[j] += localrho; if(itype == speciesB) rhoB[j] += localrho; } if(cdeamVersion == 1 && itype != jtype) { // Note: if the i-j interaction is not concentration dependent (because either // i or j are not species A or B) then its contribution to D_i and D_j should // be ignored. // This if-clause is only required for a ternary. if((itype == speciesA && jtype == speciesB) || (jtype == speciesA && itype == speciesB)) { double Phi_AB = PhiOfR(index, itype, jtype, 1.0 / r); D_values[i] += Phi_AB; if(newton_pair || j < nlocal) D_values[j] += Phi_AB; } } } } } // Communicate and sum densities. if(newton_pair) { communicationStage = 1; comm->reverse_comm_pair(this); } // fp = derivative of embedding energy at each atom // phi = embedding energy at each atom for(ii = 0; ii < inum; ii++) { i = ilist[ii]; EAMTableIndex index = rhoToTableIndex(rho[i]); fp[i] = FPrimeOfRho(index, type[i]); if(eflag) { phi = FofRho(index, type[i]); if (eflag_global) eng_vdwl += phi; if (eflag_atom) eatom[i] += phi; } } // Communicate derivative of embedding function and densities // and D_values (this for one-site formulation only). communicationStage = 2; comm->forward_comm_pair(this); // The electron densities may not drop to zero because then the concentration would no longer be defined. // But the concentration is not needed anyway if there is no interaction with another atom, which is the case // if the electron density is exactly zero. That's why the following lines have been commented out. // //for(i = 0; i < nlocal + atom->nghost; i++) { // if(rho[i] == 0 && (type[i] == speciesA || type[i] == speciesB)) // error->one("CD-EAM potential routine: Detected atom with zero electron density."); //} // Stage II // This is only required for the original two-site formulation of the CD-EAM potential. if(cdeamVersion == 2) { // Compute intermediate value D_i for each atom. 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]; // This code line is required for ternary alloys. if(itype != speciesA && itype != speciesB) continue; double x_i = rhoB[i] / rho[i]; // Concentration at atom i. for(jj = 0; jj < jnum; jj++) { j = jlist[jj]; + j &= NEIGHMASK; jtype = type[j]; if(itype == jtype) continue; // This code line is required for ternary alloys. if(jtype != speciesA && jtype != speciesB) continue; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; if(rsq < cutforcesq) { double r = sqrt(rsq); const EAMTableIndex index = radiusToTableIndex(r); // The concentration independent part of the cross pair potential. double Phi_AB = PhiOfR(index, itype, jtype, 1.0 / r); // Average concentration of two sites double x_ij = 0.5 * (x_i + rhoB[j]/rho[j]); // Calculate derivative of h(x_ij) polynomial function. double h_prime = evalHprime(x_ij); D_values[i] += h_prime * Phi_AB / (2.0 * rho[i] * rho[i]); if(newton_pair || j < nlocal) D_values[j] += h_prime * Phi_AB / (2.0 * rho[j] * rho[j]); } } } // Communicate and sum D values. if(newton_pair) { communicationStage = 3; comm->reverse_comm_pair(this); } communicationStage = 4; comm->forward_comm_pair(this); } // Stage III // Compute force acting on each atom. 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]; // Concentration at site i double x_i = -1.0; // The value -1 indicates: no concentration dependence for all interactions of atom i. // It will be replaced by the concentration at site i if atom i is either A or B. double D_i, h_prime_i; // This if-clause is only required for ternary alloys. if((itype == speciesA || itype == speciesB) && rho[i] != 0.0) { // Compute local concentration at site i. x_i = rhoB[i]/rho[i]; ASSERT(x_i >= 0 && x_i<=1.0); if(cdeamVersion == 1) { // Calculate derivative of h(x_i) polynomial function. h_prime_i = evalHprime(x_i); D_i = D_values[i] * h_prime_i / (2.0 * rho[i] * rho[i]); } else if(cdeamVersion == 2) { D_i = D_values[i]; } else ASSERT(false); } 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]; double r = sqrt(rsq); const EAMTableIndex index = radiusToTableIndex(r); // rhoip = derivative of (density at atom j due to atom i) // rhojp = derivative of (density at atom i due to atom j) // 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 rhoip = RhoPrimeOfR(index, itype, jtype); rhojp = RhoPrimeOfR(index, jtype, itype); fpair = fp[i]*rhojp + fp[j]*rhoip; recip = 1.0/r; double x_j = -1; // The value -1 indicates: no concentration dependence for this i-j pair // because atom j is not of species A nor B. // This code line is required for ternary alloy. if(jtype == speciesA || jtype == speciesB) { ASSERT(rho[i] != 0.0); ASSERT(rho[j] != 0.0); // Compute local concentration at site j. x_j = rhoB[j]/rho[j]; ASSERT(x_j >= 0 && x_j<=1.0); double D_j; if(cdeamVersion == 1) { // Calculate derivative of h(x_j) polynomial function. double h_prime_j = evalHprime(x_j); D_j = D_values[j] * h_prime_j / (2.0 * rho[j] * rho[j]); } else if(cdeamVersion == 2) { D_j = D_values[j]; } else ASSERT(false); double t2 = -rhoB[j]; if(itype == speciesB) t2 += rho[j]; fpair += D_j * rhoip * t2; } // This if-clause is only required for a ternary alloy. // Actually we don't need it at all because D_i should be zero anyway if // atom i has no concentration dependent interactions (because it is not species A or B). if(x_i != -1.0) { double t1 = -rhoB[i]; if(jtype == speciesB) t1 += rho[i]; fpair += D_i * rhojp * t1; } double phip; double phi = PhiOfR(index, itype, jtype, recip, phip); if(itype == jtype || x_i == -1.0 || x_j == -1.0) { // Case of no concentration dependence. fpair += phip; } else { // We have a concentration dependence for the i-j interaction. double h; if(cdeamVersion == 1) { // Calculate h(x_i) polynomial function. double h_i = evalH(x_i); // Calculate h(x_j) polynomial function. double h_j = evalH(x_j); h = 0.5 * (h_i + h_j); } else if(cdeamVersion == 2) { // Average concentration. double x_ij = 0.5 * (x_i + x_j); // Calculate h(x_ij) polynomial function. h = evalH(x_ij); } else ASSERT(false); fpair += h * phip; phi *= h; } // Divide by r_ij and negate to get forces from gradient. fpair /= -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 = phi; if(evflag) ev_tally(i,j,nlocal,newton_pair,evdwl,0.0,fpair,delx,dely,delz); } } } if(vflag_fdotr) virial_compute(); } /* ---------------------------------------------------------------------- */ void PairCDEAM::coeff(int narg, char **arg) { PairEAMAlloy::coeff(narg, arg); // Make sure the EAM file is a CD-EAM binary alloy. if(setfl->nelements < 2) error->all("The EAM file must contain at least 2 elements to be used with the eam/cd pair style."); // Read in the coefficients of the h polynomial from the end of the EAM file. read_h_coeff(arg[2]); // Determine which atom type is the A species and which is the B species in the alloy. // By default take the first element (index 0) in the EAM file as the A species // and the second element (index 1) in the EAM file as the B species. speciesA = -1; speciesB = -1; for(int i = 1; i <= atom->ntypes; i++) { if(map[i] == 0) { if(speciesA >= 0) error->all("The first element from the EAM file may only be mapped to a single atom type."); speciesA = i; } if(map[i] == 1) { if(speciesB >= 0) error->all("The second element from the EAM file may only be mapped to a single atom type."); speciesB = i; } } if(speciesA < 0) error->all("The first element from the EAM file must be mapped to exactly one atom type."); if(speciesB < 0) error->all("The second element from the EAM file must be mapped to exactly one atom type."); } /* ---------------------------------------------------------------------- Reads in the h(x) polynomial coefficients ------------------------------------------------------------------------- */ void PairCDEAM::read_h_coeff(char *filename) { if(comm->me == 0) { // Open potential file FILE *fp; char line[MAXLINE]; char nextline[MAXLINE]; fp = fopen(filename,"r"); if (fp == NULL) { char str[128]; sprintf(str,"Cannot open EAM potential file %s", filename); error->one(str); } // h coefficients are stored at the end of the file. // Skip to last line of file. while(fgets(nextline, MAXLINE, fp) != NULL) { strcpy(line, nextline); } char* ptr = strtok(line, " \t\n\r\f"); int degree = atoi(ptr); nhcoeff = degree+1; hcoeff = new double[nhcoeff]; int i = 0; while((ptr = strtok(NULL," \t\n\r\f")) != NULL && i < nhcoeff) { hcoeff[i++] = atof(ptr); } if(i != nhcoeff || nhcoeff < 1) error->one("Failed to read h(x) function coefficients from EAM file."); // Close the potential file. fclose(fp); } MPI_Bcast(&nhcoeff, 1, MPI_INT, 0, world); if(comm->me != 0) hcoeff = new double[nhcoeff]; MPI_Bcast(hcoeff, nhcoeff, MPI_DOUBLE, 0, world); } /* ---------------------------------------------------------------------- */ int PairCDEAM::pack_comm(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; m = 0; if(communicationStage == 2) { if(cdeamVersion == 1) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = fp[j]; buf[m++] = rho[j]; buf[m++] = rhoB[j]; buf[m++] = D_values[j]; } return 4; } else if(cdeamVersion == 2) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = fp[j]; buf[m++] = rho[j]; buf[m++] = rhoB[j]; } return 3; } else { ASSERT(false); return 0; } } else if(communicationStage == 4) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = D_values[j]; } return 1; } else return 0; } /* ---------------------------------------------------------------------- */ void PairCDEAM::unpack_comm(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; if(communicationStage == 2) { if(cdeamVersion == 1) { for(i = first; i < last; i++) { fp[i] = buf[m++]; rho[i] = buf[m++]; rhoB[i] = buf[m++]; D_values[i] = buf[m++]; } } else if(cdeamVersion == 2) { for(i = first; i < last; i++) { fp[i] = buf[m++]; rho[i] = buf[m++]; rhoB[i] = buf[m++]; } } else ASSERT(false); } else if(communicationStage == 4) { for(i = first; i < last; i++) { D_values[i] = buf[m++]; } } } /* ---------------------------------------------------------------------- */ int PairCDEAM::pack_reverse_comm(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; if(communicationStage == 1) { if(cdeamVersion == 1) { for(i = first; i < last; i++) { buf[m++] = rho[i]; buf[m++] = rhoB[i]; buf[m++] = D_values[i]; } return 3; } else if(cdeamVersion == 2) { for(i = first; i < last; i++) { buf[m++] = rho[i]; buf[m++] = rhoB[i]; } return 2; } else { ASSERT(false); return 0; } } else if(communicationStage == 3) { for(i = first; i < last; i++) { buf[m++] = D_values[i]; } return 1; } else return 0; } /* ---------------------------------------------------------------------- */ void PairCDEAM::unpack_reverse_comm(int n, int *list, double *buf) { int i,j,m; m = 0; if(communicationStage == 1) { if(cdeamVersion == 1) { for(i = 0; i < n; i++) { j = list[i]; rho[j] += buf[m++]; rhoB[j] += buf[m++]; D_values[j] += buf[m++]; } } else if(cdeamVersion == 2) { for(i = 0; i < n; i++) { j = list[i]; rho[j] += buf[m++]; rhoB[j] += buf[m++]; } } else ASSERT(false); } else if(communicationStage == 3) { for(i = 0; i < n; i++) { j = list[i]; D_values[j] += buf[m++]; } } } /* ---------------------------------------------------------------------- memory usage of local atom-based arrays ------------------------------------------------------------------------- */ double PairCDEAM::memory_usage() { double bytes = 2 * nmax * sizeof(double); return PairEAMAlloy::memory_usage() + bytes; } diff --git a/src/USER-CG-CMM/pair_cmm_common.cpp b/src/USER-CG-CMM/pair_cmm_common.cpp index fb8bf72a8..8dc7e9cac 100644 --- a/src/USER-CG-CMM/pair_cmm_common.cpp +++ b/src/USER-CG-CMM/pair_cmm_common.cpp @@ -1,478 +1,476 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Common functionality for the CMM coarse grained MD potentials. Contributing author: Axel Kohlmeyer ------------------------------------------------------------------------- */ #include "pair_cmm_common.h" #include "memory.h" #include "stdlib.h" #include "string.h" #include "ctype.h" #include "math.h" using namespace LAMMPS_NS; #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define SMALL 1.0e-6 /* ---------------------------------------------------------------------- */ PairCMMCommon::PairCMMCommon(class LAMMPS *lmp) : Pair(lmp) { ftable = NULL; allocated_coul = 0; kappa = 0.0; respa_enable = 0; single_enable = 0; } /* ---------------------------------------------------------------------- * * clean up common arrays * * ---------------------------------------------------------------------- */ PairCMMCommon::~PairCMMCommon() { if (allocated) { memory->destroy(setflag); memory->destroy(cg_type); memory->destroy(cut); memory->destroy(cutsq); memory->destroy(epsilon); memory->destroy(sigma); memory->destroy(offset); memory->destroy(lj1); memory->destroy(lj2); memory->destroy(lj3); memory->destroy(lj4); allocated = 0; } } /* ---------------------------------------------------------------------- * * allocate common arrays * * ---------------------------------------------------------------------- */ void PairCMMCommon::allocate() { allocated = 1; int n = atom->ntypes; memory->create(setflag,n+1,n+1,"paircg:setflag"); memory->create(cg_type,n+1,n+1,"paircg:cg_type"); for (int i = 1; i <= n; i++) { for (int j = i; j <= n; j++) { setflag[i][j] = 0; cg_type[i][j] = CG_NOT_SET; } } memory->create(cut,n+1,n+1,"paircg:cut"); memory->create(cutsq,n+1,n+1,"paircg:cutsq"); memory->create(epsilon,n+1,n+1,"paircg:epsilon"); memory->create(sigma,n+1,n+1,"paircg:sigma"); memory->create(offset,n+1,n+1,"paircg:offset"); memory->create(lj1,n+1,n+1,"paircg:lj1"); memory->create(lj2,n+1,n+1,"paircg:lj2"); memory->create(lj3,n+1,n+1,"paircg:lj3"); memory->create(lj4,n+1,n+1,"paircg:lj4"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ // arguments to the pair_style command (global version) // args = cutoff (cutoff2 (kappa)) void PairCMMCommon::settings(int narg, char **arg) { if ((narg < 1) || (narg > 3)) error->all("Illegal pair_style command"); cut_lj_global = force->numeric(arg[0]); if (narg == 1) cut_coul_global = cut_lj_global; else cut_coul_global = force->numeric(arg[1]); cut_coulsq_global = cut_coul_global*cut_coul_global; // exponential coulomb screening (optional) if (narg == 3) kappa = force->numeric(arg[2]); if (fabs(kappa) < SMALL) kappa=0.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_lj_global; if (allocated_coul) { cut[i][j] = MAX(cut_lj_global,cut_coul_global); cut_lj[i][j] = cut_lj_global; cut_coul[i][j] = cut_coul_global; } } } } } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairCMMCommon::coeff(int narg, char **arg) { if (narg < 5 || narg > 7) error->all("Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); int cg_type_one=find_cg_type(arg[2]); if (cg_type_one == CG_NOT_SET) error->all("Error reading CG type flag."); double epsilon_one = force->numeric(arg[3]); double sigma_one = force->numeric(arg[4]); double cut_lj_one = cut_lj_global; double cut_coul_one = cut_coul_global; if (narg >= 6) cut_lj_one = force->numeric(arg[5]); if (narg == 7) cut_coul_one = force->numeric(arg[6]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { cg_type[i][j] = cg_type_one; epsilon[i][j] = epsilon_one; sigma[i][j] = sigma_one; setflag[i][j] = 1; if (allocated_coul) { cut_lj[i][j] = cut_lj_one; cut_coul[i][j] = cut_coul_one; } else { cut[i][j] = cut_lj_one; } count++; } } if (count == 0) error->all("Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairCMMCommon::init_style() { // request regular or rRESPA neighbor lists int irequest; if (update->whichflag == 0 && strcmp(update->integrate_style,"respa") == 0) { int respa = 0; if (((Respa *) update->integrate)->level_inner >= 0) respa = 1; if (((Respa *) update->integrate)->level_middle >= 0) respa = 2; if (respa == 0) irequest = neighbor->request(this); else if (respa == 1) { irequest = neighbor->request(this); neighbor->requests[irequest]->id = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respainner = 1; irequest = neighbor->request(this); neighbor->requests[irequest]->id = 3; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respaouter = 1; } else { irequest = neighbor->request(this); neighbor->requests[irequest]->id = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respainner = 1; irequest = neighbor->request(this); neighbor->requests[irequest]->id = 2; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respamiddle = 1; irequest = neighbor->request(this); neighbor->requests[irequest]->id = 3; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respaouter = 1; } } else irequest = neighbor->request(this); } /* ---------------------------------------------------------------------- neighbor callback to inform pair style of neighbor list to use regular or rRESPA ------------------------------------------------------------------------- */ void PairCMMCommon::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 PairCMMCommon::init_one(int i, int j) { if (setflag[i][j] == 0) { error->all("for CG styles, epsilon and sigma need to be set explicitly for all pairs."); } const int cgt = cg_type[i][j]; if (cgt == CG_NOT_SET) error->all("unrecognized LJ parameter flag"); lj1[i][j] = cg_prefact[cgt] * cg_pow1[cgt] * epsilon[i][j] * pow(sigma[i][j],cg_pow1[cgt]); lj2[i][j] = cg_prefact[cgt] * cg_pow2[cgt] * epsilon[i][j] * pow(sigma[i][j],cg_pow2[cgt]); lj3[i][j] = cg_prefact[cgt] * epsilon[i][j] * pow(sigma[i][j],cg_pow1[cgt]); lj4[i][j] = cg_prefact[cgt] * epsilon[i][j] * pow(sigma[i][j],cg_pow2[cgt]); double mycut = cut[i][j]; if (offset_flag) { double ratio = sigma[i][j] / mycut; offset[i][j] = cg_prefact[cgt] * epsilon[i][j] * (pow(ratio,cg_pow1[cgt]) - pow(ratio,cg_pow2[cgt])); } else offset[i][j] = 0.0; if (allocated_coul) { mycut = MAX(cut_lj[i][j],cut_coul[i][j]); cut[i][j] = mycut; cut_ljsq[i][j]=cut_lj[i][j]*cut_lj[i][j]; cut_coulsq[i][j]=cut_coul[i][j]*cut_coul[i][j]; if (offset_flag) { double ratio = sigma[i][j] / cut_lj[i][j]; offset[i][j] = cg_prefact[cgt] * epsilon[i][j] * (pow(ratio,cg_pow1[cgt]) - pow(ratio,cg_pow2[cgt])); } else offset[i][j] = 0.0; } // make sure data is stored symmetrically 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]; cg_type[j][i] = cg_type[i][j]; cut[j][i] = mycut; if (allocated_coul) { cut_lj[j][i]=cut_lj[i][j]; cut_ljsq[j][i]=cut_ljsq[i][j]; cut_coul[j][i]=cut_coul[i][j]; cut_coulsq[j][i]=cut_coulsq[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) { #if 1 error->all("tail correction not (yet) supported by CG potentials."); #else 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 PI = 4.0*atan(1.0); 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*PI*all[0]*all[1]*epsilon[i][j] * sig6 * (sig6 - 3.0*rc6) / (9.0*rc9); ptail_ij = 16.0*PI*all[0]*all[1]*epsilon[i][j] * sig6 * (2.0*sig6 - 3.0*rc6) / (9.0*rc9); #endif } return mycut; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairCMMCommon::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(&cg_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); if (allocated_coul) { 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 PairCMMCommon::read_restart(FILE *fp) { 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(&cg_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); if(allocated_coul) { fread(&cut_lj[i][j],sizeof(double),1,fp); fread(&cut_coul[i][j],sizeof(double),1,fp); } } MPI_Bcast(&cg_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); if (allocated_coul) { 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 PairCMMCommon::write_restart_settings(FILE *fp) { fwrite(&cut_lj_global,sizeof(double),1,fp); fwrite(&cut_coul_global,sizeof(double),1,fp); fwrite(&kappa,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 PairCMMCommon::read_restart_settings(FILE *fp) { int me = comm->me; if (me == 0) { fread(&cut_lj_global,sizeof(double),1,fp); fread(&cut_coul_global,sizeof(double),1,fp); fread(&kappa,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(&kappa,1,MPI_DOUBLE,0,world); MPI_Bcast(&offset_flag,1,MPI_INT,0,world); MPI_Bcast(&mix_flag,1,MPI_INT,0,world); cut_coulsq_global = cut_coul_global*cut_coul_global; } /* ---------------------------------------------------------------------- */ double PairCMMCommon::memory_usage() { double bytes=Pair::memory_usage(); int n = atom->ntypes; // setflag/cg_type bytes += (n+1)*(n+1)*sizeof(int)*2; // cut/cutsq/epsilon/sigma/offset/lj1/lj2/lj3/lj4 bytes += (n+1)*(n+1)*sizeof(double)*9; return bytes; } /* ------------------------------------------------------------------------ */ double PairCMMCommon::eval_single(int coul_type, int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double lj_force, lj_erg, coul_force, coul_erg; lj_force=lj_erg=coul_force=coul_erg=0.0; if (rsq < cut_ljsq[itype][jtype]) { const int cgt = cg_type[itype][jtype]; const double cgpow1 = cg_pow1[cgt]; const double cgpow2 = cg_pow2[cgt]; const double cgpref = cg_prefact[cgt]; const double ratio = sigma[itype][jtype]/sqrt(rsq); const double eps = epsilon[itype][jtype]; lj_force = cgpref*eps * (cgpow1*pow(ratio,cgpow1) - cgpow2*pow(ratio,cgpow2))/rsq; lj_erg = cgpref*eps * (pow(ratio,cgpow1) - pow(ratio,cgpow2)); } if (rsq < cut_coul[itype][jtype]) { if(coul_type == CG_COUL_LONG) { error->all("single energy computation with long-range coulomb not supported by CG potentials."); } else if ((coul_type == CG_COUL_CUT) || (coul_type == CG_COUL_DEBYE)) { const double r2inv = 1.0/rsq; const double rinv = sqrt(r2inv); const double qscreen=exp(-kappa*sqrt(rsq)); coul_force = force->qqrd2e * atom->q[i]*atom->q[j]*rinv * qscreen * (kappa + rinv); coul_erg = force->qqrd2e * atom->q[i]*atom->q[j]*rinv * qscreen; // error->all("single energy computation with coulomb not supported by CG potentials."); } else if (coul_type == CG_COUL_NONE) { ; // do nothing } else { error->all("unknown coulomb type with CG potentials."); } } fforce = factor_lj*lj_force + factor_coul*coul_force; return factor_lj*lj_erg + factor_coul*coul_erg; } - -/* ------------------------------------------------------------------------ */ diff --git a/src/USER-CG-CMM/pair_cmm_common.h b/src/USER-CG-CMM/pair_cmm_common.h index 6d5d1a583..43132abac 100644 --- a/src/USER-CG-CMM/pair_cmm_common.h +++ b/src/USER-CG-CMM/pair_cmm_common.h @@ -1,722 +1,698 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Common functionality for the CMM coarse grained MD potentials. Contributing author: Axel Kohlmeyer ------------------------------------------------------------------------- */ #ifndef LMP_PAIR_CMM_COMMON_H #define LMP_PAIR_CMM_COMMON_H #include "pair.h" #include "atom.h" #include "comm.h" #include "error.h" #include "force.h" #include "neighbor.h" #include "neigh_list.h" #include "neigh_request.h" #include "respa.h" #include "update.h" #include "cg_cmm_parms.h" #include "math.h" namespace LAMMPS_NS { #define EWALD_F 1.12837917 #define EWALD_P 0.3275911 #define EWALD_A1 0.254829592 #define EWALD_A2 -0.284496736 #define EWALD_A3 1.421413741 #define EWALD_A4 -1.453152027 #define EWALD_A5 1.061405429 class PairCMMCommon : public Pair , public CGCMMParms { public: PairCMMCommon(class LAMMPS *); virtual ~PairCMMCommon(); virtual void settings(int, char **); virtual void coeff(int, char **); virtual void init_style(); virtual void init_list(int, class NeighList *); virtual double init_one(int, int); virtual void write_restart(FILE *); virtual void read_restart(FILE *); virtual void write_restart_settings(FILE *); virtual void read_restart_settings(FILE *); virtual double memory_usage(); protected: // coarse grain flags int **cg_type; // lennard jones parameters double cut_lj_global, **cut, **cut_lj, **cut_ljsq; double **epsilon, **sigma; double **lj1, **lj2, **lj3, **lj4, **offset; // coulomb parameters int allocated_coul; // 0/1 = whether coulomb arrays are allocated double cut_coul_global, cut_coulsq_global, kappa, g_ewald; double **cut_coul, **cut_coulsq; // tables double tabinnersq; double *rtable,*drtable,*ftable,*dftable,*ctable,*dctable; double *etable,*detable,*ptable,*dptable,*vtable,*dvtable; int ncoulshiftbits,ncoulmask; // r-RESPA parameters double *cut_respa; // methods virtual void allocate(); private: // disable default constructor PairCMMCommon(); protected: // general optimizeable real space loops template < const int EVFLAG, const int EFLAG, const int NEWTON_PAIR, const int COUL_TYPE > void eval_verlet(); template < const int NEWTON_PAIR, const int COUL_TYPE > void eval_inner(); template < const int NEWTON_PAIR, const int COUL_TYPE > void eval_middle(); template < const int EVFLAG, const int EFLAG, const int VFLAG, const int NEWTON_PAIR, const int COUL_TYPE > void eval_outer(); // this one is not performance critical... no template needed. double eval_single(int, int, int, int, int, double, double, double, double &); }; /* ---------------------------------------------------------------------- */ /* this is the inner heart of the CG potentials. */ #define CG_LJ_INNER(eflag,fvar) \ fvar=factor_lj; \ if (eflag) evdwl=factor_lj; \ \ if (cgt == CG_LJ12_4) { \ const double r4inv=r2inv*r2inv; \ \ fvar *= 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 (cgt == CG_LJ9_6) { \ const double r3inv = r2inv*sqrt(r2inv); \ const double r6inv = r3inv*r3inv; \ fvar *= r6inv*(lj1[itype][jtype]*r3inv \ - lj2[itype][jtype]); \ if (eflag) { \ evdwl *= r6inv*(lj3[itype][jtype]*r3inv \ - lj4[itype][jtype]) - offset[itype][jtype]; \ } \ } else if (cgt == CG_LJ12_6) { \ const double r6inv = r2inv*r2inv*r2inv; \ fvar *= r6inv*(lj1[itype][jtype]*r6inv \ - lj2[itype][jtype]); \ if (eflag) { \ evdwl *= r6inv*(lj3[itype][jtype]*r6inv \ - lj4[itype][jtype]) - offset[itype][jtype]; \ } \ } else { \ /* do nothing. this is a "cannot happen(TM)" case */ \ ; \ } #define CG_LJ_ENERGY(eflag) \ if (eflag) { \ evdwl=factor_lj; \ \ if (cgt == CG_LJ12_4) { \ const double r4inv=r2inv*r2inv; \ evdwl *= r4inv*(lj3[itype][jtype]*r4inv*r4inv \ - lj4[itype][jtype]) - offset[itype][jtype]; \ } else if (cgt == CG_LJ9_6) { \ const double r3inv = r2inv*sqrt(r2inv); \ const double r6inv = r3inv*r3inv; \ evdwl *= r6inv*(lj3[itype][jtype]*r3inv \ - lj4[itype][jtype]) - offset[itype][jtype]; \ } else if (cgt == CG_LJ12_6) { \ const double r6inv = r2inv*r2inv*r2inv; \ evdwl *= r6inv*(lj3[itype][jtype]*r6inv \ - lj4[itype][jtype]) - offset[itype][jtype]; \ } else { \ /* do nothing. this is a "cannot happen(TM)" case */ \ ; \ } \ } \ template < const int EVFLAG, const int EFLAG, const int NEWTON_PAIR, const int COUL_TYPE > void PairCMMCommon::eval_verlet() { double ** const x = atom->x; double ** const f = atom->f; const double * const q = atom->q; const int * const type = atom->type; const int nlocal = atom->nlocal; - const int nall = nlocal + atom->nghost; const double * const special_lj = force->special_lj; const double * const special_coul = force->special_coul; const double qqrd2e = force->qqrd2e; + double factor_lj,factor_coul; const int inum = list->inum; const int * const ilist = list->ilist; const int * const numneigh = list->numneigh; int * const * const firstneigh = list->firstneigh; // loop over neighbors of my atoms int ii,jj; for (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 qtmp = (COUL_TYPE != CG_COUL_NONE) ? q[i] : 0.0; const int itype = type[i]; const int * const jlist = firstneigh[i]; const int jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { int j2 = jlist[jj]; - - double factor_lj = 1.0; - double factor_coul = 1.0; - if (j2 >= nall) { - factor_lj = special_lj[j2/nall]; - if (COUL_TYPE != CG_COUL_NONE) factor_coul=special_coul[j2/nall]; - j2 %= nall; - } - const int j = j2; + factor_lj = special_lj[sbmask(j2)]; + factor_coul = special_coul[sbmask(j2)]; + const int j = j2 & NEIGHMASK; 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; const int jtype = type[j]; double evdwl = 0.0; double ecoul = 0.0; double fpair = 0.0; const double r2inv = 1.0/rsq; const int cgt=cg_type[itype][jtype]; if (rsq < cutsq[itype][jtype]) { if (COUL_TYPE == CG_COUL_NONE) { CG_LJ_INNER(EFLAG,fpair); fpair *= r2inv; } else { double forcelj = 0.0; double forcecoul = 0.0; if (rsq < cut_ljsq[itype][jtype]) { CG_LJ_INNER(EFLAG,forcelj); } // coulomb with cutoff and screening if ((COUL_TYPE == CG_COUL_CUT) || (COUL_TYPE == CG_COUL_DEBYE)) { if (rsq < cut_coulsq[itype][jtype]) { double r=sqrt(rsq); double qscreen=exp(-kappa*r); forcecoul = factor_coul * qqrd2e * qtmp * q[j] * qscreen * (kappa + 1.0/r); if (EFLAG) ecoul=factor_coul*qqrd2e * qtmp*q[j] * qscreen / r; } } if (COUL_TYPE == CG_COUL_LONG) { if (rsq < cut_coulsq_global) { if (!ncoultablebits || rsq <= tabinnersq) { const double r = sqrt(rsq); const double grij = g_ewald * r; const double expm2 = exp(-grij*grij); const double t = 1.0 / (1.0 + EWALD_P*grij); const double erfc = t * (EWALD_A1+t*(EWALD_A2+t*(EWALD_A3+t*(EWALD_A4+t*EWALD_A5)))) * expm2; const double 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; int itable = rsq_lookup.i & ncoulmask; itable >>= ncoulshiftbits; const double fraction = (rsq_lookup.f - rtable[itable]) * drtable[itable]; const double table = ftable[itable] + fraction*dftable[itable]; forcecoul = qtmp*q[j] * table; if (EFLAG) { const double table2 = etable[itable] + fraction*detable[itable]; ecoul = qtmp*q[j] * table2; } if (factor_coul < 1.0) { const double table2 = ctable[itable] + fraction*dctable[itable]; const double prefactor = qtmp*q[j] * table2; forcecoul -= (1.0-factor_coul)*prefactor; if (EFLAG) ecoul -= (1.0-factor_coul)*prefactor; } } } } 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 (EVFLAG) ev_tally(i,j,nlocal,NEWTON_PAIR, evdwl,ecoul,fpair,delx,dely,delz); } } } if (vflag_fdotr) virial_compute(); } /* ---------------------------------------------------------------------- */ template < const int NEWTON_PAIR, const int COUL_TYPE > void PairCMMCommon::eval_inner() { double ** const x = atom->x; double ** const f = atom->f; const double * const q = atom->q; const int * const type = atom->type; const int nlocal = atom->nlocal; - const int nall = nlocal + atom->nghost; const double * const special_lj = force->special_lj; const double * const special_coul = force->special_coul; const double qqrd2e = force->qqrd2e; + double factor_lj,factor_coul; const int inum = listinner->inum; const int * const ilist = listinner->ilist; const int * const numneigh = listinner->numneigh; int * const * const firstneigh = listinner->firstneigh; const double cut_out_on = cut_respa[0]; const double cut_out_off = cut_respa[1]; const double cut_out_diff = cut_out_off - cut_out_on; const double cut_out_on_sq = cut_out_on*cut_out_on; const double cut_out_off_sq = cut_out_off*cut_out_off; // loop over neighbors of my atoms int ii,jj; for (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 qtmp = (COUL_TYPE != CG_COUL_NONE) ? q[i] : 0.0; const int itype = type[i]; const int * const jlist = firstneigh[i]; const int jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { int j2 = jlist[jj]; - - double factor_lj = 1.0; - double factor_coul = 1.0; - if (j2 >= nall) { - factor_lj = special_lj[j2/nall]; - if (COUL_TYPE != CG_COUL_NONE) factor_coul=special_coul[j2/nall]; - j2 %= nall; - } - const int j = j2; + factor_lj = special_lj[sbmask(j2)]; + factor_coul = special_coul[sbmask(j2)]; + const int j = j2 & NEIGHMASK; 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; const int jtype = type[j]; double evdwl = 0.0; double ecoul = 0.0; double fpair = 0.0; const double r2inv = 1.0/rsq; const int cgt=cg_type[itype][jtype]; if (rsq < cut_out_off_sq) { if (COUL_TYPE == CG_COUL_NONE) { CG_LJ_INNER(0,fpair); fpair *= r2inv; if (rsq > cut_out_on_sq) { const double rsw = (sqrt(rsq) - cut_out_on)/cut_out_diff; fpair *= 1.0 - rsw*rsw*(3.0 - 2.0*rsw); } } else { double forcelj = 0.0; double forcecoul = 0.0; if (rsq < cut_ljsq[itype][jtype]) { CG_LJ_INNER(0,forcelj); } forcecoul = qqrd2e * qtmp*q[j]*sqrt(r2inv); if (factor_coul < 1.0) forcecoul -= (1.0 -factor_coul)*forcecoul; fpair = (forcecoul + forcelj) * r2inv; if (rsq > cut_out_on_sq) { const double 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; } } } } } /* ---------------------------------------------------------------------- */ template < const int NEWTON_PAIR, const int COUL_TYPE > void PairCMMCommon::eval_middle() { double ** const x = atom->x; double ** const f = atom->f; const double * const q = atom->q; const int * const type = atom->type; const int nlocal = atom->nlocal; - const int nall = nlocal + atom->nghost; const double * const special_lj = force->special_lj; const double * const special_coul = force->special_coul; const double qqrd2e = force->qqrd2e; + double factor_lj,factor_coul; const int inum = listmiddle->inum; const int * const ilist = listmiddle->ilist; const int * const numneigh = listmiddle->numneigh; int * const * const firstneigh = listmiddle->firstneigh; const double cut_in_off = cut_respa[0]; const double cut_in_on = cut_respa[1]; const double cut_out_on = cut_respa[2]; const double cut_out_off = cut_respa[3]; const double cut_in_diff = cut_in_on - cut_in_off; const double cut_out_diff = cut_out_off - cut_out_on; const double cut_in_off_sq = cut_in_off*cut_in_off; const double cut_in_on_sq = cut_in_on*cut_in_on; const double cut_out_on_sq = cut_out_on*cut_out_on; const double cut_out_off_sq = cut_out_off*cut_out_off; // loop over neighbors of my atoms int ii,jj; for (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 qtmp = (COUL_TYPE != CG_COUL_NONE) ? q[i] : 0.0; const int itype = type[i]; const int * const jlist = firstneigh[i]; const int jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { int j2 = jlist[jj]; - - double factor_lj = 1.0; - double factor_coul = 1.0; - if (j2 >= nall) { - factor_lj = special_lj[j2/nall]; - if (COUL_TYPE != CG_COUL_NONE) factor_coul=special_coul[j2/nall]; - j2 %= nall; - } - const int j = j2; + factor_lj = special_lj[sbmask(j2)]; + factor_coul = special_coul[sbmask(j2)]; + const int j = j2 & NEIGHMASK; 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; const int jtype = type[j]; double evdwl = 0.0; double ecoul = 0.0; double fpair = 0.0; const double r2inv = 1.0/rsq; const int cgt=cg_type[itype][jtype]; if (rsq < cut_out_off_sq && rsq > cut_in_off_sq) { if (COUL_TYPE == CG_COUL_NONE) { CG_LJ_INNER(0,fpair); fpair *= r2inv; if (rsq < cut_in_on_sq) { const double rsw = (sqrt(rsq) - cut_in_off)/cut_in_diff; fpair *= rsw*rsw*(3.0 - 2.0*rsw); } if (rsq > cut_out_on_sq) { const double rsw = (sqrt(rsq) - cut_out_on)/cut_out_diff; fpair *= 1.0 + rsw*rsw*(2.0*rsw - 3.0); } } else { double forcelj = 0.0; double forcecoul = 0.0; if (rsq < cut_ljsq[itype][jtype]) { CG_LJ_INNER(0,forcelj); } forcecoul = qqrd2e * qtmp*q[j]*sqrt(r2inv); if (factor_coul < 1.0) forcecoul -= (1.0 -factor_coul)*forcecoul; fpair = (forcecoul + forcelj) * r2inv; if (rsq < cut_in_on_sq) { const double rsw = (sqrt(rsq) - cut_in_off)/cut_in_diff; fpair *= rsw*rsw*(3.0 - 2.0*rsw); } if (rsq > cut_out_on_sq) { const double 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; } } } } } /* ---------------------------------------------------------------------- */ template < const int EVFLAG, const int EFLAG, const int VFLAG, const int NEWTON_PAIR, const int COUL_TYPE > void PairCMMCommon::eval_outer() { double ** const x = atom->x; double ** const f = atom->f; const double * const q = atom->q; const int * const type = atom->type; const int nlocal = atom->nlocal; - const int nall = nlocal + atom->nghost; const double * const special_lj = force->special_lj; const double * const special_coul = force->special_coul; const double qqrd2e = force->qqrd2e; + double factor_lj,factor_coul; const int inum = listouter->inum; const int * const ilist = listouter->ilist; const int * const numneigh = listouter->numneigh; int * const * const firstneigh = listouter->firstneigh; const double cut_in_off = cut_respa[2]; const double cut_in_on = cut_respa[3]; const double cut_in_diff = cut_in_on - cut_in_off; const double cut_in_off_sq = cut_in_off*cut_in_off; const double cut_in_on_sq = cut_in_on*cut_in_on; // loop over neighbors of my atoms int ii,jj; for (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 qtmp = (COUL_TYPE != CG_COUL_NONE) ? q[i] : 0.0; const int itype = type[i]; const int * const jlist = firstneigh[i]; const int jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { int j2 = jlist[jj]; - - double factor_lj = 1.0; - double factor_coul = 1.0; - if (j2 >= nall) { - factor_lj = special_lj[j2/nall]; - if (COUL_TYPE != CG_COUL_NONE) factor_coul=special_coul[j2/nall]; - j2 %= nall; - } - const int j = j2; + factor_lj = special_lj[sbmask(j2)]; + factor_coul = special_coul[sbmask(j2)]; + const int j = j2 & NEIGHMASK; 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; const int jtype = type[j]; double evdwl = 0.0; double ecoul = 0.0; double fpair = 0.0; const double r2inv = 1.0/rsq; const int cgt=cg_type[itype][jtype]; if (rsq < cutsq[itype][jtype]) { if (COUL_TYPE == CG_COUL_NONE) { double forcelj=0.0; if (rsq > cut_in_off_sq) { CG_LJ_INNER(0,forcelj); fpair = forcelj*r2inv; if (rsq < cut_in_on_sq) { const double 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; } } CG_LJ_ENERGY(EFLAG); if (VFLAG) { if (rsq <= cut_in_off_sq) { CG_LJ_INNER(0,fpair); fpair *= r2inv; } else if (rsq < cut_in_on_sq) { fpair = forcelj*r2inv; } } if (EVFLAG) ev_tally(i,j,nlocal,NEWTON_PAIR, evdwl,ecoul,fpair,delx,dely,delz); } else { double forcelj = 0.0; double forcecoul = 0.0; if (rsq < cut_ljsq[itype][jtype]) { CG_LJ_INNER(EFLAG,forcelj); } // coulomb with cutoff and screening if ((COUL_TYPE == CG_COUL_CUT) || (COUL_TYPE == CG_COUL_DEBYE)) { if (rsq < cut_coulsq[itype][jtype]) { double r=sqrt(rsq); double qscreen=exp(-kappa*r); forcecoul = factor_coul * qqrd2e * qtmp * q[j] * qscreen * (kappa + 1.0/r); if (EFLAG) ecoul=factor_coul*qqrd2e * qtmp*q[j] * qscreen / r; } } if (COUL_TYPE == CG_COUL_LONG) { if (rsq < cut_coulsq_global) { if (!ncoultablebits || rsq <= tabinnersq) { const double r = sqrt(rsq); const double grij = g_ewald * r; const double expm2 = exp(-grij*grij); const double t = 1.0 / (1.0 + EWALD_P*grij); const double erfc = t * (EWALD_A1+t*(EWALD_A2+t*(EWALD_A3+t*(EWALD_A4+t*EWALD_A5)))) * expm2; const double 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; int itable = rsq_lookup.i & ncoulmask; itable >>= ncoulshiftbits; const double fraction = (rsq_lookup.f - rtable[itable]) * drtable[itable]; const double table = ftable[itable] + fraction*dftable[itable]; forcecoul = qtmp*q[j] * table; if (EFLAG) { const double table2 = etable[itable] + fraction*detable[itable]; ecoul = qtmp*q[j] * table2; } if (factor_coul < 1.0) { const double table2 = ctable[itable] + fraction*dctable[itable]; const double prefactor = qtmp*q[j] * table2; forcecoul -= (1.0-factor_coul)*prefactor; if (EFLAG) ecoul -= (1.0-factor_coul)*prefactor; } } } } 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 (EVFLAG) ev_tally(i,j,nlocal,NEWTON_PAIR, evdwl,ecoul,fpair,delx,dely,delz); } } } } } /* ------------------------------------------------------------------------ */ } #undef EWALD_F #undef EWALD_P #undef EWALD_A1 #undef EWALD_A2 #undef EWALD_A3 #undef EWALD_A4 #undef EWALD_A5 #endif diff --git a/src/USER-EFF/pair_eff_cut.cpp b/src/USER-EFF/pair_eff_cut.cpp index 5cbebbf4e..47c99d283 100644 --- a/src/USER-EFF/pair_eff_cut.cpp +++ b/src/USER-EFF/pair_eff_cut.cpp @@ -1,956 +1,957 @@ /* ---------------------------------------------------------------------- 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 "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #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" using namespace LAMMPS_NS; #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) /* ---------------------------------------------------------------------- */ 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 = 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 (flexible_pressure_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); } // 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); } // 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 && flexible_pressure_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 && flexible_pressure_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 && flexible_pressure_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 && flexible_pressure_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 && flexible_pressure_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 (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, PAULI_CORE_B, PAULI_CORE_C); } 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); PauliCoreElec(rc,eradius[j],&ecp_epauli,&ecp_fpair, &ecp_e2rforce,PAULI_CORE_A, PAULI_CORE_B, PAULI_CORE_C); } // 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 && flexible_pressure_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 (abs(spin[j]) == 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,PAULI_CORE_B, PAULI_CORE_C); } 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); PauliCoreElec(rc,eradius[i],&ecp_epauli,&ecp_fpair, &ecp_e1rforce,PAULI_CORE_A, PAULI_CORE_B, PAULI_CORE_C); } // 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 && flexible_pressure_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 && abs(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_size_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 (flexible_pressure_flag) // flexible electron pressure ev_tally_eff(i,i,nlocal,newton_pair,0.0,eradius[i]*e1rforce); } } } } } if (vflag_fdotr) { virial_compute(); if (flexible_pressure_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 && narg != 3 && narg != 4 && narg != 7) error->all("Illegal pair_style command"); // Defaults ECP parameters for Si PAULI_CORE_A = 0.320852; PAULI_CORE_B = 2.283269; PAULI_CORE_C = 0.814857; if (narg == 1) { cut_global = force->numeric(arg[0]); limit_size_flag = 0; flexible_pressure_flag = 0; } else if (narg == 3) { cut_global = force->numeric(arg[0]); limit_size_flag = force->inumeric(arg[1]); flexible_pressure_flag = force->inumeric(arg[2]); } else if (narg == 4) { cut_global = force->numeric(arg[0]); limit_size_flag = 0; flexible_pressure_flag = 0; if (strcmp(arg[1],"ecp") != 0) error->all("Illegal pair_style command"); else { PAULI_CORE_A = force->numeric(arg[2]); PAULI_CORE_B = force->numeric(arg[3]); PAULI_CORE_C = force->numeric(arg[4]); } } else if (narg == 7) { cut_global = force->numeric(arg[0]); limit_size_flag = force->inumeric(arg[1]); flexible_pressure_flag = force->inumeric(arg[2]); if (strcmp(arg[3],"ecp") != 0) error->all("Illegal pair_style command"); else { PAULI_CORE_A = force->numeric(arg[4]); PAULI_CORE_B = force->numeric(arg[5]); PAULI_CORE_C = force->numeric(arg[6]); } } // 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("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; } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairEffCut::coeff(int narg, char **arg) { if (narg < 2 || narg > 3) error->all("Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); double cut_one = cut_global; if (narg == 3) cut_one = atof(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("Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- 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("Pair eff/cut requires atom attributes " "q, spin, eradius, erforce"); // 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("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); } /* ---------------------------------------------------------------------- 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-EWALDN/pair_buck_coul.cpp b/src/USER-EWALDN/pair_buck_coul.cpp index dc0060878..d2f3fdf14 100644 --- a/src/USER-EWALDN/pair_buck_coul.cpp +++ b/src/USER-EWALDN/pair_buck_coul.cpp @@ -1,1171 +1,1171 @@ /* ---------------------------------------------------------------------- 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 "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "math_vector.h" #include "pair_buck_coul.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 MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) #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 /* ---------------------------------------------------------------------- */ PairBuckCoul::PairBuckCoul(LAMMPS *lmp) : Pair(lmp) { respa_enable = 1; ftable = NULL; } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ #define PAIR_ILLEGAL "Illegal pair_style buck/coul command" #define PAIR_CUTOFF "Only one cut-off allowed when requesting all long" #define PAIR_MISSING "Cut-offs missing in pair_style buck/coul" #define PAIR_LJ_OFF "LJ6 off not supported in pair_style buck/coul" #define PAIR_COUL_CUT "Coulombic cut not supported in pair_style buck/coul" #define PAIR_LARGEST "Using largest cut-off for buck/coul long long" #define PAIR_MIX "Geometric mixing assumed for 1/r^6 coefficients" void PairBuckCoul::options(char **arg, int order) { char *option[] = {"long", "cut", "off", NULL}; int i; if (!*arg) error->all(PAIR_ILLEGAL); for (i=0; option[i]&&strcmp(arg[0], option[i]); ++i); switch (i) { default: error->all(PAIR_ILLEGAL); case 0: ewald_order |= 1<all("Illegal pair_style command"); ewald_order = 0; ewald_off = 0; options(arg, 6); options(++arg, 1); if (!comm->me && ewald_order&(1<<6)) error->warning(PAIR_MIX); if (!comm->me && ewald_order==((1<<1)|(1<<6))) error->warning(PAIR_LARGEST); if (!*(++arg)) error->all(PAIR_MISSING); if (ewald_off&(1<<6)) error->all(PAIR_LJ_OFF); if (!((ewald_order^ewald_off)&(1<<1))) error->all(PAIR_COUL_CUT); cut_buck_global = force->numeric(*(arg++)); if (*arg&&(ewald_order&0x42==0x42)) error->all(PAIR_CUTOFF); if (narg == 4) cut_coul = force->numeric(*arg); else cut_coul = cut_buck_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_buck[i][j] = cut_buck_global; } } /* ---------------------------------------------------------------------- free all arrays ------------------------------------------------------------------------- */ PairBuckCoul::~PairBuckCoul() { 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 PairBuckCoul::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 *PairBuckCoul::extract(char *id, int &dim) { char *ids[] = { "B", "ewald_order", "ewald_cut", "ewald_mix", "cut_coul", NULL}; void *ptrs[] = { buck_c, &ewald_order, &cut_coul, &mix_flag, &cut_coul, 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 PairBuckCoul::coeff(int narg, char **arg) { if (narg < 5 || narg > 6) error->all("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); double buck_a_one = force->numeric(*(arg++)); double buck_rho_one = force->numeric(*(arg++)); double buck_c_one = force->numeric(*(arg++)); double cut_buck_one = cut_buck_global; if (narg == 6) cut_buck_one = force->numeric(*(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("Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairBuckCoul::init_style() { // require an atom style with charge defined if (!atom->q_flag && (ewald_order&(1<<1))) error->all( "Invoking coulombic in pair style lj/coul requires atom attribute q"); // request regular or rRESPA neighbor lists int irequest; if (update->whichflag == 0 && strcmp(update->integrate_style,"respa") == 0) { int respa = 0; if (((Respa *) update->integrate)->level_inner >= 0) respa = 1; if (((Respa *) update->integrate)->level_middle >= 0) respa = 2; if (respa == 0) irequest = neighbor->request(this); else if (respa == 1) { irequest = neighbor->request(this); neighbor->requests[irequest]->id = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respainner = 1; irequest = neighbor->request(this); neighbor->requests[irequest]->id = 3; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respaouter = 1; } else { irequest = neighbor->request(this); neighbor->requests[irequest]->id = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respainner = 1; irequest = neighbor->request(this); neighbor->requests[irequest]->id = 2; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respamiddle = 1; irequest = neighbor->request(this); neighbor->requests[irequest]->id = 3; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respaouter = 1; } } else irequest = neighbor->request(this); cut_coulsq = cut_coul * cut_coul; // set rRESPA cutoffs if (strcmp(update->integrate_style,"respa") == 0 && ((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 (ewald_order&(1<<1)) { // r^-1 kspace if (force->kspace == NULL) error->all("Pair style is incompatible with KSpace style"); g_ewald = force->kspace->g_ewald; } if (ewald_order&(1<<6)) { // r^-6 kspace if (!force->kspace && strcmp(force->kspace_style,"ewald/n")) error->all("Pair style is incompatible with KSpace style"); g_ewald = force->kspace->g_ewald; } // setup force tables if (ncoultablebits) init_tables(); } /* ---------------------------------------------------------------------- neighbor callback to inform pair style of neighbor list to use regular or rRESPA ------------------------------------------------------------------------- */ void PairBuckCoul::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 PairBuckCoul::init_one(int i, int j) { if (setflag[i][j] == 0) error->all("All pair coeffs are not set"); 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("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 PairBuckCoul::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 PairBuckCoul::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 PairBuckCoul::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(&ewald_order,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairBuckCoul::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(&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(&ewald_order,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- compute pair interactions ------------------------------------------------------------------------- */ void PairBuckCoul::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; - int nall = nlocal + atom->nghost; 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, qri, *cutsqi, *cut_bucksqi, *buck1i, *buck2i, *buckai, *buckci, *rhoinvi, *offseti; double r, rsq, r2inv, force_coul, force_buck; double g2 = g_ewald*g_ewald, 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) { + 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) { + 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 register double x2 = g2*rsq, a2 = 1.0/x2; x2 = a2*exp(-x2)*buckci[typej]; - if (ni < 0) { + 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 { // cut - if (ni < 0) { + 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_compute(); } /* ---------------------------------------------------------------------- */ void PairBuckCoul::compute_inner() { double r, rsq, r2inv, force_coul, force_buck, fpair; int *type = atom->type; int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; 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 ? + 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 ? + 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 PairBuckCoul::compute_middle() { double r, rsq, r2inv, force_coul, force_buck, fpair; int *type = atom->type; int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; 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 ? + 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 ? + 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 PairBuckCoul::compute_outer(int eflag, int vflag) { double evdwl,ecoul,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; - int nall = nlocal + atom->nghost; 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, qri, *cutsqi, *cut_bucksqi, *buck1i, *buck2i, *buckai, *buckci, *rhoinvi, *offseti; double r, rsq, r2inv, force_coul, force_buck; double g2 = g_ewald*g_ewald, g6 = g2*g2*g2, g8 = g6*g2; double respa_buck, respa_coul, frespa; 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); if ((respa_flag = (rsq>cut_in_off_sq)&&(rsq> ncoulshiftbits; register double f = (rsq-rtable[k])*drtable[k], qiqj = qi*q[j]; - if (ni < 0) { + 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) 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 + 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 register double x2 = g2*rsq, a2 = 1.0/x2; x2 = a2*exp(-x2)*buckci[typej]; - if (ni < 0) { + 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 { // 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]; if (eflag) evdwl = f*expr*buckai[typej] - g6*((a2+1.0)*a2+0.5)*x2+t*buckci[typej]; } } else { // cut form - if (ni < 0) { + if (ni == 0) { force_buck = r*expr*buck1i[typej]-rn*buck2i[typej]; 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]); 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; frespa = fpair-(respa_coul+respa_buck)*r2inv; if (newton_pair || j < nlocal) { register double *fj = f0+(j+(j<<1)), f; fi[0] += f = d[0]*frespa; fj[0] -= f; fi[1] += f = d[1]*frespa; fj[1] -= f; fi[2] += f = d[2]*frespa; fj[2] -= f; } else { fi[0] += d[0]*frespa; fi[1] += d[1]*frespa; fi[2] += d[2]*frespa; } if (evflag) ev_tally(i,j,nlocal,newton_pair, evdwl,ecoul,fpair,d[0],d[1],d[2]); } } } /* ---------------------------------------------------------------------- setup force tables used in compute routines ------------------------------------------------------------------------- */ void PairBuckCoul::init_tables() { int masklo,maskhi; double r,grij,expm2,derfc,rsw; double qqrd2e = force->qqrd2e; tabinnersq = tabinner*tabinner; init_bitmap(tabinner,cut_coul,ncoultablebits, masklo,maskhi,ncoulmask,ncoulshiftbits); int ntable = 1; for (int i = 0; i < ncoultablebits; i++) ntable *= 2; // linear lookup tables of length N = 2^ncoultablebits // stored value = value at lower edge of bin // d values = delta from lower edge to upper edge of bin if (ftable) free_tables(); memory->create(rtable,ntable,"pair:rtable"); memory->create(ftable,ntable,"pair:ftable"); memory->create(ctable,ntable,"pair:ctable"); memory->create(etable,ntable,"pair:etable"); memory->create(drtable,ntable,"pair:drtable"); memory->create(dftable,ntable,"pair:dftable"); memory->create(dctable,ntable,"pair:dctable"); memory->create(detable,ntable,"pair:detable"); if (cut_respa == NULL) { vtable = ptable = dvtable = dptable = NULL; } else { memory->create(vtable,ntable,"pair:vtable"); memory->create(ptable,ntable,"pair:ptable"); memory->create(dvtable,ntable,"pair:dvtable"); memory->create(dptable,ntable,"pair:dptable"); } union_int_float_t rsq_lookup; union_int_float_t minrsq_lookup; int itablemin; minrsq_lookup.i = 0 << ncoulshiftbits; minrsq_lookup.i |= maskhi; for (int i = 0; i < ntable; i++) { rsq_lookup.i = i << ncoulshiftbits; rsq_lookup.i |= masklo; if (rsq_lookup.f < tabinnersq) { rsq_lookup.i = i << ncoulshiftbits; rsq_lookup.i |= maskhi; } r = sqrt(rsq_lookup.f); grij = g_ewald * r; expm2 = exp(-grij*grij); derfc = erfc(grij); if (cut_respa == NULL) { rtable[i] = rsq_lookup.f; ftable[i] = qqrd2e/r * (derfc + EWALD_F*grij*expm2); ctable[i] = qqrd2e/r; etable[i] = qqrd2e/r * derfc; } else { rtable[i] = rsq_lookup.f; ftable[i] = qqrd2e/r * (derfc + EWALD_F*grij*expm2 - 1.0); ctable[i] = 0.0; etable[i] = qqrd2e/r * derfc; ptable[i] = qqrd2e/r; vtable[i] = qqrd2e/r * (derfc + EWALD_F*grij*expm2); if (rsq_lookup.f > cut_respa[2]*cut_respa[2]) { if (rsq_lookup.f < cut_respa[3]*cut_respa[3]) { rsw = (r - cut_respa[2])/(cut_respa[3] - cut_respa[2]); ftable[i] += qqrd2e/r * rsw*rsw*(3.0 - 2.0*rsw); ctable[i] = qqrd2e/r * rsw*rsw*(3.0 - 2.0*rsw); } else { ftable[i] = qqrd2e/r * (derfc + EWALD_F*grij*expm2); ctable[i] = qqrd2e/r; } } } minrsq_lookup.f = MIN(minrsq_lookup.f,rsq_lookup.f); } tabinnersq = minrsq_lookup.f; int ntablem1 = ntable - 1; for (int i = 0; i < ntablem1; i++) { drtable[i] = 1.0/(rtable[i+1] - rtable[i]); dftable[i] = ftable[i+1] - ftable[i]; dctable[i] = ctable[i+1] - ctable[i]; detable[i] = etable[i+1] - etable[i]; } if (cut_respa) { for (int i = 0; i < ntablem1; i++) { dvtable[i] = vtable[i+1] - vtable[i]; dptable[i] = ptable[i+1] - ptable[i]; } } // get the delta values for the last table entries // tables are connected periodically between 0 and ntablem1 drtable[ntablem1] = 1.0/(rtable[0] - rtable[ntablem1]); dftable[ntablem1] = ftable[0] - ftable[ntablem1]; dctable[ntablem1] = ctable[0] - ctable[ntablem1]; detable[ntablem1] = etable[0] - etable[ntablem1]; if (cut_respa) { dvtable[ntablem1] = vtable[0] - vtable[ntablem1]; dptable[ntablem1] = ptable[0] - ptable[ntablem1]; } // get the correct delta values at itablemax // smallest r is in bin itablemin // largest r is in bin itablemax, which is itablemin-1, // or ntablem1 if itablemin=0 // deltas at itablemax only needed if corresponding rsq < cut*cut // if so, compute deltas between rsq and cut*cut double f_tmp,c_tmp,e_tmp,p_tmp,v_tmp; itablemin = minrsq_lookup.i & ncoulmask; itablemin >>= ncoulshiftbits; int itablemax = itablemin - 1; if (itablemin == 0) itablemax = ntablem1; rsq_lookup.i = itablemax << ncoulshiftbits; rsq_lookup.i |= maskhi; if (rsq_lookup.f < cut_coulsq) { rsq_lookup.f = cut_coulsq; r = sqrtf(rsq_lookup.f); grij = g_ewald * r; expm2 = exp(-grij*grij); derfc = erfc(grij); if (cut_respa == NULL) { f_tmp = qqrd2e/r * (derfc + EWALD_F*grij*expm2); c_tmp = qqrd2e/r; e_tmp = qqrd2e/r * derfc; } else { f_tmp = qqrd2e/r * (derfc + EWALD_F*grij*expm2 - 1.0); c_tmp = 0.0; e_tmp = qqrd2e/r * derfc; p_tmp = qqrd2e/r; v_tmp = qqrd2e/r * (derfc + EWALD_F*grij*expm2); if (rsq_lookup.f > cut_respa[2]*cut_respa[2]) { if (rsq_lookup.f < cut_respa[3]*cut_respa[3]) { rsw = (r - cut_respa[2])/(cut_respa[3] - cut_respa[2]); f_tmp += qqrd2e/r * rsw*rsw*(3.0 - 2.0*rsw); c_tmp = qqrd2e/r * rsw*rsw*(3.0 - 2.0*rsw); } else { f_tmp = qqrd2e/r * (derfc + EWALD_F*grij*expm2); c_tmp = qqrd2e/r; } } } drtable[itablemax] = 1.0/(rsq_lookup.f - rtable[itablemax]); dftable[itablemax] = f_tmp - ftable[itablemax]; dctable[itablemax] = c_tmp - ctable[itablemax]; detable[itablemax] = e_tmp - etable[itablemax]; if (cut_respa) { dvtable[itablemax] = v_tmp - vtable[itablemax]; dptable[itablemax] = p_tmp - ptable[itablemax]; } } } /* ---------------------------------------------------------------------- free memory for tables used in pair computations ------------------------------------------------------------------------- */ void PairBuckCoul::free_tables() { memory->destroy(rtable); memory->destroy(drtable); memory->destroy(ftable); memory->destroy(dftable); memory->destroy(ctable); memory->destroy(dctable); memory->destroy(etable); memory->destroy(detable); memory->destroy(vtable); memory->destroy(dvtable); memory->destroy(ptable); memory->destroy(dptable); } /* ---------------------------------------------------------------------- */ double PairBuckCoul::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*g_ewald, 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/USER-EWALDN/pair_lj_coul.cpp b/src/USER-EWALDN/pair_lj_coul.cpp index 60b18e277..2fdc0c610 100644 --- a/src/USER-EWALDN/pair_lj_coul.cpp +++ b/src/USER-EWALDN/pair_lj_coul.cpp @@ -1,1161 +1,1161 @@ /* ---------------------------------------------------------------------- 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 "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "math_vector.h" #include "pair_lj_coul.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 MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) #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 /* ---------------------------------------------------------------------- */ PairLJCoul::PairLJCoul(LAMMPS *lmp) : Pair(lmp) { respa_enable = 1; ftable = NULL; } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ #define PAIR_ILLEGAL "Illegal pair_style lj/coul command" #define PAIR_CUTOFF "Only one cut-off allowed when requesting all long" #define PAIR_MISSING "Cut-offs missing in pair_style lj/coul" #define PAIR_COUL_CUT "Coulombic cut not supported in pair_style lj/coul" #define PAIR_LARGEST "Using largest cut-off for lj/coul long long" #define PAIR_MIX "Mixing forced for lj coefficients" void PairLJCoul::options(char **arg, int order) { char *option[] = {"long", "cut", "off", NULL}; int i; if (!*arg) error->all(PAIR_ILLEGAL); for (i=0; option[i]&&strcmp(arg[0], option[i]); ++i); switch (i) { default: error->all(PAIR_ILLEGAL); case 0: ewald_order |= 1<all("Illegal pair_style command"); ewald_off = 0; ewald_order = 0; options(arg, 6); options(++arg, 1); if (!comm->me && ewald_order&(1<<6)) error->warning(PAIR_MIX); if (!comm->me && ewald_order==((1<<1)|(1<<6))) error->warning(PAIR_LARGEST); if (!*(++arg)) error->all(PAIR_MISSING); if (!((ewald_order^ewald_off)&(1<<1))) error->all(PAIR_COUL_CUT); cut_lj_global = force->numeric(*(arg++)); if (*arg&&(ewald_order&0x42==0x42)) error->all(PAIR_CUTOFF); if (narg == 4) cut_coul = force->numeric(*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 ------------------------------------------------------------------------- */ PairLJCoul::~PairLJCoul() { 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 PairLJCoul::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 *PairLJCoul::extract(char *id, int &dim) { char *ids[] = { "B", "sigma", "epsilon", "ewald_order", "ewald_cut", "ewald_mix", "cut_coul", NULL}; void *ptrs[] = { lj4, sigma, epsilon, &ewald_order, &cut_coul, &mix_flag, &cut_coul, 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 PairLJCoul::coeff(int narg, char **arg) { if (narg < 4 || narg > 5) error->all("Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(arg[2]); double sigma_one = force->numeric(arg[3]); double cut_lj_one = cut_lj_global; if (narg == 5) cut_lj_one = force->numeric(arg[4]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { epsilon_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("Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairLJCoul::init_style() { char *style1[] = {"ewald", "ewald/n", "pppm", NULL}; char *style6[] = {"ewald/n", NULL}; int i; // require an atom style with charge defined if (!atom->q_flag && (ewald_order&(1<<1))) error->all( "Invoking coulombic in pair style lj/coul requires atom attribute q"); // request regular or rRESPA neighbor lists int irequest; if (update->whichflag == 0 && strcmp(update->integrate_style,"respa") == 0) { int respa = 0; if (((Respa *) update->integrate)->level_inner >= 0) respa = 1; if (((Respa *) update->integrate)->level_middle >= 0) respa = 2; if (respa == 0) irequest = neighbor->request(this); else if (respa == 1) { irequest = neighbor->request(this); neighbor->requests[irequest]->id = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respainner = 1; irequest = neighbor->request(this); neighbor->requests[irequest]->id = 3; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respaouter = 1; } else { irequest = neighbor->request(this); neighbor->requests[irequest]->id = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respainner = 1; irequest = neighbor->request(this); neighbor->requests[irequest]->id = 2; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respamiddle = 1; irequest = neighbor->request(this); neighbor->requests[irequest]->id = 3; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respaouter = 1; } } else irequest = neighbor->request(this); cut_coulsq = cut_coul * cut_coul; // set rRESPA cutoffs if (strcmp(update->integrate_style,"respa") == 0 && ((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 (ewald_order&(1<<1)) { // r^-1 kspace if (force->kspace == NULL) error->all("Pair style is incompatible with KSpace style"); for (i=0; style1[i]&&strcmp(force->kspace_style, style1[i]); ++i); if (!style1[i]) error->all("Pair style is incompatible with KSpace style"); } if (ewald_order&(1<<6)) { // r^-6 kspace if (force->kspace == NULL) error->all("Pair style is incompatible with KSpace style"); for (i=0; style6[i]&&strcmp(force->kspace_style, style6[i]); ++i); if (!style6[i]) error->all("Pair style is incompatible with KSpace style"); } if (force->kspace) g_ewald = force->kspace->g_ewald; // setup force tables if (ncoultablebits) init_tables(); } /* ---------------------------------------------------------------------- neighbor callback to inform pair style of neighbor list to use regular or rRESPA ------------------------------------------------------------------------- */ void PairLJCoul::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 PairLJCoul::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("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 PairLJCoul::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 PairLJCoul::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 PairLJCoul::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 PairLJCoul::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 PairLJCoul::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; - int nall = nlocal + atom->nghost; 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, qri, *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; 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) { + 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) { + 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 register double rn = r2inv*r2inv*r2inv; register double x2 = g2*rsq, a2 = 1.0/x2; x2 = a2*exp(-x2)*lj4i[typej]; - if (ni < 0) { + 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) { + 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_compute(); } /* ---------------------------------------------------------------------- */ void PairLJCoul::compute_inner() { double rsq, r2inv, force_coul, force_lj, fpair; int *type = atom->type; int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; 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 = list->ilist)+list->inum; for (; ineighfirstneigh[i])+list->numneigh[i]; for (; jneigh= cut_out_off_sq) continue; r2inv = 1.0/rsq; if (order1 && (rsq < cut_coulsq)) // coulombic - force_coul = ni<0 ? + 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 ? + 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 PairLJCoul::compute_middle() { double rsq, r2inv, force_coul, force_lj, fpair; int *type = atom->type; int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; 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 = list->ilist)+list->inum; for (; ineighfirstneigh[i])+list->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 ? + 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 ? + 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 PairLJCoul::compute_outer(int eflag, int vflag) { double evdwl,ecoul,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; - int nall = nlocal + atom->nghost; 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, qri, *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 respa_lj, respa_coul, frespa; 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 = list->ilist)+list->inum; for (; ineighfirstneigh[i])+list->numneigh[i]; for (; jneigh= cutsqi[typej = type[j]]) continue; r2inv = 1.0/rsq; if ((respa_flag = (rsq>cut_in_off_sq)&&(rsq> ncoulshiftbits; register double f = (rsq-rtable[k])*drtable[k], qiqj = qi*q[j]; - if (ni < 0) { + 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) 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 + 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 register double x2 = g2*rsq, a2 = 1.0/x2; x2 = a2*exp(-x2)*lj4i[typej]; - if (ni < 0) { + 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 { // 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]; if (eflag) evdwl = f*rn*lj3i[typej]-g6*((a2+1.0)*a2+0.5)*x2+t*lj4i[typej]; } } else { // cut form - if (ni < 0) { + if (ni == 0) { force_lj = rn*(rn*lj1i[typej]-lj2i[typej]); 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]); 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; frespa = fpair-(respa_coul+respa_lj)*r2inv; if (newton_pair || j < nlocal) { register double *fj = f0+(j+(j<<1)), f; fi[0] += f = d[0]*frespa; fj[0] -= f; fi[1] += f = d[1]*frespa; fj[1] -= f; fi[2] += f = d[2]*frespa; fj[2] -= f; } else { fi[0] += d[0]*frespa; fi[1] += d[1]*frespa; fi[2] += d[2]*frespa; } if (evflag) ev_tally(i,j,nlocal,newton_pair, evdwl,ecoul,fpair,d[0],d[1],d[2]); } } } /* ---------------------------------------------------------------------- setup force tables used in compute routines ------------------------------------------------------------------------- */ void PairLJCoul::init_tables() { int masklo,maskhi; double r,grij,expm2,derfc,rsw; double qqrd2e = force->qqrd2e; tabinnersq = tabinner*tabinner; init_bitmap(tabinner,cut_coul,ncoultablebits, masklo,maskhi,ncoulmask,ncoulshiftbits); int ntable = 1; for (int i = 0; i < ncoultablebits; i++) ntable *= 2; // linear lookup tables of length N = 2^ncoultablebits // stored value = value at lower edge of bin // d values = delta from lower edge to upper edge of bin if (ftable) free_tables(); memory->create(rtable,ntable,"pair:rtable"); memory->create(ftable,ntable,"pair:ftable"); memory->create(ctable,ntable,"pair:ctable"); memory->create(etable,ntable,"pair:etable"); memory->create(drtable,ntable,"pair:drtable"); memory->create(dftable,ntable,"pair:dftable"); memory->create(dctable,ntable,"pair:dctable"); memory->create(detable,ntable,"pair:detable"); if (cut_respa == NULL) { vtable = ptable = dvtable = dptable = NULL; } else { memory->create(vtable,ntable,"pair:vtable"); memory->create(ptable,ntable,"pair:ptable"); memory->create(dvtable,ntable,"pair:dvtable"); memory->create(dptable,ntable,"pair:dptable"); } union_int_float_t rsq_lookup; union_int_float_t minrsq_lookup; int itablemin; minrsq_lookup.i = 0 << ncoulshiftbits; minrsq_lookup.i |= maskhi; for (int i = 0; i < ntable; i++) { rsq_lookup.i = i << ncoulshiftbits; rsq_lookup.i |= masklo; if (rsq_lookup.f < tabinnersq) { rsq_lookup.i = i << ncoulshiftbits; rsq_lookup.i |= maskhi; } r = sqrtf(rsq_lookup.f); grij = g_ewald * r; expm2 = exp(-grij*grij); derfc = erfc(grij); if (cut_respa == NULL) { rtable[i] = rsq_lookup.f; ftable[i] = qqrd2e/r * (derfc + EWALD_F*grij*expm2); ctable[i] = qqrd2e/r; etable[i] = qqrd2e/r * derfc; } else { rtable[i] = rsq_lookup.f; ftable[i] = qqrd2e/r * (derfc + EWALD_F*grij*expm2 - 1.0); ctable[i] = 0.0; etable[i] = qqrd2e/r * derfc; ptable[i] = qqrd2e/r; vtable[i] = qqrd2e/r * (derfc + EWALD_F*grij*expm2); if (rsq_lookup.f > cut_respa[2]*cut_respa[2]) { if (rsq_lookup.f < cut_respa[3]*cut_respa[3]) { rsw = (r - cut_respa[2])/(cut_respa[3] - cut_respa[2]); ftable[i] += qqrd2e/r * rsw*rsw*(3.0 - 2.0*rsw); ctable[i] = qqrd2e/r * rsw*rsw*(3.0 - 2.0*rsw); } else { ftable[i] = qqrd2e/r * (derfc + EWALD_F*grij*expm2); ctable[i] = qqrd2e/r; } } } minrsq_lookup.f = MIN(minrsq_lookup.f,rsq_lookup.f); } tabinnersq = minrsq_lookup.f; int ntablem1 = ntable - 1; for (int i = 0; i < ntablem1; i++) { drtable[i] = 1.0/(rtable[i+1] - rtable[i]); dftable[i] = ftable[i+1] - ftable[i]; dctable[i] = ctable[i+1] - ctable[i]; detable[i] = etable[i+1] - etable[i]; } if (cut_respa) { for (int i = 0; i < ntablem1; i++) { dvtable[i] = vtable[i+1] - vtable[i]; dptable[i] = ptable[i+1] - ptable[i]; } } // get the delta values for the last table entries // tables are connected periodically between 0 and ntablem1 drtable[ntablem1] = 1.0/(rtable[0] - rtable[ntablem1]); dftable[ntablem1] = ftable[0] - ftable[ntablem1]; dctable[ntablem1] = ctable[0] - ctable[ntablem1]; detable[ntablem1] = etable[0] - etable[ntablem1]; if (cut_respa) { dvtable[ntablem1] = vtable[0] - vtable[ntablem1]; dptable[ntablem1] = ptable[0] - ptable[ntablem1]; } // get the correct delta values at itablemax // smallest r is in bin itablemin // largest r is in bin itablemax, which is itablemin-1, // or ntablem1 if itablemin=0 // deltas at itablemax only needed if corresponding rsq < cut*cut // if so, compute deltas between rsq and cut*cut double f_tmp,c_tmp,e_tmp,p_tmp,v_tmp; itablemin = minrsq_lookup.i & ncoulmask; itablemin >>= ncoulshiftbits; int itablemax = itablemin - 1; if (itablemin == 0) itablemax = ntablem1; rsq_lookup.i = itablemax << ncoulshiftbits; rsq_lookup.i |= maskhi; if (rsq_lookup.f < cut_coulsq) { rsq_lookup.f = cut_coulsq; r = sqrtf(rsq_lookup.f); grij = g_ewald * r; expm2 = exp(-grij*grij); derfc = erfc(grij); if (cut_respa == NULL) { f_tmp = qqrd2e/r * (derfc + EWALD_F*grij*expm2); c_tmp = qqrd2e/r; e_tmp = qqrd2e/r * derfc; } else { f_tmp = qqrd2e/r * (derfc + EWALD_F*grij*expm2 - 1.0); c_tmp = 0.0; e_tmp = qqrd2e/r * derfc; p_tmp = qqrd2e/r; v_tmp = qqrd2e/r * (derfc + EWALD_F*grij*expm2); if (rsq_lookup.f > cut_respa[2]*cut_respa[2]) { if (rsq_lookup.f < cut_respa[3]*cut_respa[3]) { rsw = (r - cut_respa[2])/(cut_respa[3] - cut_respa[2]); f_tmp += qqrd2e/r * rsw*rsw*(3.0 - 2.0*rsw); c_tmp = qqrd2e/r * rsw*rsw*(3.0 - 2.0*rsw); } else { f_tmp = qqrd2e/r * (derfc + EWALD_F*grij*expm2); c_tmp = qqrd2e/r; } } } drtable[itablemax] = 1.0/(rsq_lookup.f - rtable[itablemax]); dftable[itablemax] = f_tmp - ftable[itablemax]; dctable[itablemax] = c_tmp - ctable[itablemax]; detable[itablemax] = e_tmp - etable[itablemax]; if (cut_respa) { dvtable[itablemax] = v_tmp - vtable[itablemax]; dptable[itablemax] = p_tmp - ptable[itablemax]; } } } /* ---------------------------------------------------------------------- free memory for tables used in pair computations ------------------------------------------------------------------------- */ void PairLJCoul::free_tables() { memory->destroy(rtable); memory->destroy(drtable); memory->destroy(ftable); memory->destroy(dftable); memory->destroy(ctable); memory->destroy(dctable); memory->destroy(etable); memory->destroy(detable); memory->destroy(vtable); memory->destroy(dvtable); memory->destroy(ptable); memory->destroy(dptable); } /* ---------------------------------------------------------------------- */ double PairLJCoul::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*g_ewald, 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/USER-REAXC/pair_reax_c.cpp b/src/USER-REAXC/pair_reax_c.cpp index efbb368f9..a340f9878 100644 --- a/src/USER-REAXC/pair_reax_c.cpp +++ b/src/USER-REAXC/pair_reax_c.cpp @@ -1,752 +1,758 @@ /* ---------------------------------------------------------------------- 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: Hasan Metin Aktulga, Purdue University ------------------------------------------------------------------------- */ #include "pair_reax_c.h" #include "atom.h" #include "update.h" #include "force.h" #include "comm.h" #include "neighbor.h" #include "neigh_list.h" #include "neigh_request.h" #include "modify.h" #include "fix.h" #include "fix_reax_c.h" #include "memory.h" #include "error.h" #include "reaxc_types.h" #include "reaxc_allocate.h" #include "reaxc_control.h" #include "reaxc_ffield.h" #include "reaxc_forces.h" #include "reaxc_init_md.h" #include "reaxc_io_tools.h" #include "reaxc_list.h" #include "reaxc_lookup.h" #include "reaxc_reset_tools.h" #include "reaxc_traj.h" #include "reaxc_vector.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ PairReaxC::PairReaxC(LAMMPS *lmp) : Pair(lmp) { system = (reax_system *) memory->smalloc(sizeof(reax_system),"reax:system"); control = (control_params *) memory->smalloc(sizeof(control_params),"reax:control"); data = (simulation_data *) memory->smalloc(sizeof(simulation_data),"reax:data"); workspace = (storage *) memory->smalloc(sizeof(storage),"reax:storage"); lists = (reax_list *) memory->smalloc(LIST_N * sizeof(reax_list),"reax:lists"); out_control = (output_controls *) memory->smalloc(sizeof(output_controls),"reax:out_control"); mpi_data = (mpi_datatypes *) memory->smalloc(sizeof(mpi_datatypes),"reax:mpi"); MPI_Comm_rank(world,&system->my_rank); system->my_coords[0] = 0; system->my_coords[1] = 0; system->my_coords[2] = 0; system->num_nbrs = 0; system->n = 0; // my atoms system->N = 0; // mine + ghosts system->bigN = 0; // all atoms in the system system->local_cap = 0; system->total_cap = 0; system->gcell_cap = 0; system->bndry_cuts.ghost_nonb = 0; system->bndry_cuts.ghost_hbond = 0; system->bndry_cuts.ghost_bond = 0; system->bndry_cuts.ghost_cutoff = 0; system->my_atoms = NULL; fix_reax = NULL; nextra = 14; pvector = new double[nextra]; setup_flag = 0; } /* ---------------------------------------------------------------------- */ PairReaxC::~PairReaxC() { if (fix_reax) modify->delete_fix("REAXC"); Close_Output_Files( system, control, out_control, mpi_data ); // deallocate reax data-structures if( control->tabulate ) Deallocate_Lookup_Tables( system ); if( control->hbond_cut > 0 ) Delete_List( lists+HBONDS, world ); Delete_List( lists+BONDS, world ); Delete_List( lists+THREE_BODIES, world ); Delete_List( lists+FAR_NBRS, world ); // fprintf( stderr, "3\n" ); DeAllocate_Workspace( control, workspace ); DeAllocate_System( system ); //fprintf( stderr, "4\n" ); memory->destroy( system ); memory->destroy( control ); memory->destroy( data ); memory->destroy( workspace ); memory->destroy( lists ); memory->destroy( out_control ); memory->destroy( mpi_data ); //fprintf( stderr, "5\n" ); // deallocate interface storage if( allocated ) { memory->destroy(setflag); memory->destroy(cutsq); delete [] map; delete [] chi; delete [] eta; delete [] gamma; } delete [] pvector; //fprintf( stderr, "6\n" ); } /* ---------------------------------------------------------------------- */ void PairReaxC::allocate( ) { allocated = 1; int n = atom->ntypes; memory->create(setflag,n+1,n+1,"pair:setflag"); memory->create(cutsq,n+1,n+1,"pair:cutsq"); map = new int[n+1]; chi = new double[n+1]; eta = new double[n+1]; gamma = new double[n+1]; } /* ---------------------------------------------------------------------- */ void PairReaxC::settings(int narg, char **arg) { if (narg != 1 && narg != 3) error->all("Illegal pair_style command"); // read name of control file or use default controls if (strcmp(arg[0],"NULL") == 0) { strcpy( control->sim_name, "simulate" ); control->ensemble = 0; out_control->energy_update_freq = 0; control->tabulate = 0; control->reneighbor = 1; control->vlist_cut = control->nonb_cut; control->bond_cut = 5.; control->hbond_cut = 7.50; control->thb_cut = 0.001; out_control->write_steps = 0; out_control->traj_method = 0; strcpy( out_control->traj_title, "default_title" ); out_control->atom_info = 0; out_control->bond_info = 0; out_control->angle_info = 0; } else Read_Control_File(arg[0], control, out_control); // default values qeqflag = 1; // process optional keywords int iarg = 1; while (iarg < narg) { if (strcmp(arg[iarg],"checkqeq") == 0) { if (iarg+2 > narg) error->all("Illegal pair_style reax/c command"); if (strcmp(arg[iarg+1],"yes") == 0) qeqflag = 1; else if (strcmp(arg[iarg+1],"no") == 0) qeqflag = 0; else error->all("Illegal pair_style reax/c command"); iarg += 2; } else error->all("Illegal pair_style reax/c command"); } // LAMMPS is responsible for generating nbrs control->reneighbor = 1; } /* ---------------------------------------------------------------------- */ void PairReaxC::coeff( int nargs, char **args ) { if (!allocated) allocate(); if (nargs != 3 + atom->ntypes) error->all("Incorrect args for pair coefficients"); // insure I,J args are * * if (strcmp(args[0],"*") != 0 || strcmp(args[1],"*") != 0) error->all("Incorrect args for pair coefficients"); // read ffield file Read_Force_Field(args[2], &(system->reax_param), control); // read args that map atom types to elements in potential file // map[i] = which element the Ith atom type is, -1 if NULL int itmp; int nreax_types = system->reax_param.num_atom_types; for (int i = 3; i < nargs; i++) { if (strcmp(args[i],"NULL") == 0) { map[i-2] = -1; continue; } itmp = atoi(args[i]) - 1; map[i-2] = itmp; // error check if (itmp < 0 || itmp >= nreax_types) error->all("Non-existent ReaxFF type"); } int n = atom->ntypes; int count = 0; for (int i = 1; i <= n; i++) for (int j = i; j <= n; j++) { setflag[i][j] = 1; count++; } if (count == 0) error->all("Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- */ void PairReaxC::init_style( ) { if (!atom->q_flag) error->all("Pair reax/c requires atom attribute q"); firstwarn = 1; int iqeq; for (iqeq = 0; iqeq < modify->nfix; iqeq++) if (strcmp(modify->fix[iqeq]->style,"qeq/reax") == 0) break; if (iqeq == modify->nfix && qeqflag == 1) error->all("Pair reax/c requires use of fix qeq/reax"); system->n = atom->nlocal; // my atoms system->N = atom->nlocal + atom->nghost; // mine + ghosts system->bigN = static_cast (atom->natoms); // all atoms in the system system->wsize = comm->nprocs; system->big_box.V = 0; system->big_box.box_norms[0] = 0; system->big_box.box_norms[1] = 0; system->big_box.box_norms[2] = 0; if (atom->tag_enable == 0) error->all("Pair style reax/c requires atom IDs"); if (force->newton_pair == 0) error->all("Pair style reax/c requires newton pair on"); // need a half neighbor list w/ Newton off // built whenever re-neighboring occurs int irequest = neighbor->request(this); neighbor->requests[irequest]->newton = 2; cutmax = MAX3(control->nonb_cut, control->hbond_cut, 2*control->bond_cut); for( int i = 0; i < LIST_N; ++i ) lists[i].allocated = 0; if (fix_reax == NULL) { char **fixarg = new char*[3]; fixarg[0] = (char *) "REAXC"; fixarg[1] = (char *) "all"; fixarg[2] = (char *) "REAXC"; modify->add_fix(3,fixarg); delete [] fixarg; fix_reax = (FixReaxC *) modify->fix[modify->nfix-1]; } } /* ---------------------------------------------------------------------- */ void PairReaxC::setup( ) { int oldN; system->n = atom->nlocal; // my atoms system->N = atom->nlocal + atom->nghost; // mine + ghosts oldN = system->N; system->bigN = static_cast (atom->natoms); // all atoms in the system if (setup_flag == 0) { setup_flag = 1; int *num_bonds = fix_reax->num_bonds; int *num_hbonds = fix_reax->num_hbonds; control->vlist_cut = neighbor->cutneighmax; // determine the local and total capacity system->local_cap = MAX( (int)(system->n * SAFE_ZONE), MIN_CAP ); system->total_cap = MAX( (int)(system->N * SAFE_ZONE), MIN_CAP ); // initialize my data structures PreAllocate_Space( system, control, workspace, world ); write_reax_atoms(); int num_nbrs = estimate_reax_lists(); if(!Make_List(system->total_cap, num_nbrs, TYP_FAR_NEIGHBOR, lists+FAR_NBRS, world)) error->all("Pair reax/c problem in far neighbor list"); write_reax_lists(); Initialize( system, control, data, workspace, &lists, out_control, mpi_data, world ); for( int k = 0; k < system->N; ++k ) { num_bonds[k] = system->my_atoms[k].num_bonds; num_hbonds[k] = system->my_atoms[k].num_hbonds; } } else { // fill in reax datastructures write_reax_atoms(); // reset the bond list info for new atoms for(int k = oldN; k < system->N; ++k) Set_End_Index( k, Start_Index( k, lists+BONDS ), lists+BONDS ); // check if I need to shrink/extend my data-structs ReAllocate( system, control, data, workspace, &lists, mpi_data ); } } /* ---------------------------------------------------------------------- */ double PairReaxC::init_one(int i, int j) { return cutmax; } /* ---------------------------------------------------------------------- */ void PairReaxC::compute(int eflag, int vflag) { double evdwl,ecoul; double t_start, t_end; // communicate num_bonds once every reneighboring // 2 num arrays stored by fix, grab ptr to them if (neighbor->ago == 0) comm->forward_comm_fix(fix_reax); int *num_bonds = fix_reax->num_bonds; int *num_hbonds = fix_reax->num_hbonds; evdwl = ecoul = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = eflag_global = vflag_global = 0; if ((eflag_atom || vflag_atom) && firstwarn) { firstwarn = 0; if (comm->me == 0) error->warning("Pair reax/c cannot yet compute " "per-atom energy or stress"); } if (vflag_global) control->virial = 1; else control->virial = 0; system->n = atom->nlocal; // my atoms system->N = atom->nlocal + atom->nghost; // mine + ghosts system->bigN = static_cast (atom->natoms); // all atoms in the system system->big_box.V = 0; system->big_box.box_norms[0] = 0; system->big_box.box_norms[1] = 0; system->big_box.box_norms[2] = 0; if( comm->me == 0 ) t_start = MPI_Wtime(); // setup data structures setup(); Reset( system, control, data, workspace, &lists, world ); workspace->realloc.num_far = write_reax_lists(); // timing for filling in the reax lists if( comm->me == 0 ) { t_end = MPI_Wtime(); data->timing.nbrs = t_end - t_start; } // forces Compute_Forces(system,control,data,workspace,&lists,out_control,mpi_data); read_reax_forces(); for(int k = 0; k < system->N; ++k) { num_bonds[k] = system->my_atoms[k].num_bonds; num_hbonds[k] = system->my_atoms[k].num_hbonds; } // energies and pressure if (eflag_global) { evdwl += data->my_en.e_bond; evdwl += data->my_en.e_ov; evdwl += data->my_en.e_un; evdwl += data->my_en.e_lp; evdwl += data->my_en.e_ang; evdwl += data->my_en.e_pen; evdwl += data->my_en.e_coa; evdwl += data->my_en.e_hb; evdwl += data->my_en.e_tor; evdwl += data->my_en.e_con; evdwl += data->my_en.e_vdW; ecoul += data->my_en.e_ele; ecoul += data->my_en.e_pol; eng_vdwl += evdwl; eng_coul += ecoul; // Store the different parts of the energy // in a list for output by compute pair command pvector[0] = data->my_en.e_bond; pvector[1] = data->my_en.e_ov + data->my_en.e_un; pvector[2] = data->my_en.e_lp; pvector[3] = 0.0; pvector[4] = data->my_en.e_ang; pvector[5] = data->my_en.e_pen; pvector[6] = data->my_en.e_coa; pvector[7] = data->my_en.e_hb; pvector[8] = data->my_en.e_tor; pvector[9] = data->my_en.e_con; pvector[10] = data->my_en.e_vdW; pvector[11] = data->my_en.e_ele; pvector[12] = 0.0; pvector[13] = data->my_en.e_pol; } if (vflag_fdotr) virial_compute(); // #if defined(LOG_PERFORMANCE) // if( comm->me == 0 && fix_qeq != NULL ) { // data->timing.s_matvecs += fix_qeq->matvecs; // data->timing.qEq += fix_qeq->qeq_time; // } // #endif Output_Results( system, control, data, &lists, out_control, mpi_data ); ++data->step; } /* ---------------------------------------------------------------------- */ void PairReaxC::write_reax_atoms() { int *num_bonds = fix_reax->num_bonds; int *num_hbonds = fix_reax->num_hbonds; for( int i = 0; i < system->N; ++i ){ system->my_atoms[i].orig_id = atom->tag[i]; system->my_atoms[i].type = map[atom->type[i]]; system->my_atoms[i].x[0] = atom->x[i][0]; system->my_atoms[i].x[1] = atom->x[i][1]; system->my_atoms[i].x[2] = atom->x[i][2]; system->my_atoms[i].q = atom->q[i]; system->my_atoms[i].num_bonds = num_bonds[i]; system->my_atoms[i].num_hbonds = num_hbonds[i]; } } /* ---------------------------------------------------------------------- */ void PairReaxC::get_distance( rvec xj, rvec xi, double *d_sqr, rvec *dvec ) { (*dvec)[0] = xj[0] - xi[0]; (*dvec)[1] = xj[1] - xi[1]; (*dvec)[2] = xj[2] - xi[2]; *d_sqr = SQR((*dvec)[0]) + SQR((*dvec)[1]) + SQR((*dvec)[2]); } /* ---------------------------------------------------------------------- */ void PairReaxC::set_far_nbr( far_neighbor_data *fdest, int j, double d, rvec dvec ) { fdest->nbr = j; fdest->d = d; rvec_Copy( fdest->dvec, dvec ); ivec_MakeZero( fdest->rel_box ); } /* ---------------------------------------------------------------------- */ int PairReaxC::estimate_reax_lists() { int itr_i, itr_j, itr_g, i, j, g; int nlocal, nghost, num_nbrs, num_marked; int *ilist, *jlist, *numneigh, **firstneigh, *marked; double d_sqr, g_d_sqr; rvec dvec, g_dvec; double *dist, **x; reax_list *far_nbrs; far_neighbor_data *far_list; x = atom->x; nlocal = atom->nlocal; nghost = atom->nghost; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; far_nbrs = lists + FAR_NBRS; far_list = far_nbrs->select.far_nbr_list; num_nbrs = 0; num_marked = 0; marked = (int*) calloc( system->N, sizeof(int) ); dist = (double*) calloc( system->N, sizeof(double) ); for( itr_i = 0; itr_i < list->inum; ++itr_i ){ i = ilist[itr_i]; marked[i] = 1; ++num_marked; jlist = firstneigh[i]; for( itr_j = 0; itr_j < numneigh[i]; ++itr_j ){ j = jlist[itr_j]; + j &= NEIGHMASK; get_distance( x[j], x[i], &d_sqr, &dvec ); dist[j] = sqrt(d_sqr); if( dist[j] <= control->nonb_cut ) ++num_nbrs; } // compute the nbrs among ghost atoms for( itr_j = 0; itr_j < numneigh[i]; ++itr_j ){ j = jlist[itr_j]; + j &= NEIGHMASK; if( j >= nlocal && !marked[j] && dist[j] <= (control->vlist_cut - control->bond_cut) ){ marked[j] = 1; ++num_marked; for( itr_g = 0; itr_g < numneigh[i]; ++itr_g ){ g = jlist[itr_g]; + g &= NEIGHMASK; if( g >= nlocal && !marked[g] ){ get_distance( x[g], x[j], &g_d_sqr, &g_dvec ); //g_dvec[0] = x[g][0] - x[j][0]; //g_dvec[1] = x[g][1] - x[j][1]; //g_dvec[2] = x[g][2] - x[j][2]; //g_d_sqr = SQR(g_dvec[0]) + SQR(g_dvec[1]) + SQR(g_dvec[2]); if( g_d_sqr <= SQR(control->bond_cut) ) ++num_nbrs; } } } } } for( i = 0; i < system->N; ++i ) if( !marked[i] ) { marked[i] = 1; ++num_marked; for( j = i+1; j < system->N; ++j ) if( !marked[j] ) { get_distance( x[j], x[i], &d_sqr, &dvec ); if( d_sqr <= SQR(control->bond_cut) ) ++num_nbrs; } } free( marked ); free( dist ); return static_cast (MAX( num_nbrs*SAFE_ZONE, MIN_CAP*MIN_NBRS )); } /* ---------------------------------------------------------------------- */ int PairReaxC::write_reax_lists() { int itr_i, itr_j, itr_g, i, j, g; int nlocal, nghost, num_nbrs; int *ilist, *jlist, *numneigh, **firstneigh, *marked; double d_sqr, g_d, g_d_sqr; rvec dvec, g_dvec; double *dist, **x; reax_list *far_nbrs; far_neighbor_data *far_list; x = atom->x; nlocal = atom->nlocal; nghost = atom->nghost; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; far_nbrs = lists + FAR_NBRS; far_list = far_nbrs->select.far_nbr_list; num_nbrs = 0; marked = (int*) calloc( system->N, sizeof(int) ); dist = (double*) calloc( system->N, sizeof(double) ); for( itr_i = 0; itr_i < list->inum; ++itr_i ){ i = ilist[itr_i]; marked[i] = 1; jlist = firstneigh[i]; Set_Start_Index( i, num_nbrs, far_nbrs ); for( itr_j = 0; itr_j < numneigh[i]; ++itr_j ){ j = jlist[itr_j]; + j &= NEIGHMASK; get_distance( x[j], x[i], &d_sqr, &dvec ); dist[j] = sqrt( d_sqr ); if( dist[j] <= control->nonb_cut ){ set_far_nbr( &far_list[num_nbrs], j, dist[j], dvec ); ++num_nbrs; } } Set_End_Index( i, num_nbrs, far_nbrs ); // compute the nbrs among ghost atoms for( itr_j = 0; itr_j < numneigh[i]; ++itr_j ){ j = jlist[itr_j]; + j &= NEIGHMASK; if( j >= nlocal && !marked[j] && dist[j] <= (control->vlist_cut - control->bond_cut) ){ marked[j] = 1; Set_Start_Index( j, num_nbrs, far_nbrs ); for( itr_g = 0; itr_g < numneigh[i]; ++itr_g ){ g = jlist[itr_g]; + g &= NEIGHMASK; if( g >= nlocal && !marked[g] ){ get_distance( x[g], x[j], &g_d_sqr, &g_dvec ); if( g_d_sqr <= SQR(control->bond_cut) ){ g_d = sqrt( g_d_sqr ); set_far_nbr( &far_list[num_nbrs], g, g_d, g_dvec ); ++num_nbrs; } } } Set_End_Index( j, num_nbrs, far_nbrs ); } } } for( i = 0; i < system->N; ++i ) if( !marked[i] ) { marked[i] = 1; Set_Start_Index( i, num_nbrs, far_nbrs ); for( j = i+1; j < system->N; ++j ) if( !marked[j] ) { get_distance( x[j], x[i], &d_sqr, &dvec ); if( d_sqr <= SQR(control->bond_cut) ) { set_far_nbr( &far_list[num_nbrs], j, sqrt(d_sqr), dvec ); ++num_nbrs; } } Set_End_Index( i, num_nbrs, far_nbrs ); } free( marked ); free( dist ); return num_nbrs; } /* ---------------------------------------------------------------------- */ void PairReaxC::read_reax_forces() { for( int i = 0; i < system->N; ++i ) { system->my_atoms[i].f[0] = workspace->f[i][0]; system->my_atoms[i].f[1] = workspace->f[i][1]; system->my_atoms[i].f[2] = workspace->f[i][2]; atom->f[i][0] = -workspace->f[i][0]; atom->f[i][1] = -workspace->f[i][1]; atom->f[i][2] = -workspace->f[i][2]; } } /* ---------------------------------------------------------------------- */ void *PairReaxC::extract(char *str, int &dim) { dim = 1; if (strcmp(str,"chi") == 0 && chi) { for (int i = 1; i <= atom->ntypes; i++) if (map[i] >= 0) chi[i] = system->reax_param.sbp[map[i]].chi; else chi[i] = 0.0; return (void *) chi; } if (strcmp(str,"eta") == 0 && eta) { for (int i = 1; i <= atom->ntypes; i++) if (map[i] >= 0) eta[i] = system->reax_param.sbp[map[i]].eta; else eta[i] = 0.0; return (void *) eta; } if (strcmp(str,"gamma") == 0 && gamma) { for (int i = 1; i <= atom->ntypes; i++) if (map[i] >= 0) gamma[i] = system->reax_param.sbp[map[i]].gamma; else gamma[i] = 0.0; return (void *) gamma; } return NULL; } diff --git a/src/compute.h b/src/compute.h index ceacee82a..9b929b345 100644 --- a/src/compute.h +++ b/src/compute.h @@ -1,128 +1,132 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #ifndef LMP_COMPUTE_H #define LMP_COMPUTE_H #include "pointers.h" namespace LAMMPS_NS { class Compute : protected Pointers { public: char *id,*style; int igroup,groupbit; double scalar; // computed global scalar double *vector; // computed global vector double **array; // computed global array double *vector_atom; // computed per-atom vector double **array_atom; // computed per-atom array double *vector_local; // computed local vector double **array_local; // computed local array int scalar_flag; // 0/1 if compute_scalar() function exists int vector_flag; // 0/1 if compute_vector() function exists int array_flag; // 0/1 if compute_array() function exists int size_vector; // length of global vector int size_array_rows; // rows in global array int size_array_cols; // columns in global array int peratom_flag; // 0/1 if compute_peratom() function exists int size_peratom_cols; // 0 = vector, N = columns in peratom array int local_flag; // 0/1 if compute_local() function exists int size_local_rows; // rows in local vector or array int size_local_cols; // 0 = vector, N = columns in local array int extscalar; // 0/1 if global scalar is intensive/extensive int extvector; // 0/1/-1 if global vector is all int/ext/extlist int *extlist; // list of 0/1 int/ext for each vec component int extarray; // 0/1 if global array is all intensive/extensive int tempflag; // 1 if Compute can be used as temperature // must have both compute_scalar, compute_vector int pressflag; // 1 if Compute can be used as pressure (uses virial) // must have both compute_scalar, compute_vector int pressatomflag; // 1 if Compute calculates per-atom virial int peflag; // 1 if Compute calculates PE (uses Force energies) int peatomflag; // 1 if Compute calculates per-atom PE int tempbias; // 0/1 if Compute temp includes self/extra bias int timeflag; // 1 if Compute stores list of timesteps it's called on int ntime; // # of entries in time list int maxtime; // max # of entries time list can hold bigint *tlist; // list of timesteps the Compute is called on int invoked_flag; // non-zero if invoked or accessed this step, 0 if not bigint invoked_scalar; // last timestep on which compute_scalar() was invoked bigint invoked_vector; // ditto for compute_vector() bigint invoked_array; // ditto for compute_array() bigint invoked_peratom; // ditto for compute_peratom() bigint invoked_local; // ditto for compute_local() double dof; // degrees-of-freedom for temperature int comm_forward; // size of forward communication (0 if none) int comm_reverse; // size of reverse communication (0 if none) Compute(class LAMMPS *, int, char **); virtual ~Compute(); void modify_params(int, char **); void reset_extra_dof(); virtual void init() = 0; virtual void init_list(int, class NeighList *) {} virtual double compute_scalar() {return 0.0;} virtual void compute_vector() {} virtual void compute_array() {} virtual void compute_peratom() {} virtual void compute_local() {} virtual int pack_comm(int, int *, double *, int, int *) {return 0;} virtual void unpack_comm(int, int, double *) {} virtual int pack_reverse_comm(int, int, double *) {return 0;} virtual void unpack_reverse_comm(int, int *, double *) {} virtual int dof_remove(int) {return 0;} virtual void remove_bias(int, double *) {} virtual void remove_bias_all() {} virtual void restore_bias(int, double *) {} virtual void restore_bias_all() {} virtual void reset_extra_compute_fix(char *); void addstep(bigint); int matchstep(bigint); void clearstep(); virtual double memory_usage() {return 0.0;} protected: int extra_dof; // extra DOF for temperature computes int dynamic; // recount atoms for temperature computes int thermoflag; // 1 if include fix PE for PE computes double vbias[3]; // stored velocity bias for one atom double **vbiasall; // stored velocity bias for all atoms int maxbias; // size of vbiasall array int *molmap; // convert molecule ID to local index int molecules_in_group(int &, int &); + + inline int sbmask(int j) { + return j >> SBBITS & 3; + } }; } #endif diff --git a/src/compute_centro_atom.cpp b/src/compute_centro_atom.cpp index 0b3ac52a5..811d5761a 100644 --- a/src/compute_centro_atom.cpp +++ b/src/compute_centro_atom.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 author: Michel Perez (U Lyon) for non-fcc lattices ------------------------------------------------------------------------- */ #include "string.h" #include "stdlib.h" #include "compute_centro_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; /* ---------------------------------------------------------------------- */ ComputeCentroAtom::ComputeCentroAtom(LAMMPS *lmp, int narg, char **arg) : Compute(lmp, narg, arg) { if (narg != 4) error->all("Illegal compute centro/atom command"); if (strcmp(arg[3],"fcc") == 0) nnn = 12; else if (strcmp(arg[3],"bcc") == 0) nnn = 8; else nnn = atoi(arg[3]); if (nnn <= 0 || nnn % 2) error->all("Illegal neighbor value for compute centro/atom command"); peratom_flag = 1; size_peratom_cols = 0; nmax = 0; centro = NULL; maxneigh = 0; distsq = NULL; nearest = NULL; } /* ---------------------------------------------------------------------- */ ComputeCentroAtom::~ComputeCentroAtom() { memory->destroy(centro); memory->destroy(distsq); memory->destroy(nearest); } /* ---------------------------------------------------------------------- */ void ComputeCentroAtom::init() { if (force->pair == NULL) error->all("Compute centro/atom requires a pair style be defined"); int count = 0; for (int i = 0; i < modify->ncompute; i++) if (strcmp(modify->compute[i]->style,"centro/atom") == 0) count++; if (count > 1 && comm->me == 0) error->warning("More than one compute centro/atom"); // need an occasional full neighbor list int irequest = neighbor->request((void *) this); 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; } /* ---------------------------------------------------------------------- */ void ComputeCentroAtom::init_list(int id, NeighList *ptr) { list = ptr; } /* ---------------------------------------------------------------------- */ void ComputeCentroAtom::compute_peratom() { int i,j,k,ii,jj,kk,n,inum,jnum; double xtmp,ytmp,ztmp,delx,dely,delz,rsq,value; int *ilist,*jlist,*numneigh,**firstneigh; invoked_peratom = update->ntimestep; // grow centro array if necessary if (atom->nlocal > nmax) { memory->destroy(centro); nmax = atom->nmax; memory->create(centro,nmax,"centro/atom:centro"); vector_atom = centro; } // invoke full neighbor list (will copy or build if necessary) neighbor->build_one(list->index); inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // npairs = number of unique pairs int nhalf = nnn/2; int npairs = nnn * (nnn-1) / 2; double *pairs = new double[npairs]; // compute centro-symmetry parameter for each atom in group // use full neighbor list double **x = atom->x; int *mask = atom->mask; int nall = atom->nlocal + atom->nghost; double cutsq = force->pair->cutforce * force->pair->cutforce; 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]; // insure distsq and nearest arrays are long enough if (jnum > maxneigh) { memory->destroy(distsq); memory->destroy(nearest); maxneigh = jnum; memory->create(distsq,maxneigh,"centro/atom:distsq"); memory->create(nearest,maxneigh,"centro/atom:nearest"); } // loop over list of all neighbors within force cutoff // distsq[] = distance sq to each // nearest[] = atom indices of neighbors n = 0; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; - if (j >= nall) j %= nall; + 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 < cutsq) { distsq[n] = rsq; nearest[n++] = j; } } // if not nnn neighbors, centro = 0.0 if (n < nnn) { centro[i] = 0.0; continue; } // store nnn nearest neighs in 1st nnn locations of distsq and nearest select2(nnn,n,distsq,nearest); // R = Ri + Rj for each of npairs i,j pairs among nnn neighbors // pairs = squared length of each R n = 0; for (j = 0; j < nnn; j++) { jj = nearest[j]; for (k = j+1; k < nnn; k++) { kk = nearest[k]; delx = x[jj][0] + x[kk][0] - 2.0*xtmp; dely = x[jj][1] + x[kk][1] - 2.0*ytmp; delz = x[jj][2] + x[kk][2] - 2.0*ztmp; pairs[n++] = delx*delx + dely*dely + delz*delz; } } // store nhalf smallest pair distances in 1st nhalf locations of pairs select(nhalf,npairs,pairs); // centrosymmetry = sum of nhalf smallest squared values value = 0.0; for (j = 0; j < nhalf; j++) value += pairs[j]; centro[i] = value; } else centro[i] = 0.0; } delete [] pairs; } /* ---------------------------------------------------------------------- 2 select routines from Numerical Recipes (slightly modified) find k smallest values in array of length n 2nd routine sorts auxiliary array at same time ------------------------------------------------------------------------- */ #define SWAP(a,b) tmp = a; a = b; b = tmp; #define ISWAP(a,b) itmp = a; a = b; b = itmp; void ComputeCentroAtom::select(int k, int n, double *arr) { int i,ir,j,l,mid; double a,tmp; arr--; l = 1; ir = n; for (;;) { if (ir <= l+1) { if (ir == l+1 && arr[ir] < arr[l]) { SWAP(arr[l],arr[ir]) } return; } else { mid=(l+ir) >> 1; SWAP(arr[mid],arr[l+1]) if (arr[l] > arr[ir]) { SWAP(arr[l],arr[ir]) } if (arr[l+1] > arr[ir]) { SWAP(arr[l+1],arr[ir]) } if (arr[l] > arr[l+1]) { SWAP(arr[l],arr[l+1]) } i = l+1; j = ir; a = arr[l+1]; for (;;) { do i++; while (arr[i] < a); do j--; while (arr[j] > a); if (j < i) break; SWAP(arr[i],arr[j]) } arr[l+1] = arr[j]; arr[j] = a; if (j >= k) ir = j-1; if (j <= k) l = i; } } } /* ---------------------------------------------------------------------- */ void ComputeCentroAtom::select2(int k, int n, double *arr, int *iarr) { int i,ir,j,l,mid,ia,itmp; double a,tmp; arr--; iarr--; l = 1; ir = n; for (;;) { if (ir <= l+1) { if (ir == l+1 && arr[ir] < arr[l]) { SWAP(arr[l],arr[ir]) ISWAP(iarr[l],iarr[ir]) } return; } else { mid=(l+ir) >> 1; SWAP(arr[mid],arr[l+1]) ISWAP(iarr[mid],iarr[l+1]) if (arr[l] > arr[ir]) { SWAP(arr[l],arr[ir]) ISWAP(iarr[l],iarr[ir]) } if (arr[l+1] > arr[ir]) { SWAP(arr[l+1],arr[ir]) ISWAP(iarr[l+1],iarr[ir]) } if (arr[l] > arr[l+1]) { SWAP(arr[l],arr[l+1]) ISWAP(iarr[l],iarr[l+1]) } i = l+1; j = ir; a = arr[l+1]; ia = iarr[l+1]; for (;;) { do i++; while (arr[i] < a); do j--; while (arr[j] > a); if (j < i) break; SWAP(arr[i],arr[j]) ISWAP(iarr[i],iarr[j]) } arr[l+1] = arr[j]; arr[j] = a; iarr[l+1] = iarr[j]; iarr[j] = ia; if (j >= k) ir = j-1; if (j <= k) l = i; } } } /* ---------------------------------------------------------------------- memory usage of local atom-based array ------------------------------------------------------------------------- */ double ComputeCentroAtom::memory_usage() { double bytes = nmax * sizeof(double); return bytes; } diff --git a/src/compute_cluster_atom.cpp b/src/compute_cluster_atom.cpp index e426047e6..38a63d078 100644 --- a/src/compute_cluster_atom.cpp +++ b/src/compute_cluster_atom.cpp @@ -1,224 +1,224 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "math.h" #include "string.h" #include "stdlib.h" #include "compute_cluster_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; #define MIN(A,B) ((A) < (B)) ? (A) : (B) #define MAX(A,B) ((A) > (B)) ? (A) : (B) /* ---------------------------------------------------------------------- */ ComputeClusterAtom::ComputeClusterAtom(LAMMPS *lmp, int narg, char **arg) : Compute(lmp, narg, arg) { if (narg != 4) error->all("Illegal compute cluster/atom command"); double cutoff = atof(arg[3]); cutsq = cutoff*cutoff; peratom_flag = 1; size_peratom_cols = 0; comm_forward = 1; nmax = 0; clusterID = NULL; } /* ---------------------------------------------------------------------- */ ComputeClusterAtom::~ComputeClusterAtom() { memory->destroy(clusterID); } /* ---------------------------------------------------------------------- */ void ComputeClusterAtom::init() { if (atom->tag_enable == 0) error->all("Cannot use compute cluster/atom unless atoms have IDs"); if (force->pair == NULL) error->all("Compute cluster/atom requires a pair style be defined"); if (sqrt(cutsq) > force->pair->cutforce) error->all("Compute cluster/atom cutoff is longer than pairwise cutoff"); // need an occasional full neighbor list // full required so that pair of atoms on 2 procs both set their clusterID int irequest = neighbor->request((void *) this); 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,"cluster/atom") == 0) count++; if (count > 1 && comm->me == 0) error->warning("More than one compute cluster/atom"); } /* ---------------------------------------------------------------------- */ void ComputeClusterAtom::init_list(int id, NeighList *ptr) { list = ptr; } /* ---------------------------------------------------------------------- */ void ComputeClusterAtom::compute_peratom() { int i,j,ii,jj,inum,jnum,n; double xtmp,ytmp,ztmp,delx,dely,delz,rsq; int *ilist,*jlist,*numneigh,**firstneigh; invoked_peratom = update->ntimestep; // grow clusterID array if necessary if (atom->nlocal > nmax) { memory->destroy(clusterID); nmax = atom->nmax; memory->create(clusterID,nmax,"cluster/atom:clusterID"); vector_atom = clusterID; } // invoke full neighbor list (will copy or build if necessary) neighbor->build_one(list->index); inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // every atom starts in its own cluster, with clusterID = atomID int *tag = atom->tag; int *mask = atom->mask; for (ii = 0; ii < inum; ii++) { i = ilist[ii]; if (mask[i] & groupbit) clusterID[i] = tag[i]; else clusterID[i] = 0; } // loop until no more changes on any proc: // acquire clusterIDs of ghost atoms // loop over my atoms, checking distance to neighbors // if both atoms are in cluster, assign lowest clusterID to both // iterate until no changes in my atoms // then check if any proc made changes double **x = atom->x; int nall = atom->nlocal + atom->nghost; int change,done,anychange; while (1) { comm->forward_comm_compute(this); change = 0; while (1) { done = 1; 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]; jlist = firstneigh[i]; jnum = numneigh[i]; n = 0; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; - if (j >= nall) j %= nall; + j &= NEIGHMASK; if (!(mask[j] & groupbit)) continue; if (clusterID[i] == clusterID[j]) continue; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; if (rsq < cutsq) { clusterID[i] = clusterID[j] = MIN(clusterID[i],clusterID[j]); done = 0; } } } if (!done) change = 1; if (done) break; } // stop if all procs are done MPI_Allreduce(&change,&anychange,1,MPI_INT,MPI_MAX,world); if (!anychange) break; } } /* ---------------------------------------------------------------------- */ int ComputeClusterAtom::pack_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++] = clusterID[j]; } return 1; } /* ---------------------------------------------------------------------- */ void ComputeClusterAtom::unpack_comm(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) clusterID[i] = buf[m++]; } /* ---------------------------------------------------------------------- memory usage of local atom-based array ------------------------------------------------------------------------- */ double ComputeClusterAtom::memory_usage() { double bytes = nmax * sizeof(double); return bytes; } diff --git a/src/compute_cna_atom.cpp b/src/compute_cna_atom.cpp index 6ad00a2c4..f07ffd6fc 100644 --- a/src/compute_cna_atom.cpp +++ b/src/compute_cna_atom.cpp @@ -1,367 +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. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author: Wan Liang (Chinese Academy of Sciences) ------------------------------------------------------------------------- */ #include "string.h" #include "stdlib.h" #include "compute_cna_atom.h" #include "atom.h" #include "update.h" #include "force.h" #include "pair.h" #include "modify.h" #include "neighbor.h" #include "neigh_list.h" #include "neigh_request.h" #include "comm.h" #include "memory.h" #include "error.h" #include "math.h" using namespace LAMMPS_NS; #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAXNEAR 16 #define MAXCOMMON 8 enum{UNKNOWN,FCC,HCP,BCC,ICOS,OTHER}; enum{NCOMMON,NBOND,MAXBOND,MINBOND}; /* ---------------------------------------------------------------------- */ ComputeCNAAtom::ComputeCNAAtom(LAMMPS *lmp, int narg, char **arg) : Compute(lmp, narg, arg) { if (narg != 4) error->all("Illegal compute cna/atom command"); peratom_flag = 1; size_peratom_cols = 0; double cutoff = atof(arg[3]); if (cutoff < 0.0) error->all("Illegal compute cna/atom command"); cutsq = cutoff*cutoff; nmax = 0; nearest = NULL; nnearest = NULL; pattern = NULL; } /* ---------------------------------------------------------------------- */ ComputeCNAAtom::~ComputeCNAAtom() { memory->destroy(nearest); memory->destroy(nnearest); memory->destroy(pattern); } /* ---------------------------------------------------------------------- */ void ComputeCNAAtom::init() { if (force->pair == NULL) error->all("Compute cna/atom requires a pair style be defined"); if (sqrt(cutsq) > force->pair->cutforce) error->all("Compute cna/atom cutoff is longer than pairwise cutoff"); // cannot use neighbor->cutneighmax b/c neighbor has not yet been init if (2.0*sqrt(cutsq) > force->pair->cutforce + neighbor->skin && comm->me == 0) error->warning("Compute cna/atom cutoff may be too large to find " "ghost atom neighbors"); int count = 0; for (int i = 0; i < modify->ncompute; i++) if (strcmp(modify->compute[i]->style,"cna/atom") == 0) count++; if (count > 1 && comm->me == 0) error->warning("More than one compute cna/atom defined"); // need an occasional full neighbor list int irequest = neighbor->request((void *) this); 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; } /* ---------------------------------------------------------------------- */ void ComputeCNAAtom::init_list(int id, NeighList *ptr) { list = ptr; } /* ---------------------------------------------------------------------- */ void ComputeCNAAtom::compute_peratom() { int i,j,k,ii,jj,kk,m,n,inum,jnum,inear,jnear; int firstflag,ncommon,nbonds,maxbonds,minbonds; int nfcc,nhcp,nbcc4,nbcc6,nico,cj,ck,cl,cm; int *ilist,*jlist,*numneigh,**firstneigh; int cna[MAXNEAR][4],onenearest[MAXNEAR]; int common[MAXCOMMON],bonds[MAXCOMMON]; double xtmp,ytmp,ztmp,delx,dely,delz,rsq; invoked_peratom = update->ntimestep; // grow arrays if necessary if (atom->nlocal > nmax) { memory->destroy(nearest); memory->destroy(nnearest); memory->destroy(pattern); nmax = atom->nmax; memory->create(nearest,nmax,MAXNEAR,"cna:nearest"); memory->create(nnearest,nmax,"cna:nnearest"); memory->create(pattern,nmax,"cna:cna_pattern"); vector_atom = pattern; } // invoke full neighbor list (will copy or build if necessary) neighbor->build_one(list->index); inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // find the neigbours of each atom within cutoff using full neighbor list // nearest[] = atom indices of nearest neighbors, up to MAXNEAR // do this for all atoms, not just compute group // since CNA calculation requires neighbors of neighbors double **x = atom->x; int *mask = atom->mask; int nlocal = atom->nlocal; int nerror = 0; for (ii = 0; ii < inum; ii++) { i = ilist[ii]; 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; + 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) { if (n < MAXNEAR) nearest[i][n++] = j; else { nerror++; break; } } } nnearest[i] = n; } // warning message int nerrorall; MPI_Allreduce(&nerror,&nerrorall,1,MPI_INT,MPI_SUM,world); if (nerrorall && comm->me == 0) { char str[128]; sprintf(str,"Too many neighbors in CNA for %d atoms",nerrorall); error->warning(str,0); } // compute CNA for each atom in group // only performed if # of nearest neighbors = 12 or 14 (fcc,hcp) nerror = 0; for (ii = 0; ii < inum; ii++) { i = ilist[ii]; if (!(mask[i] & groupbit)) { pattern[i] = UNKNOWN; continue; } if (nnearest[i] != 12 && nnearest[i] != 14) { pattern[i] = OTHER; continue; } // loop over near neighbors of I to build cna data structure // cna[k][NCOMMON] = # of common neighbors of I with each of its neighs // cna[k][NBONDS] = # of bonds between those common neighbors // cna[k][MAXBOND] = max # of bonds of any common neighbor // cna[k][MINBOND] = min # of bonds of any common neighbor for (m = 0; m < nnearest[i]; m++) { j = nearest[i][m]; // common = list of neighbors common to atom I and atom J // if J is an owned atom, use its near neighbor list to find them // if J is a ghost atom, use full neighbor list of I to find them // in latter case, must exclude J from I's neighbor list if (j < nlocal) { firstflag = 1; ncommon = 0; for (inear = 0; inear < nnearest[i]; inear++) for (jnear = 0; jnear < nnearest[j]; jnear++) if (nearest[i][inear] == nearest[j][jnear]) { if (ncommon < MAXCOMMON) common[ncommon++] = nearest[i][inear]; else if (firstflag) { nerror++; firstflag = 0; } } } else { xtmp = x[j][0]; ytmp = x[j][1]; ztmp = x[j][2]; jlist = firstneigh[i]; jnum = numneigh[i]; n = 0; for (kk = 0; kk < jnum; kk++) { k = jlist[kk]; + k &= NEIGHMASK; if (k == j) continue; delx = xtmp - x[k][0]; dely = ytmp - x[k][1]; delz = ztmp - x[k][2]; rsq = delx*delx + dely*dely + delz*delz; if (rsq < cutsq) { if (n < MAXNEAR) onenearest[n++] = k; else break; } } firstflag = 1; ncommon = 0; for (inear = 0; inear < nnearest[i]; inear++) for (jnear = 0; jnear < n; jnear++) if (nearest[i][inear] == onenearest[jnear]) { if (ncommon < MAXCOMMON) common[ncommon++] = nearest[i][inear]; else if (firstflag) { nerror++; firstflag = 0; } } } cna[m][NCOMMON] = ncommon; // calculate total # of bonds between common neighbor atoms // also max and min # of common atoms any common atom is bonded to // bond = pair of atoms within cutoff for (n = 0; n < ncommon; n++) bonds[n] = 0; nbonds = 0; for (jj = 0; jj < ncommon; jj++) { j = common[jj]; xtmp = x[j][0]; ytmp = x[j][1]; ztmp = x[j][2]; for (kk = jj+1; kk < ncommon; kk++) { k = common[kk]; delx = xtmp - x[k][0]; dely = ytmp - x[k][1]; delz = ztmp - x[k][2]; rsq = delx*delx + dely*dely + delz*delz; if (rsq < cutsq) { nbonds++; bonds[jj]++; bonds[kk]++; } } } cna[m][NBOND] = nbonds; maxbonds = 0; minbonds = MAXCOMMON; for (n = 0; n < ncommon; n++) { maxbonds = MAX(bonds[n],maxbonds); minbonds = MIN(bonds[n],minbonds); } cna[m][MAXBOND] = maxbonds; cna[m][MINBOND] = minbonds; } // detect CNA pattern of the atom nfcc = nhcp = nbcc4 = nbcc6 = nico = 0; pattern[i] = OTHER; if (nnearest[i] == 12) { for (inear = 0; inear < 12; inear++) { cj = cna[inear][NCOMMON]; ck = cna[inear][NBOND]; cl = cna[inear][MAXBOND]; cm = cna[inear][MINBOND]; if (cj == 4 && ck == 2 && cl == 1 && cm == 1) nfcc++; else if (cj == 4 && ck == 2 && cl == 2 && cm == 0) nhcp++; else if (cj == 5 && ck == 5 && cl == 2 && cm == 2) nico++; } if (nfcc == 12) pattern[i] = FCC; else if (nfcc == 6 && nhcp == 6) pattern[i] = HCP; else if (nico == 12) pattern[i] = ICOS; } else if (nnearest[i] == 14) { for (inear = 0; inear < 14; inear++) { cj = cna[inear][NCOMMON]; ck = cna[inear][NBOND]; cl = cna[inear][MAXBOND]; cm = cna[inear][MINBOND]; if (cj == 4 && ck == 4 && cl == 2 && cm == 2) nbcc4++; else if (cj == 6 && ck == 6 && cl == 2 && cm == 2) nbcc6++; } if (nbcc4 == 6 && nbcc6 == 8) pattern[i] = BCC; } } // warning message MPI_Allreduce(&nerror,&nerrorall,1,MPI_INT,MPI_SUM,world); if (nerrorall && comm->me == 0) { char str[128]; sprintf(str,"Too many common neighbors in CNA %d times",nerrorall); error->warning(str); } } /* ---------------------------------------------------------------------- memory usage of local atom-based array ------------------------------------------------------------------------- */ double ComputeCNAAtom::memory_usage() { double bytes = nmax * sizeof(int); bytes += nmax * MAXNEAR * sizeof(int); bytes += nmax * sizeof(double); return bytes; } diff --git a/src/compute_coord_atom.cpp b/src/compute_coord_atom.cpp index 46280b69b..1461be86f 100644 --- a/src/compute_coord_atom.cpp +++ b/src/compute_coord_atom.cpp @@ -1,157 +1,157 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "math.h" #include "string.h" #include "stdlib.h" #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) { if (narg != 4) error->all("Illegal compute coord/atom command"); double cutoff = atof(arg[3]); cutsq = cutoff*cutoff; peratom_flag = 1; size_peratom_cols = 0; nmax = 0; coordination = NULL; } /* ---------------------------------------------------------------------- */ ComputeCoordAtom::~ComputeCoordAtom() { memory->destroy(coordination); } /* ---------------------------------------------------------------------- */ void ComputeCoordAtom::init() { if (force->pair == NULL) error->all("Compute coord/atom requires a pair style be defined"); if (sqrt(cutsq) > force->pair->cutforce) error->all("Compute coord/atom cutoff is longer than pairwise cutoff"); // need an occasional full neighbor list int irequest = neighbor->request((void *) this); 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("More than one compute coord/atom"); } /* ---------------------------------------------------------------------- */ void ComputeCoordAtom::init_list(int id, NeighList *ptr) { list = ptr; } /* ---------------------------------------------------------------------- */ void ComputeCoordAtom::compute_peratom() { int i,j,ii,jj,inum,jnum,n; double xtmp,ytmp,ztmp,delx,dely,delz,rsq; int *ilist,*jlist,*numneigh,**firstneigh; invoked_peratom = update->ntimestep; // grow coordination array if necessary if (atom->nlocal > nmax) { memory->destroy(coordination); nmax = atom->nmax; memory->create(coordination,nmax,"coord/atom:coordination"); vector_atom = coordination; } // invoke full neighbor list (will copy or build if necessary) neighbor->build_one(list->index); inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // compute coordination number for each atom in group // use full neighbor list to count atoms less than cutoff double **x = atom->x; int *mask = atom->mask; int nall = atom->nlocal + atom->nghost; 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]; - if (j >= nall) j %= nall; + 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 < cutsq) n++; } coordination[i] = n; } else coordination[i] = 0.0; } } /* ---------------------------------------------------------------------- memory usage of local atom-based array ------------------------------------------------------------------------- */ double ComputeCoordAtom::memory_usage() { double bytes = nmax * sizeof(double); return bytes; } diff --git a/src/compute_group_group.cpp b/src/compute_group_group.cpp index bf1cb8184..e7f80f66b 100644 --- a/src/compute_group_group.cpp +++ b/src/compute_group_group.cpp @@ -1,221 +1,217 @@ /* ---------------------------------------------------------------------- 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 "mpi.h" #include "string.h" #include "compute_group_group.h" #include "atom.h" #include "update.h" #include "force.h" #include "pair.h" #include "neighbor.h" #include "neigh_request.h" #include "neigh_list.h" #include "group.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ ComputeGroupGroup::ComputeGroupGroup(LAMMPS *lmp, int narg, char **arg) : Compute(lmp, narg, arg) { if (narg != 4) error->all("Illegal compute group/group command"); scalar_flag = vector_flag = 1; size_vector = 3; extscalar = 1; extvector = 1; int n = strlen(arg[3]) + 1; group2 = new char[n]; strcpy(group2,arg[3]); jgroup = group->find(group2); if (jgroup == -1) error->all("Compute group/group group ID does not exist"); jgroupbit = group->bitmask[jgroup]; vector = new double[3]; } /* ---------------------------------------------------------------------- */ ComputeGroupGroup::~ComputeGroupGroup() { delete [] group2; delete [] vector; } /* ---------------------------------------------------------------------- */ void ComputeGroupGroup::init() { if (force->pair == NULL) error->all("No pair style defined for compute group/group"); // if non-hybrid, then error if single_enable = 0 // if hybrid, let hybrid determine if sub-style sets single_enable = 0 if (force->pair_match("hybrid",0) == NULL && force->pair->single_enable == 0) error->all("Pair style does not support compute group/group"); pair = force->pair; cutsq = force->pair->cutsq; // recheck that group 2 has not been deleted jgroup = group->find(group2); if (jgroup == -1) error->all("Compute group/group group ID does not exist"); jgroupbit = group->bitmask[jgroup]; // need an occasional half neighbor list int irequest = neighbor->request((void *) this); neighbor->requests[irequest]->pair = 0; neighbor->requests[irequest]->compute = 1; neighbor->requests[irequest]->occasional = 1; } /* ---------------------------------------------------------------------- */ void ComputeGroupGroup::init_list(int id, NeighList *ptr) { list = ptr; } /* ---------------------------------------------------------------------- */ double ComputeGroupGroup::compute_scalar() { invoked_scalar = invoked_vector = update->ntimestep; interact(); return scalar; } /* ---------------------------------------------------------------------- */ void ComputeGroupGroup::compute_vector() { invoked_scalar = invoked_vector = update->ntimestep; interact(); } /* ---------------------------------------------------------------------- */ void ComputeGroupGroup::interact() { int i,j,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz; double rsq,eng,fpair,factor_coul,factor_lj; int *ilist,*jlist,*numneigh,**firstneigh; double **x = atom->x; int *type = atom->type; int *mask = atom->mask; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; double *special_coul = force->special_coul; double *special_lj = force->special_lj; int newton_pair = force->newton_pair; // invoke half neighbor list (will copy or build if necessary) neighbor->build_one(list->index); inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // loop over neighbors of my atoms // skip if I,J are not in 2 groups double one[4],all[4]; one[0] = one[1] = one[2] = one[3] = 0.0; for (ii = 0; ii < inum; ii++) { i = ilist[ii]; if (mask[i] & groupbit) othergroupbit = jgroupbit; else if (mask[i] & jgroupbit) othergroupbit = groupbit; else 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]; - - if (j < nall) factor_coul = factor_lj = 1.0; - else { - factor_coul = special_coul[j/nall]; - factor_lj = special_lj[j/nall]; - j %= nall; - } + factor_lj = special_lj[sbmask(j)]; + factor_coul = special_coul[sbmask(j)]; + j &= NEIGHMASK; if (!(mask[j] & othergroupbit)) continue; 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]) { eng = pair->single(i,j,itype,jtype,rsq,factor_coul,factor_lj,fpair); // energy only computed once so tally full amount // force tally is jgroup acting on igroup if (newton_pair || j < nlocal) { one[0] += eng; if (othergroupbit == jgroupbit) { one[1] += delx*fpair; one[2] += dely*fpair; one[3] += delz*fpair; } if (othergroupbit == groupbit) { one[1] -= delx*fpair; one[2] -= dely*fpair; one[3] -= delz*fpair; } // energy computed twice so tally half amount // only tally force if I own igroup atom } else { one[0] += 0.5*eng; if (othergroupbit == jgroupbit) { one[1] += delx*fpair; one[2] += dely*fpair; one[3] += delz*fpair; } } } } } MPI_Allreduce(one,all,4,MPI_DOUBLE,MPI_SUM,world); scalar = all[0]; vector[0] = all[1]; vector[1] = all[2]; vector[2] = all[3]; } diff --git a/src/compute_pair_local.cpp b/src/compute_pair_local.cpp index 71828e504..a8b6bff07 100644 --- a/src/compute_pair_local.cpp +++ b/src/compute_pair_local.cpp @@ -1,234 +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. ------------------------------------------------------------------------- */ #include "math.h" #include "string.h" #include "compute_pair_local.h" #include "atom.h" #include "update.h" #include "force.h" #include "pair.h" #include "neighbor.h" #include "neigh_request.h" #include "neigh_list.h" #include "group.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define DELTA 10000 /* ---------------------------------------------------------------------- */ ComputePairLocal::ComputePairLocal(LAMMPS *lmp, int narg, char **arg) : Compute(lmp, narg, arg) { if (narg < 4) error->all("Illegal compute pair/local command"); local_flag = 1; nvalues = narg - 3; if (nvalues == 1) size_local_cols = 0; else size_local_cols = nvalues; dflag = eflag = fflag = -1; nvalues = 0; int i; for (int iarg = 3; iarg < narg; iarg++) { i = iarg-3; if (strcmp(arg[iarg],"dist") == 0) dflag = nvalues++; else if (strcmp(arg[iarg],"eng") == 0) eflag = nvalues++; else if (strcmp(arg[iarg],"force") == 0) fflag = nvalues++; else error->all("Invalid keyword in compute pair/local command"); } nmax = 0; vector = NULL; array = NULL; } /* ---------------------------------------------------------------------- */ ComputePairLocal::~ComputePairLocal() { memory->destroy(vector); memory->destroy(array); } /* ---------------------------------------------------------------------- */ void ComputePairLocal::init() { if (force->pair == NULL) error->all("No pair style is defined for compute pair/local"); if (force->pair->single_enable == 0) error->all("Pair style does not support compute pair/local"); // need an occasional half neighbor list int irequest = neighbor->request((void *) this); neighbor->requests[irequest]->pair = 0; neighbor->requests[irequest]->compute = 1; neighbor->requests[irequest]->occasional = 1; } /* ---------------------------------------------------------------------- */ void ComputePairLocal::init_list(int id, NeighList *ptr) { list = ptr; } /* ---------------------------------------------------------------------- */ void ComputePairLocal::compute_local() { invoked_local = update->ntimestep; // count local entries and compute pair info ncount = compute_pairs(0); if (ncount > nmax) reallocate(ncount); size_local_rows = ncount; ncount = compute_pairs(1); } /* ---------------------------------------------------------------------- count pairs and compute pair info on this proc only count pair once if newton_pair is off both atom I,J must be in group if flag is set, compute requested info about pair ------------------------------------------------------------------------- */ int ComputePairLocal::compute_pairs(int flag) { int i,j,m,n,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz; double rsq,eng,fpair,factor_coul,factor_lj; int *ilist,*jlist,*numneigh,**firstneigh; double *dbuf,*ebuf,*fbuf; double **x = atom->x; int *type = atom->type; int *mask = atom->mask; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; double *special_coul = force->special_coul; double *special_lj = force->special_lj; int newton_pair = force->newton_pair; // invoke half neighbor list (will copy or build if necessary) if (flag == 0) neighbor->build_one(list->index); inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // loop over neighbors of my atoms // skip if I or J are not in group if (flag) { if (nvalues == 1) { if (dflag >= 0) dbuf = vector; if (eflag >= 0) ebuf = vector; if (fflag >= 0) fbuf = vector; } else { if (dflag >= 0) dbuf = &array[0][dflag]; if (eflag >= 0) ebuf = &array[0][eflag]; if (fflag >= 0) fbuf = &array[0][fflag]; } } Pair *pair = force->pair; double **cutsq = force->pair->cutsq; m = n = 0; 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]; - - if (j < nall) factor_coul = factor_lj = 1.0; - else { - factor_coul = special_coul[j/nall]; - factor_lj = special_lj[j/nall]; - j %= nall; - } + factor_lj = special_lj[sbmask(j)]; + factor_coul = special_coul[sbmask(j)]; + j &= NEIGHMASK; if (!(mask[j] & groupbit)) continue; if (newton_pair == 0 && j >= nlocal) continue; 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; if (flag) { if (dflag >= 0) dbuf[n] = sqrt(rsq); if (eflag >= 0 || fflag >= 0) { eng = pair->single(i,j,itype,jtype,rsq,factor_coul,factor_lj,fpair); if (eflag >= 0) ebuf[n] = eng; if (fflag >= 0) fbuf[n] = sqrt(rsq)*fpair; } n += nvalues; } m++; } } return m; } /* ---------------------------------------------------------------------- */ void ComputePairLocal::reallocate(int n) { // grow vector or array and indices array while (nmax < n) nmax += DELTA; if (nvalues == 1) { memory->destroy(vector); memory->create(vector,nmax,"pair/local:vector"); vector_local = vector; } else { memory->destroy(array); memory->create(array,nmax,nvalues,"pair/local:array"); array_local = array; } } /* ---------------------------------------------------------------------- memory usage of local data ------------------------------------------------------------------------- */ double ComputePairLocal::memory_usage() { double bytes = nmax*nvalues * sizeof(double); return bytes; } diff --git a/src/compute_property_local.cpp b/src/compute_property_local.cpp index 4f5ef51a3..8955393a1 100644 --- a/src/compute_property_local.cpp +++ b/src/compute_property_local.cpp @@ -1,835 +1,831 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "string.h" #include "compute_property_local.h" #include "atom.h" #include "atom_vec.h" #include "update.h" #include "force.h" #include "pair.h" #include "neighbor.h" #include "neigh_request.h" #include "neigh_list.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; enum{NONE,NEIGH,PAIR,BOND,ANGLE,DIHEDRAL,IMPROPER}; #define DELTA 10000 /* ---------------------------------------------------------------------- */ ComputePropertyLocal::ComputePropertyLocal(LAMMPS *lmp, int narg, char **arg) : Compute(lmp, narg, arg) { if (narg < 4) error->all("Illegal compute property/local command"); local_flag = 1; nvalues = narg - 3; if (nvalues == 1) size_local_cols = 0; else size_local_cols = nvalues; pack_choice = new FnPtrPack[nvalues]; kindflag = NONE; int i; for (int iarg = 3; iarg < narg; iarg++) { i = iarg-3; if (strcmp(arg[iarg],"natom1") == 0) { pack_choice[i] = &ComputePropertyLocal::pack_patom1; if (kindflag != NONE && kindflag != NEIGH) error->all("Compute property/local cannot use these inputs together"); kindflag = NEIGH; } else if (strcmp(arg[iarg],"natom2") == 0) { pack_choice[i] = &ComputePropertyLocal::pack_patom2; if (kindflag != NONE && kindflag != NEIGH) error->all("Compute property/local cannot use these inputs together"); kindflag = NEIGH; } else if (strcmp(arg[iarg],"patom1") == 0) { pack_choice[i] = &ComputePropertyLocal::pack_patom1; if (kindflag != NONE && kindflag != PAIR) error->all("Compute property/local cannot use these inputs together"); kindflag = PAIR; } else if (strcmp(arg[iarg],"patom2") == 0) { pack_choice[i] = &ComputePropertyLocal::pack_patom2; if (kindflag != NONE && kindflag != PAIR) error->all("Compute property/local cannot use these inputs together"); kindflag = PAIR; } else if (strcmp(arg[iarg],"batom1") == 0) { pack_choice[i] = &ComputePropertyLocal::pack_batom1; if (kindflag != NONE && kindflag != BOND) error->all("Compute property/local cannot use these inputs together"); kindflag = BOND; } else if (strcmp(arg[iarg],"batom2") == 0) { pack_choice[i] = &ComputePropertyLocal::pack_batom2; if (kindflag != NONE && kindflag != BOND) error->all("Compute property/local cannot use these inputs together"); kindflag = BOND; } else if (strcmp(arg[iarg],"btype") == 0) { pack_choice[i] = &ComputePropertyLocal::pack_btype; if (kindflag != NONE && kindflag != BOND) error->all("Compute property/local cannot use these inputs together"); kindflag = BOND; } else if (strcmp(arg[iarg],"aatom1") == 0) { pack_choice[i] = &ComputePropertyLocal::pack_aatom1; if (kindflag != NONE && kindflag != ANGLE) error->all("Compute property/local cannot use these inputs together"); kindflag = ANGLE; } else if (strcmp(arg[iarg],"aatom2") == 0) { pack_choice[i] = &ComputePropertyLocal::pack_aatom2; if (kindflag != NONE && kindflag != ANGLE) error->all("Compute property/local cannot use these inputs together"); kindflag = ANGLE; } else if (strcmp(arg[iarg],"aatom3") == 0) { pack_choice[i] = &ComputePropertyLocal::pack_aatom3; if (kindflag != NONE && kindflag != ANGLE) error->all("Compute property/local cannot use these inputs together"); kindflag = ANGLE; } else if (strcmp(arg[iarg],"atype") == 0) { pack_choice[i] = &ComputePropertyLocal::pack_atype; if (kindflag != NONE && kindflag != ANGLE) error->all("Compute property/local cannot use these inputs together"); kindflag = ANGLE; } else if (strcmp(arg[iarg],"datom1") == 0) { pack_choice[i] = &ComputePropertyLocal::pack_datom1; if (kindflag != NONE && kindflag != DIHEDRAL) error->all("Compute property/local cannot use these inputs together"); kindflag = DIHEDRAL; } else if (strcmp(arg[iarg],"datom2") == 0) { pack_choice[i] = &ComputePropertyLocal::pack_datom2; if (kindflag != NONE && kindflag != DIHEDRAL) error->all("Compute property/local cannot use these inputs together"); kindflag = DIHEDRAL; } else if (strcmp(arg[iarg],"datom3") == 0) { pack_choice[i] = &ComputePropertyLocal::pack_datom3; if (kindflag != NONE && kindflag != DIHEDRAL) error->all("Compute property/local cannot use these inputs together"); kindflag = DIHEDRAL; } else if (strcmp(arg[iarg],"datom4") == 0) { pack_choice[i] = &ComputePropertyLocal::pack_datom4; if (kindflag != NONE && kindflag != DIHEDRAL) error->all("Compute property/local cannot use these inputs together"); kindflag = DIHEDRAL; } else if (strcmp(arg[iarg],"dtype") == 0) { pack_choice[i] = &ComputePropertyLocal::pack_dtype; if (kindflag != NONE && kindflag != DIHEDRAL) error->all("Compute property/local cannot use these inputs together"); kindflag = DIHEDRAL; } else if (strcmp(arg[iarg],"iatom1") == 0) { pack_choice[i] = &ComputePropertyLocal::pack_iatom1; if (kindflag != NONE && kindflag != IMPROPER) error->all("Compute property/local cannot use these inputs together"); kindflag = IMPROPER; } else if (strcmp(arg[iarg],"iatom2") == 0) { pack_choice[i] = &ComputePropertyLocal::pack_iatom2; if (kindflag != NONE && kindflag != IMPROPER) error->all("Compute property/local cannot use these inputs together"); kindflag = IMPROPER; } else if (strcmp(arg[iarg],"iatom3") == 0) { pack_choice[i] = &ComputePropertyLocal::pack_iatom3; if (kindflag != NONE && kindflag != IMPROPER) error->all("Compute property/local cannot use these inputs together"); kindflag = IMPROPER; } else if (strcmp(arg[iarg],"iatom4") == 0) { pack_choice[i] = &ComputePropertyLocal::pack_iatom4; if (kindflag != NONE && kindflag != IMPROPER) error->all("Compute property/local cannot use these inputs together"); kindflag = IMPROPER; } else if (strcmp(arg[iarg],"itype") == 0) { pack_choice[i] = &ComputePropertyLocal::pack_itype; if (kindflag != NONE && kindflag != IMPROPER) error->all("Compute property/local cannot use these inputs together"); kindflag = IMPROPER; } else error->all("Invalid keyword in compute property/local command"); } // error check if (kindflag == BOND && atom->avec->bonds_allow == 0) error->all("Compute property/local for property that isn't allocated"); if (kindflag == ANGLE && atom->avec->angles_allow == 0) error->all("Compute property/local for property that isn't allocated"); if (kindflag == DIHEDRAL && atom->avec->dihedrals_allow == 0) error->all("Compute property/local for property that isn't allocated"); if (kindflag == IMPROPER && atom->avec->impropers_allow == 0) error->all("Compute property/local for property that isn't allocated"); nmax = 0; vector = NULL; array = NULL; indices = NULL; } /* ---------------------------------------------------------------------- */ ComputePropertyLocal::~ComputePropertyLocal() { delete [] pack_choice; memory->destroy(vector); memory->destroy(array); memory->destroy(indices); } /* ---------------------------------------------------------------------- */ void ComputePropertyLocal::init() { if (kindflag == NEIGH || kindflag == PAIR) { if (force->pair == NULL) error->all("No pair style is defined for compute property/local"); if (force->pair->single_enable == 0) error->all("Pair style does not support compute property/local"); } // for NEIGH/PAIR need an occasional half neighbor list if (kindflag == NEIGH || kindflag == PAIR) { int irequest = neighbor->request((void *) this); neighbor->requests[irequest]->pair = 0; neighbor->requests[irequest]->compute = 1; neighbor->requests[irequest]->occasional = 1; } // do initial memory allocation so that memory_usage() is correct // cannot be done yet for NEIGH/PAIR, since neigh list does not exist if (kindflag == NEIGH) ncount = 0; else if (kindflag == PAIR) ncount = 0; else if (kindflag == BOND) ncount = count_bonds(0); else if (kindflag == ANGLE) ncount = count_angles(0); else if (kindflag == DIHEDRAL) ncount = count_dihedrals(0); else if (kindflag == IMPROPER) ncount = count_impropers(0); if (ncount > nmax) reallocate(ncount); size_local_rows = ncount; } /* ---------------------------------------------------------------------- */ void ComputePropertyLocal::init_list(int id, NeighList *ptr) { list = ptr; } /* ---------------------------------------------------------------------- */ void ComputePropertyLocal::compute_local() { invoked_local = update->ntimestep; // count local entries and generate list of indices if (kindflag == NEIGH) ncount = count_pairs(0,0); else if (kindflag == PAIR) ncount = count_pairs(0,1); else if (kindflag == BOND) ncount = count_bonds(0); else if (kindflag == ANGLE) ncount = count_angles(0); else if (kindflag == DIHEDRAL) ncount = count_dihedrals(0); else if (kindflag == IMPROPER) ncount = count_impropers(0); if (ncount > nmax) reallocate(ncount); size_local_rows = ncount; if (kindflag == NEIGH) ncount = count_pairs(1,0); else if (kindflag == PAIR) ncount = count_pairs(1,1); else if (kindflag == BOND) ncount = count_bonds(1); else if (kindflag == ANGLE) ncount = count_angles(1); else if (kindflag == DIHEDRAL) ncount = count_dihedrals(1); else if (kindflag == IMPROPER) ncount = count_impropers(1); // fill vector or array with local values if (nvalues == 1) { buf = vector; (this->*pack_choice[0])(0); } else { if (array) buf = &array[0][0]; for (int n = 0; n < nvalues; n++) (this->*pack_choice[n])(n); } } /* ---------------------------------------------------------------------- count pairs and compute pair info on this proc only count pair once if newton_pair is off both atom I,J must be in group if allflag is set, compute requested info about pair if forceflag = 1, pair must be within force cutoff, else neighbor cutoff ------------------------------------------------------------------------- */ int ComputePropertyLocal::count_pairs(int allflag, int forceflag) { int i,j,m,n,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz; double rsq,factor_coul,factor_lj; int *ilist,*jlist,*numneigh,**firstneigh; double **x = atom->x; int *tag = atom->tag; int *type = atom->type; int *mask = atom->mask; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; double *special_coul = force->special_coul; double *special_lj = force->special_lj; int newton_pair = force->newton_pair; // invoke half neighbor list (will copy or build if necessary) if (allflag == 0) neighbor->build_one(list->index); inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // loop over neighbors of my atoms // skip if I or J are not in group double **cutsq = force->pair->cutsq; m = n = 0; 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]; - - if (j < nall) factor_coul = factor_lj = 1.0; - else { - factor_coul = special_coul[j/nall]; - factor_lj = special_lj[j/nall]; - j %= nall; - } + factor_lj = special_lj[sbmask(j)]; + factor_coul = special_coul[sbmask(j)]; + j &= NEIGHMASK; if (!(mask[j] & groupbit)) continue; if (newton_pair == 0 && j >= nlocal) continue; 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 (forceflag && rsq >= cutsq[itype][jtype]) continue; if (allflag) { indices[m][0] = tag[i]; indices[m][1] = tag[j]; } m++; } } return m; } /* ---------------------------------------------------------------------- count bonds on this proc only count bond once if newton_bond is off all atoms in interaction must be in group all atoms in interaction must be known to proc if bond is deleted (type = 0), do not count if bond is turned off (type < 0), still count ------------------------------------------------------------------------- */ int ComputePropertyLocal::count_bonds(int flag) { int i,atom1,atom2; int *num_bond = atom->num_bond; int **bond_atom = atom->bond_atom; int **bond_type = atom->bond_type; int *tag = atom->tag; int *mask = atom->mask; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; int m = 0; for (atom1 = 0; atom1 < nlocal; atom1++) { if (!(mask[atom1] & groupbit)) continue; for (i = 0; i < num_bond[atom1]; i++) { atom2 = atom->map(bond_atom[atom1][i]); if (atom2 < 0 || !(mask[atom2] & groupbit)) continue; if (newton_bond == 0 && tag[atom1] > tag[atom2]) continue; if (bond_type[atom1][i] == 0) continue; if (flag) { indices[m][0] = atom1; indices[m][1] = i; } m++; } } return m; } /* ---------------------------------------------------------------------- count angles on this proc only count if 2nd atom is the one storing the angle all atoms in interaction must be in group all atoms in interaction must be known to proc if angle is deleted (type = 0), do not count if angle is turned off (type < 0), still count ------------------------------------------------------------------------- */ int ComputePropertyLocal::count_angles(int flag) { int i,atom1,atom2,atom3; int *num_angle = atom->num_angle; int **angle_atom1 = atom->angle_atom1; int **angle_atom2 = atom->angle_atom2; int **angle_atom3 = atom->angle_atom3; int **angle_type = atom->angle_type; int *tag = atom->tag; int *mask = atom->mask; int nlocal = atom->nlocal; int m = 0; for (atom2 = 0; atom2 < nlocal; atom2++) { if (!(mask[atom2] & groupbit)) continue; for (i = 0; i < num_angle[atom2]; i++) { if (tag[atom2] != angle_atom2[atom2][i]) continue; atom1 = atom->map(angle_atom1[atom2][i]); if (atom1 < 0 || !(mask[atom1] & groupbit)) continue; atom3 = atom->map(angle_atom3[atom2][i]); if (atom3 < 0 || !(mask[atom3] & groupbit)) continue; if (angle_type[atom2][i] == 0) continue; if (flag) { indices[m][0] = atom2; indices[m][1] = i; } m++; } } return m; } /* ---------------------------------------------------------------------- count dihedrals on this proc only count if 2nd atom is the one storing the dihedral all atoms in interaction must be in group all atoms in interaction must be known to proc ------------------------------------------------------------------------- */ int ComputePropertyLocal::count_dihedrals(int flag) { int i,atom1,atom2,atom3,atom4; int *num_dihedral = atom->num_dihedral; int **dihedral_atom1 = atom->dihedral_atom1; int **dihedral_atom2 = atom->dihedral_atom2; int **dihedral_atom3 = atom->dihedral_atom3; int **dihedral_atom4 = atom->dihedral_atom4; int *tag = atom->tag; int *mask = atom->mask; int nlocal = atom->nlocal; int m = 0; for (atom2 = 0; atom2 < nlocal; atom2++) { if (!(mask[atom2] & groupbit)) continue; for (i = 0; i < num_dihedral[atom2]; i++) { if (tag[atom2] != dihedral_atom2[atom2][i]) continue; atom1 = atom->map(dihedral_atom1[atom2][i]); if (atom1 < 0 || !(mask[atom1] & groupbit)) continue; atom3 = atom->map(dihedral_atom3[atom2][i]); if (atom3 < 0 || !(mask[atom3] & groupbit)) continue; atom4 = atom->map(dihedral_atom4[atom2][i]); if (atom4 < 0 || !(mask[atom4] & groupbit)) continue; if (flag) { indices[m][0] = atom2; indices[m][1] = i; } m++; } } return m; } /* ---------------------------------------------------------------------- count impropers on this proc only count if 2nd atom is the one storing the improper all atoms in interaction must be in group all atoms in interaction must be known to proc ------------------------------------------------------------------------- */ int ComputePropertyLocal::count_impropers(int flag) { int i,atom1,atom2,atom3,atom4; int *num_improper = atom->num_improper; int **improper_atom1 = atom->improper_atom1; int **improper_atom2 = atom->improper_atom2; int **improper_atom3 = atom->improper_atom3; int **improper_atom4 = atom->improper_atom4; int *tag = atom->tag; int *mask = atom->mask; int nlocal = atom->nlocal; int m = 0; for (atom2 = 0; atom2 < nlocal; atom2++) { if (!(mask[atom2] & groupbit)) continue; for (i = 0; i < num_improper[atom2]; i++) { if (tag[atom2] != improper_atom2[atom2][i]) continue; atom1 = atom->map(improper_atom1[atom2][i]); if (atom1 < 0 || !(mask[atom1] & groupbit)) continue; atom3 = atom->map(improper_atom3[atom2][i]); if (atom3 < 0 || !(mask[atom3] & groupbit)) continue; atom4 = atom->map(improper_atom4[atom2][i]); if (atom4 < 0 || !(mask[atom4] & groupbit)) continue; if (flag) { indices[m][0] = atom2; indices[m][1] = i; } m++; } } return m; } /* ---------------------------------------------------------------------- */ void ComputePropertyLocal::reallocate(int n) { // grow vector or array and indices array while (nmax < n) nmax += DELTA; if (nvalues == 1) { memory->destroy(vector); memory->create(vector,nmax,"property/local:vector"); vector_local = vector; } else { memory->destroy(array); memory->create(array,nmax,nvalues,"property/local:array"); array_local = array; } memory->destroy(indices); memory->create(indices,nmax,2,"property/local:indices"); } /* ---------------------------------------------------------------------- memory usage of local data ------------------------------------------------------------------------- */ double ComputePropertyLocal::memory_usage() { double bytes = nmax*nvalues * sizeof(double); bytes += nmax*2 * sizeof(int); return bytes; } /* ---------------------------------------------------------------------- one method for every keyword compute property/local can output the atom property is packed into buf starting at n with stride nvalues customize a new keyword by adding a method ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */ void ComputePropertyLocal::pack_patom1(int n) { for (int m = 0; m < ncount; m++) { buf[n] = indices[m][0]; n += nvalues; } } /* ---------------------------------------------------------------------- */ void ComputePropertyLocal::pack_patom2(int n) { for (int m = 0; m < ncount; m++) { buf[n] = indices[m][1]; n += nvalues; } } /* ---------------------------------------------------------------------- */ void ComputePropertyLocal::pack_batom1(int n) { int i; int *tag = atom->tag; for (int m = 0; m < ncount; m++) { i = indices[m][0]; buf[n] = tag[i]; n += nvalues; } } /* ---------------------------------------------------------------------- */ void ComputePropertyLocal::pack_batom2(int n) { int i,j; int **bond_atom = atom->bond_atom; for (int m = 0; m < ncount; m++) { i = indices[m][0]; j = indices[m][1]; buf[n] = bond_atom[i][j]; n += nvalues; } } /* ---------------------------------------------------------------------- */ void ComputePropertyLocal::pack_btype(int n) { int i,j; int **bond_type = atom->bond_type; for (int m = 0; m < ncount; m++) { i = indices[m][0]; j = indices[m][1]; buf[n] = bond_type[i][j]; n += nvalues; } } /* ---------------------------------------------------------------------- */ void ComputePropertyLocal::pack_aatom1(int n) { int i,j; int **angle_atom1 = atom->angle_atom1; for (int m = 0; m < ncount; m++) { i = indices[m][0]; j = indices[m][1]; buf[n] = angle_atom1[i][j]; n += nvalues; } } /* ---------------------------------------------------------------------- */ void ComputePropertyLocal::pack_aatom2(int n) { int i,j; int **angle_atom2 = atom->angle_atom2; for (int m = 0; m < ncount; m++) { i = indices[m][0]; j = indices[m][1]; buf[n] = angle_atom2[i][j]; n += nvalues; } } /* ---------------------------------------------------------------------- */ void ComputePropertyLocal::pack_aatom3(int n) { int i,j; int **angle_atom3 = atom->angle_atom3; for (int m = 0; m < ncount; m++) { i = indices[m][0]; j = indices[m][1]; buf[n] = angle_atom3[i][j]; n += nvalues; } } /* ---------------------------------------------------------------------- */ void ComputePropertyLocal::pack_atype(int n) { int i,j; int **angle_type = atom->angle_type; for (int m = 0; m < ncount; m++) { i = indices[m][0]; j = indices[m][1]; buf[n] = angle_type[i][j]; n += nvalues; } } /* ---------------------------------------------------------------------- */ void ComputePropertyLocal::pack_datom1(int n) { int i,j; int **dihedral_atom1 = atom->dihedral_atom1; for (int m = 0; m < ncount; m++) { i = indices[m][0]; j = indices[m][1]; buf[n] = dihedral_atom1[i][j]; n += nvalues; } } /* ---------------------------------------------------------------------- */ void ComputePropertyLocal::pack_datom2(int n) { int i,j; int **dihedral_atom2 = atom->dihedral_atom2; for (int m = 0; m < ncount; m++) { i = indices[m][0]; j = indices[m][1]; buf[n] = dihedral_atom2[i][j]; n += nvalues; } } /* ---------------------------------------------------------------------- */ void ComputePropertyLocal::pack_datom3(int n) { int i,j; int **dihedral_atom3 = atom->dihedral_atom3; for (int m = 0; m < ncount; m++) { i = indices[m][0]; j = indices[m][1]; buf[n] = dihedral_atom3[i][j]; n += nvalues; } } /* ---------------------------------------------------------------------- */ void ComputePropertyLocal::pack_datom4(int n) { int i,j; int **dihedral_atom4 = atom->dihedral_atom4; for (int m = 0; m < ncount; m++) { i = indices[m][0]; j = indices[m][1]; buf[n] = dihedral_atom4[i][j]; n += nvalues; } } /* ---------------------------------------------------------------------- */ void ComputePropertyLocal::pack_dtype(int n) { int i,j; int **dihedral_type = atom->dihedral_type; for (int m = 0; m < ncount; m++) { i = indices[m][0]; j = indices[m][1]; buf[n] = dihedral_type[i][j]; n += nvalues; } } /* ---------------------------------------------------------------------- */ void ComputePropertyLocal::pack_iatom1(int n) { int i,j; int **improper_atom1 = atom->improper_atom1; for (int m = 0; m < ncount; m++) { i = indices[m][0]; j = indices[m][1]; buf[n] = improper_atom1[i][j]; n += nvalues; } } /* ---------------------------------------------------------------------- */ void ComputePropertyLocal::pack_iatom2(int n) { int i,j; int **improper_atom2 = atom->improper_atom2; for (int m = 0; m < ncount; m++) { i = indices[m][0]; j = indices[m][1]; buf[n] = improper_atom2[i][j]; n += nvalues; } } /* ---------------------------------------------------------------------- */ void ComputePropertyLocal::pack_iatom3(int n) { int i,j; int **improper_atom3 = atom->improper_atom3; for (int m = 0; m < ncount; m++) { i = indices[m][0]; j = indices[m][1]; buf[n] = improper_atom3[i][j]; n += nvalues; } } /* ---------------------------------------------------------------------- */ void ComputePropertyLocal::pack_iatom4(int n) { int i,j; int **improper_atom4 = atom->improper_atom4; for (int m = 0; m < ncount; m++) { i = indices[m][0]; j = indices[m][1]; buf[n] = improper_atom4[i][j]; n += nvalues; } } /* ---------------------------------------------------------------------- */ void ComputePropertyLocal::pack_itype(int n) { int i,j; int **improper_type = atom->improper_type; for (int m = 0; m < ncount; m++) { i = indices[m][0]; j = indices[m][1]; buf[n] = improper_type[i][j]; n += nvalues; } } diff --git a/src/compute_rdf.cpp b/src/compute_rdf.cpp index 04848b392..e1f75014e 100644 --- a/src/compute_rdf.cpp +++ b/src/compute_rdf.cpp @@ -1,308 +1,310 @@ /* ---------------------------------------------------------------------- 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 "mpi.h" #include "math.h" #include "stdlib.h" #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 "memory.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ ComputeRDF::ComputeRDF(LAMMPS *lmp, int narg, char **arg) : Compute(lmp, narg, arg) { if (narg < 4 || (narg-4) % 2) error->all("Illegal compute rdf command"); array_flag = 1; extarray = 0; nbin = atoi(arg[3]); if (nbin < 1) error->all("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]); if (ilo[npairs] > ihi[npairs] || jlo[npairs] > jhi[npairs]) error->all("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]; } /* ---------------------------------------------------------------------- */ 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; } /* ---------------------------------------------------------------------- */ void ComputeRDF::init() { int i,m; if (force->pair) delr = force->pair->cutforce / nbin; else error->all("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 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]; } 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]; delete [] scratch; // need an occasional half neighbor list int irequest = neighbor->request((void *) this); 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->index); 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 - // weighting factor must be != 0.0 for this pair - // could be 0 and still be in neigh list for long-range Coulombics // 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; int nall = atom->nlocal + atom->nghost; 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 (j >= nall) { - if (special_coul[j/nall] == 0.0 && special_lj[j/nall] == 0.0) - continue; - j %= nall; - } + // 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 // nideal = # of J atoms surrounding single I atom in a single bin // assuming J atoms are at uniform density double constant,nideal,gr,ncoord,rlower,rupper; double PI = 4.0*atan(1.0); if (domain->dimension == 3) { constant = 4.0*PI / (3.0*domain->xprd*domain->yprd*domain->zprd); for (m = 0; m < npairs; m++) { ncoord = 0.0; for (ibin = 0; ibin < nbin; ibin++) { rlower = ibin*delr; rupper = (ibin+1)*delr; nideal = constant * (rupper*rupper*rupper - rlower*rlower*rlower) * jcount[m]; if (icount[m]*nideal != 0.0) gr = histall[m][ibin] / (icount[m]*nideal); else gr = 0.0; ncoord += gr*nideal; array[ibin][1+2*m] = gr; array[ibin][2+2*m] = ncoord; } } } else { constant = PI / (domain->xprd*domain->yprd); for (m = 0; m < npairs; m++) { ncoord = 0.0; for (ibin = 0; ibin < nbin; ibin++) { rlower = ibin*delr; rupper = (ibin+1)*delr; nideal = constant * (rupper*rupper - rlower*rlower) * jcount[m]; if (icount[m]*nideal != 0.0) gr = histall[m][ibin] / (icount[m]*nideal); else gr = 0.0; ncoord += gr*nideal; array[ibin][1+2*m] = gr; array[ibin][2+2*m] = ncoord; } } } } diff --git a/src/delete_atoms.cpp b/src/delete_atoms.cpp index e450828c6..56879053d 100644 --- a/src/delete_atoms.cpp +++ b/src/delete_atoms.cpp @@ -1,364 +1,365 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "lmptype.h" #include "stdlib.h" #include "string.h" #include "delete_atoms.h" #include "atom.h" #include "atom_vec.h" #include "comm.h" #include "domain.h" #include "force.h" #include "group.h" #include "region.h" #include "neighbor.h" #include "neigh_list.h" #include "neigh_request.h" #include "random_mars.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) /* ---------------------------------------------------------------------- */ DeleteAtoms::DeleteAtoms(LAMMPS *lmp) : Pointers(lmp) {} /* ---------------------------------------------------------------------- */ void DeleteAtoms::command(int narg, char **arg) { if (domain->box_exist == 0) error->all("Delete_atoms command before simulation box is defined"); if (narg < 1) error->all("Illegal delete_atoms command"); if (atom->tag_enable == 0) error->all("Cannot use delete_atoms unless atoms have IDs"); // store state before delete bigint natoms_previous = atom->natoms; // delete the atoms if (strcmp(arg[0],"group") == 0) delete_group(narg,arg); else if (strcmp(arg[0],"region") == 0) delete_region(narg,arg); else if (strcmp(arg[0],"overlap") == 0) delete_overlap(narg,arg); else if (strcmp(arg[0],"porosity") == 0) delete_porosity(narg,arg); else error->all("Illegal delete_atoms command"); // delete local atoms flagged in dlist // reset nlocal AtomVec *avec = atom->avec; int nlocal = atom->nlocal; int i = 0; while (i < nlocal) { if (dlist[i]) { avec->copy(nlocal-1,i); dlist[i] = dlist[nlocal-1]; nlocal--; } else i++; } atom->nlocal = nlocal; memory->destroy(dlist); // if non-molecular system and compress flag set, // reset atom tags to be contiguous // set all atom IDs to 0, call tag_extend() if (atom->molecular == 0 && compress_flag) { int *tag = atom->tag; for (i = 0; i < nlocal; i++) tag[i] = 0; atom->tag_extend(); } // reset atom->natoms // reset atom->map if it exists // set nghost to 0 so old ghosts of deleted atoms won't be mapped bigint nblocal = atom->nlocal; MPI_Allreduce(&nblocal,&atom->natoms,1,MPI_LMP_BIGINT,MPI_SUM,world); if (atom->map_style) { atom->nghost = 0; atom->map_init(); atom->map_set(); } // print before and after atom count bigint ndelete = natoms_previous - atom->natoms; if (comm->me == 0) { if (screen) fprintf(screen,"Deleted " BIGINT_FORMAT " atoms, new total = " BIGINT_FORMAT "\n", ndelete,atom->natoms); if (logfile) fprintf(logfile,"Deleted " BIGINT_FORMAT " atoms, new total = " BIGINT_FORMAT "\n", ndelete,atom->natoms); } } /* ---------------------------------------------------------------------- delete all atoms in group group will still exist ------------------------------------------------------------------------- */ void DeleteAtoms::delete_group(int narg, char **arg) { if (narg < 2) error->all("Illegal delete_atoms command"); int igroup = group->find(arg[1]); if (igroup == -1) error->all("Could not find delete_atoms group ID"); options(narg-2,&arg[2]); // allocate and initialize deletion list int nlocal = atom->nlocal; memory->create(dlist,nlocal,"delete_atoms:dlist"); for (int i = 0; i < nlocal; i++) dlist[i] = 0; int *mask = atom->mask; int groupbit = group->bitmask[igroup]; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) dlist[i] = 1; } /* ---------------------------------------------------------------------- delete all atoms in region ------------------------------------------------------------------------- */ void DeleteAtoms::delete_region(int narg, char **arg) { if (narg < 2) error->all("Illegal delete_atoms command"); int iregion = domain->find_region(arg[1]); if (iregion == -1) error->all("Could not find delete_atoms region ID"); options(narg-2,&arg[2]); // allocate and initialize deletion list int nlocal = atom->nlocal; memory->create(dlist,nlocal,"delete_atoms:dlist"); for (int i = 0; i < nlocal; i++) dlist[i] = 0; double **x = atom->x; for (int i = 0; i < nlocal; i++) if (domain->regions[iregion]->match(x[i][0],x[i][1],x[i][2])) dlist[i] = 1; } /* ---------------------------------------------------------------------- delete atoms so there are no pairs within cutoff which atoms are deleted depends on ordering of atoms within proc deletions can vary with processor count no guarantee that minimium number of atoms will be deleted ------------------------------------------------------------------------- */ void DeleteAtoms::delete_overlap(int narg, char **arg) { if (narg < 4) error->all("Illegal delete_atoms command"); // read args double cut = atof(arg[1]); double cutsq = cut*cut; int igroup1 = group->find(arg[2]); int igroup2 = group->find(arg[3]); if (igroup1 < 0 || igroup2 < 0) error->all("Could not find delete_atoms group ID"); options(narg-4,&arg[4]); int group1bit = group->bitmask[igroup1]; int group2bit = group->bitmask[igroup2]; if (comm->me == 0 && screen) fprintf(screen,"System init for delete_atoms ...\n"); // request a full neighbor list for use by this command int irequest = neighbor->request((void *) this); neighbor->requests[irequest]->pair = 0; neighbor->requests[irequest]->command = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->full = 1; neighbor->requests[irequest]->occasional = 1; // init entire system since comm->borders and neighbor->build is done // comm::init needs neighbor::init needs pair::init needs kspace::init, etc lmp->init(); // error check on cutoff // if no pair style, neighbor list will be empty if (force->pair == NULL) error->all("Delete_atoms requires a pair style be defined"); if (cut > neighbor->cutneighmax) error->all("Delete_atoms cutoff > neighbor cutoff"); // setup domain, communication and neighboring // acquire ghosts // build neighbor list based on earlier request if (domain->triclinic) domain->x2lamda(atom->nlocal); domain->pbc(); domain->reset_box(); comm->setup(); if (neighbor->style) neighbor->setup_bins(); comm->exchange(); comm->borders(); if (domain->triclinic) domain->lamda2x(atom->nlocal+atom->nghost); NeighList *list = neighbor->lists[irequest]; neighbor->build_one(irequest); // allocate and initialize deletion list // must be after exchange potentially changes nlocal int nlocal = atom->nlocal; memory->create(dlist,nlocal,"delete_atoms:dlist"); for (int i = 0; i < nlocal; i++) dlist[i] = 0; // double loop over owned atoms and their full neighbor list // at end of loop, there are no more overlaps // only ever delete owned atom I, never J even if owned int *tag = atom->tag; int *mask = atom->mask; double **x = atom->x; int nall = atom->nlocal + atom->nghost; double *special_coul = force->special_coul; double *special_lj = force->special_lj; int i,j,ii,jj,inum,jnum; double xtmp,ytmp,ztmp,delx,dely,delz,rsq; int *ilist,*jlist,*numneigh,**firstneigh; + double factor_lj,factor_coul; 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]; 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 weighting factors are 0, skip this pair + // 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 (j >= nall) { - if (special_coul[j/nall] == 0.0 && special_lj[j/nall] == 0.0) continue; - j %= nall; - } + if (factor_lj == 0.0 && factor_coul == 0.0) continue; // only consider deletion if I,J distance < cutoff 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) continue; // only consider deletion if I,J are in groups 1,2 respectively // true whether J is owned or ghost atom if (!(mask[i] & group1bit)) continue; if (!(mask[j] & group2bit)) continue; // J is owned atom: // delete atom I if atom J has not already been deleted // J is ghost atom: // delete atom I if J,I is not a candidate deletion pair // due to being in groups 1,2 respectively // if they are candidate pair, then either: // another proc owns J and could delete J // J is a ghost of another of my owned atoms, and I could delete J // test on tags of I,J insures that only I or J is deleted if (j < nlocal) { if (dlist[j]) continue; } else if ((mask[i] & group2bit) && (mask[j] & group1bit)) { if (tag[i] > tag[j]) continue; } dlist[i] = 1; break; } } } /* ---------------------------------------------------------------------- create porosity by deleting atoms in a specified region ------------------------------------------------------------------------- */ void DeleteAtoms::delete_porosity(int narg, char **arg) { if (narg < 4) error->all("Illegal delete_atoms command"); int iregion = domain->find_region(arg[1]); if (iregion == -1) error->all("Could not find delete_atoms region ID"); double porosity_fraction = atof(arg[2]); int seed = atoi(arg[3]); options(narg-4,&arg[4]); RanMars *random = new RanMars(lmp,seed + comm->me); // allocate and initialize deletion list int nlocal = atom->nlocal; memory->create(dlist,nlocal,"delete_atoms:dlist"); for (int i = 0; i < nlocal; i++) dlist[i] = 0; double **x = atom->x; for (int i = 0; i < nlocal; i++) if (domain->regions[iregion]->match(x[i][0],x[i][1],x[i][2])) if (random->uniform() <= porosity_fraction) dlist[i] = 1; } /* ---------------------------------------------------------------------- process command options ------------------------------------------------------------------------- */ void DeleteAtoms::options(int narg, char **arg) { compress_flag = 1; int iarg = 0; while (iarg < narg) { if (strcmp(arg[iarg],"compress") == 0) { if (iarg+2 > narg) error->all("Illegal delete_bonds command"); if (strcmp(arg[iarg+1],"yes") == 0) compress_flag = 1; else if (strcmp(arg[iarg+1],"no") == 0) compress_flag = 0; else error->all("Illegal delete_bonds command"); iarg += 2; } else error->all("Illegal delete_bonds command"); } } diff --git a/src/delete_atoms.h b/src/delete_atoms.h index e941728fe..840c0d65d 100644 --- a/src/delete_atoms.h +++ b/src/delete_atoms.h @@ -1,46 +1,50 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #ifdef COMMAND_CLASS CommandStyle(delete_atoms,DeleteAtoms) #else #ifndef LMP_DELETE_ATOMS_H #define LMP_DELETE_ATOMS_H #include "pointers.h" namespace LAMMPS_NS { class DeleteAtoms : protected Pointers { public: DeleteAtoms(class LAMMPS *); void command(int, char **); private: int *dlist; int compress_flag; void delete_group(int, char **); void delete_region(int, char **); void delete_overlap(int, char **); void delete_porosity(int, char **); void options(int, char **); + + inline int sbmask(int j) { + return j >> SBBITS & 3; + } }; } #endif #endif diff --git a/src/fix_orient_fcc.cpp b/src/fix_orient_fcc.cpp index dfef553b0..663061694 100644 --- a/src/fix_orient_fcc.cpp +++ b/src/fix_orient_fcc.cpp @@ -1,592 +1,593 @@ /* ---------------------------------------------------------------------- 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: Koenraad Janssens and David Olmsted (SNL) ------------------------------------------------------------------------- */ #include "math.h" #include "string.h" #include "stdlib.h" #include "mpi.h" #include "fix_orient_fcc.h" #include "atom.h" #include "update.h" #include "respa.h" #include "neighbor.h" #include "neigh_list.h" #include "neigh_request.h" #include "comm.h" #include "output.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define BIG 1000000000 #define MIN(A,B) ((A) < (B)) ? (A) : (B) #define MAX(A,B) ((A) > (B)) ? (A) : (B) /* ---------------------------------------------------------------------- */ FixOrientFCC::FixOrientFCC(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg) { MPI_Comm_rank(world,&me); if (narg != 11) error->all("Illegal fix orient/fcc command"); scalar_flag = 1; global_freq = 1; extscalar = 1; peratom_flag = 1; size_peratom_cols = 2; peratom_freq = 1; nstats = atoi(arg[3]); direction_of_motion = atoi(arg[4]); a = atof(arg[5]); Vxi = atof(arg[6]); uxif_low = atof(arg[7]); uxif_high = atof(arg[8]); if (direction_of_motion == 0) { int n = strlen(arg[9]) + 1; chifilename = new char[n]; strcpy(chifilename,arg[9]); n = strlen(arg[10]) + 1; xifilename = new char[n]; strcpy(xifilename,arg[10]); } else if (direction_of_motion == 1) { int n = strlen(arg[9]) + 1; xifilename = new char[n]; strcpy(xifilename,arg[9]); n = strlen(arg[10]) + 1; chifilename = new char[n]; strcpy(chifilename,arg[10]); } else error->all("Illegal fix orient/fcc command"); // initializations PI = 4.0*atan(1.0); half_fcc_nn = 6; use_xismooth = false; double xicutoff = 1.57; xicutoffsq = xicutoff * xicutoff; cutsq = 0.5 * a*a*xicutoffsq; nmax = 0; // read xi and chi reference orientations from files if (me == 0) { char line[512]; char *result; int count; FILE *infile = fopen(xifilename,"r"); if (infile == NULL) error->one("Fix orient/fcc file open failed"); for (int i = 0; i < 6; i++) { result = fgets(line,512,infile); if (!result) error->one("Fix orient/fcc file read failed"); count = sscanf(line,"%lg %lg %lg",&Rxi[i][0],&Rxi[i][1],&Rxi[i][2]); if (count != 3) error->one("Fix orient/fcc file read failed"); } fclose(infile); infile = fopen(chifilename,"r"); if (infile == NULL) error->one("Fix orient/fcc file open failed"); for (int i = 0; i < 6; i++) { result = fgets(line,512,infile); if (!result) error->one("Fix orient/fcc file read failed"); count = sscanf(line,"%lg %lg %lg",&Rchi[i][0],&Rchi[i][1],&Rchi[i][2]); if (count != 3) error->one("Fix orient/fcc file read failed"); } fclose(infile); } MPI_Bcast(&Rxi[0][0],18,MPI_DOUBLE,0,world); MPI_Bcast(&Rchi[0][0],18,MPI_DOUBLE,0,world); // make copy of the reference vectors for (int i = 0; i < 6; i++) for (int j = 0; j < 3; j++) { half_xi_chi_vec[0][i][j] = Rxi[i][j]; half_xi_chi_vec[1][i][j] = Rchi[i][j]; } // compute xiid,xi0,xi1 for all 12 neighbors // xi is the favored crystal // want order parameter when actual is Rchi double xi_sq,dxi[3],rchi[3]; xiid = 0.0; for (int i = 0; i < 6; i++) { rchi[0] = Rchi[i][0]; rchi[1] = Rchi[i][1]; rchi[2] = Rchi[i][2]; find_best_ref(rchi,0,xi_sq,dxi); xiid += sqrt(xi_sq); for (int j = 0; j < 3; j++) rchi[j] = -rchi[j]; find_best_ref(rchi,0,xi_sq,dxi); xiid += sqrt(xi_sq); } xiid /= 12.0; xi0 = uxif_low * xiid; xi1 = uxif_high * xiid; // set comm size needed by this Fix // NOTE: doesn't seem that use_xismooth is ever true if (use_xismooth) comm_forward = 62; else comm_forward = 50; added_energy = 0.0; nmax = atom->nmax; nbr = (Nbr *) memory->smalloc(nmax*sizeof(Nbr),"orient/fcc:nbr"); memory->create(order,nmax,2,"orient/fcc:order"); array_atom = order; // zero the array since a variable may access it before first run int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) order[i][0] = order[i][1] = 0.0; } /* ---------------------------------------------------------------------- */ FixOrientFCC::~FixOrientFCC() { delete [] xifilename; delete [] chifilename; memory->sfree(nbr); memory->destroy(order); } /* ---------------------------------------------------------------------- */ int FixOrientFCC::setmask() { int mask = 0; mask |= POST_FORCE; mask |= THERMO_ENERGY; mask |= POST_FORCE_RESPA; return mask; } /* ---------------------------------------------------------------------- */ void FixOrientFCC::init() { if (strcmp(update->integrate_style,"respa") == 0) nlevels_respa = ((Respa *) update->integrate)->nlevels; // need a full neighbor list, built whenever re-neighboring occurs int irequest = neighbor->request((void *) this); neighbor->requests[irequest]->pair = 0; neighbor->requests[irequest]->fix = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->full = 1; } /* ---------------------------------------------------------------------- */ void FixOrientFCC::init_list(int id, NeighList *ptr) { list = ptr; } /* ---------------------------------------------------------------------- */ void FixOrientFCC::setup(int vflag) { if (strcmp(update->integrate_style,"verlet") == 0) post_force(vflag); else { ((Respa *) update->integrate)->copy_flevel_f(nlevels_respa-1); post_force_respa(vflag,nlevels_respa-1,0); ((Respa *) update->integrate)->copy_f_flevel(nlevels_respa-1); } } /* ---------------------------------------------------------------------- */ void FixOrientFCC::post_force(int vflag) { int i,j,k,ii,jj,inum,jnum,m,n,nn,nsort,id_self; int *ilist,*jlist,*numneigh,**firstneigh; double edelta,omega; double dx,dy,dz,rsq,xismooth,xi_sq,duxi,duxi_other; double dxi[3]; double *dxiptr; bool found_myself; // set local ptrs double **x = atom->x; double **f = atom->f; int *mask = atom->mask; int *tag = atom->tag; int nlocal = atom->nlocal; int nall = atom->nlocal + atom->nghost; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // insure nbr and order data structures are adequate size if (nall > nmax) { nmax = nall; memory->destroy(nbr); memory->destroy(order); nbr = (Nbr *) memory->smalloc(nmax*sizeof(Nbr),"orient/fcc:nbr"); memory->create(order,nmax,2,"orient/fcc:order"); array_atom = order; } // loop over owned atoms and build Nbr data structure of neighbors // use full neighbor list added_energy = 0.0; int count = 0; int mincount = BIG; int maxcount = 0; for (ii = 0; ii < inum; ii++) { i = ilist[ii]; jlist = firstneigh[i]; jnum = numneigh[i]; if (jnum < mincount) mincount = jnum; if (jnum > maxcount) { if (maxcount) delete [] sort; sort = new Sort[jnum]; maxcount = jnum; } // loop over all neighbors of atom i // for those within cutsq, build sort data structure // store local id, rsq, delta vector, xismooth (if included) nsort = 0; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; + j &= NEIGHMASK; count++; dx = x[i][0] - x[j][0]; dy = x[i][1] - x[j][1]; dz = x[i][2] - x[j][2]; rsq = dx*dx + dy*dy + dz*dz; if (rsq < cutsq) { sort[nsort].id = j; sort[nsort].rsq = rsq; sort[nsort].delta[0] = dx; sort[nsort].delta[1] = dy; sort[nsort].delta[2] = dz; if (use_xismooth) { xismooth = (xicutoffsq - 2.0*rsq/(a*a)) / (xicutoffsq - 1.0); sort[nsort].xismooth = 1.0 - fabs(1.0-xismooth); } nsort++; } } // sort neighbors by rsq distance // no need to sort if nsort <= 12 if (nsort > 12) qsort(sort,nsort,sizeof(Sort),compare); // copy up to 12 nearest neighbors into nbr data structure // operate on delta vector via find_best_ref() to compute dxi n = MIN(12,nsort); nbr[i].n = n; if (n == 0) continue; double xi_total = 0.0; for (j = 0; j < n; j++) { find_best_ref(sort[j].delta,0,xi_sq,dxi); xi_total += sqrt(xi_sq); nbr[i].id[j] = sort[j].id; nbr[i].dxi[j][0] = dxi[0]/n; nbr[i].dxi[j][1] = dxi[1]/n; nbr[i].dxi[j][2] = dxi[2]/n; if (use_xismooth) nbr[i].xismooth[j] = sort[j].xismooth; } xi_total /= n; order[i][0] = xi_total; // compute potential derivative to xi if (xi_total < xi0) { nbr[i].duxi = 0.0; edelta = 0.0; order[i][1] = 0.0; } else if (xi_total > xi1) { nbr[i].duxi = 0.0; edelta = Vxi; order[i][1] = 1.0; } else { omega = (0.5*PI)*(xi_total-xi0) / (xi1-xi0); nbr[i].duxi = PI*Vxi*sin(2.0*omega) / (2.0*(xi1-xi0)); edelta = Vxi*(1 - cos(2.0*omega)) / 2.0; order[i][1] = omega / (0.5*PI); } added_energy += edelta; } if (maxcount) delete [] sort; // communicate to acquire nbr data for ghost atoms comm->forward_comm_fix(this); // compute grain boundary force on each owned atom // skip atoms not in group for (ii = 0; ii < inum; ii++) { i = ilist[ii]; if (!(mask[i] & groupbit)) continue; n = nbr[i].n; duxi = nbr[i].duxi; for (j = 0; j < n; j++) { dxiptr = &nbr[i].dxi[j][0]; if (use_xismooth) { xismooth = nbr[i].xismooth[j]; f[i][0] += duxi * dxiptr[0] * xismooth; f[i][1] += duxi * dxiptr[1] * xismooth; f[i][2] += duxi * dxiptr[2] * xismooth; } else { f[i][0] += duxi * dxiptr[0]; f[i][1] += duxi * dxiptr[1]; f[i][2] += duxi * dxiptr[2]; } // m = local index of neighbor // id_self = ID for atom I in atom M's neighbor list // if M is local atom, id_self will be local ID of atom I // if M is ghost atom, id_self will be global ID of atom I m = nbr[i].id[j]; if (m < nlocal) id_self = i; else id_self = tag[i]; found_myself = false; nn = nbr[m].n; for (k = 0; k < nn; k++) { if (id_self == nbr[m].id[k]) { if (found_myself) error->one("Fix orient/fcc found self twice"); found_myself = true; duxi_other = nbr[m].duxi; dxiptr = &nbr[m].dxi[k][0]; if (use_xismooth) { xismooth = nbr[m].xismooth[k]; f[i][0] -= duxi_other * dxiptr[0] * xismooth; f[i][1] -= duxi_other * dxiptr[1] * xismooth; f[i][2] -= duxi_other * dxiptr[2] * xismooth; } else { f[i][0] -= duxi_other * dxiptr[0]; f[i][1] -= duxi_other * dxiptr[1]; f[i][2] -= duxi_other * dxiptr[2]; } } } } } // print statistics every nstats timesteps if (nstats && update->ntimestep % nstats == 0) { int total; MPI_Allreduce(&count,&total,1,MPI_INT,MPI_SUM,world); double ave = total/atom->natoms; int min,max; MPI_Allreduce(&mincount,&min,1,MPI_INT,MPI_MIN,world); MPI_Allreduce(&maxcount,&max,1,MPI_INT,MPI_MAX,world); if (me == 0) { if (screen) fprintf(screen, "orient step " BIGINT_FORMAT ": " BIGINT_FORMAT " atoms have %d neighbors\n", update->ntimestep,atom->natoms,total); if (logfile) fprintf(logfile, "orient step " BIGINT_FORMAT ": " BIGINT_FORMAT " atoms have %d neighbors\n", update->ntimestep,atom->natoms,total); if (screen) fprintf(screen," neighs: min = %d, max = %d, ave = %g\n", min,max,ave); if (logfile) fprintf(logfile," neighs: min = %d, max = %d, ave = %g\n", min,max,ave); } } } /* ---------------------------------------------------------------------- */ void FixOrientFCC::post_force_respa(int vflag, int ilevel, int iloop) { if (ilevel == nlevels_respa-1) post_force(vflag); } /* ---------------------------------------------------------------------- */ double FixOrientFCC::compute_scalar() { double added_energy_total; MPI_Allreduce(&added_energy,&added_energy_total,1,MPI_DOUBLE,MPI_SUM,world); return added_energy_total; } /* ---------------------------------------------------------------------- */ int FixOrientFCC::pack_comm(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,k,id,num; int *tag = atom->tag; int nlocal = atom->nlocal; int m = 0; for (i = 0; i < n; i++) { k = list[i]; num = nbr[k].n; buf[m++] = num; buf[m++] = nbr[k].duxi; for (j = 0; j < num; j++) { if (use_xismooth) buf[m++] = nbr[m].xismooth[j]; buf[m++] = nbr[k].dxi[j][0]; buf[m++] = nbr[k].dxi[j][1]; buf[m++] = nbr[k].dxi[j][2]; // id stored in buf needs to be global ID // if k is a local atom, it stores local IDs, so convert to global // if k is a ghost atom (already comm'd), its IDs are already global id = nbr[k].id[j]; if (k < nlocal) id = tag[id]; buf[m++] = id; } m += (12-num) * 3; if (use_xismooth) m += 12-num; } if (use_xismooth) return 62; return 50; } /* ---------------------------------------------------------------------- */ void FixOrientFCC::unpack_comm(int n, int first, double *buf) { int i,j,num; int last = first + n; int m = 0; for (i = first; i < last; i++) { nbr[i].n = num = static_cast (buf[m++]); nbr[i].duxi = buf[m++]; for (j = 0; j < num; j++) { if (use_xismooth) nbr[i].xismooth[j] = buf[m++]; nbr[i].dxi[j][0] = buf[m++]; nbr[i].dxi[j][1] = buf[m++]; nbr[i].dxi[j][2] = buf[m++]; nbr[i].id[j] = static_cast (buf[m++]); } m += (12-num) * 3; if (use_xismooth) m += 12-num; } } /* ---------------------------------------------------------------------- */ void FixOrientFCC::find_best_ref(double *displs, int which_crystal, double &xi_sq, double *dxi) { int i; double dot,tmp; double best_dot = -1.0; // best is biggest (smallest angle) int best_i = -1; int best_sign = 0; for (i = 0; i < half_fcc_nn; i++) { dot = displs[0] * half_xi_chi_vec[which_crystal][i][0] + displs[1] * half_xi_chi_vec[which_crystal][i][1] + displs[2] * half_xi_chi_vec[which_crystal][i][2]; if (fabs(dot) > best_dot) { best_dot = fabs(dot); best_i = i; if (dot < 0.0) best_sign = -1; else best_sign = 1; } } xi_sq = 0.0; for (i = 0; i < 3; i++) { tmp = displs[i] - best_sign * half_xi_chi_vec[which_crystal][best_i][i]; xi_sq += tmp*tmp; } if (xi_sq > 0.0) { double xi = sqrt(xi_sq); for (i = 0; i < 3; i++) dxi[i] = (best_sign * half_xi_chi_vec[which_crystal][best_i][i] - displs[i]) / xi; } else dxi[0] = dxi[1] = dxi[2] = 0.0; } /* ---------------------------------------------------------------------- compare two neighbors I and J in sort data structure called via qsort in post_force() method is a static method so can't access sort data structure directly return -1 if I < J, 0 if I = J, 1 if I > J do comparison based on rsq distance ------------------------------------------------------------------------- */ int FixOrientFCC::compare(const void *pi, const void *pj) { FixOrientFCC::Sort *ineigh = (FixOrientFCC::Sort *) pi; FixOrientFCC::Sort *jneigh = (FixOrientFCC::Sort *) pj; if (ineigh->rsq < jneigh->rsq) return -1; else if (ineigh->rsq > jneigh->rsq) return 1; return 0; } /* ---------------------------------------------------------------------- memory usage of local atom-based arrays ------------------------------------------------------------------------- */ double FixOrientFCC::memory_usage() { double bytes = nmax * sizeof(Nbr); bytes += 2*nmax * sizeof(double); return bytes; } diff --git a/src/fix_shear_history.cpp b/src/fix_shear_history.cpp index 328756e49..0740a2f25 100644 --- a/src/fix_shear_history.cpp +++ b/src/fix_shear_history.cpp @@ -1,310 +1,311 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "string.h" #include "stdio.h" #include "fix_shear_history.h" #include "atom.h" #include "neighbor.h" #include "neigh_list.h" #include "force.h" #include "pair.h" #include "update.h" #include "modify.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define MAXTOUCH 15 /* ---------------------------------------------------------------------- */ FixShearHistory::FixShearHistory(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg) { // set time_depend so that history will be preserved correctly // across multiple runs via laststep setting in granular pair styles restart_peratom = 1; create_attribute = 1; time_depend = 1; // perform initial allocation of atom-based arrays // register with atom class npartner = NULL; partner = NULL; shearpartner = NULL; grow_arrays(atom->nmax); atom->add_callback(0); atom->add_callback(1); // initialize npartner to 0 so neighbor list creation is OK the 1st time int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) npartner[i] = 0; } /* ---------------------------------------------------------------------- */ FixShearHistory::~FixShearHistory() { // unregister this fix so atom class doesn't invoke it any more atom->delete_callback(id,0); atom->delete_callback(id,1); // delete locally stored arrays memory->destroy(npartner); memory->destroy(partner); memory->destroy(shearpartner); } /* ---------------------------------------------------------------------- */ int FixShearHistory::setmask() { int mask = 0; mask |= PRE_EXCHANGE; return mask; } /* ---------------------------------------------------------------------- */ void FixShearHistory::init() { if (atom->tag_enable == 0) error->all("Pair style granular with history requires atoms have IDs"); } /* ---------------------------------------------------------------------- */ void FixShearHistory::setup_pre_exchange() { pre_exchange(); } /* ---------------------------------------------------------------------- copy shear partner info from neighbor lists to atom arrays so can be exchanged with atoms ------------------------------------------------------------------------- */ void FixShearHistory::pre_exchange() { int i,j,ii,jj,m,inum,jnum; int *ilist,*jlist,*numneigh,**firstneigh; int *touch,**firsttouch; double *shear,*allshear,**firstshear; // zero npartners for all current atoms int nlocal = atom->nlocal; for (i = 0; i < nlocal; i++) npartner[i] = 0; // copy shear info from neighbor list atoms to atom arrays int *tag = atom->tag; NeighList *list = pair->list; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; firsttouch = list->listgranhistory->firstneigh; firstshear = list->listgranhistory->firstdouble; for (ii = 0; ii < inum; ii++) { i = ilist[ii]; jlist = firstneigh[i]; allshear = firstshear[i]; jnum = numneigh[i]; touch = firsttouch[i]; for (jj = 0; jj < jnum; jj++) { if (touch[jj]) { shear = &allshear[3*jj]; j = jlist[jj]; + j &= NEIGHMASK; if (npartner[i] < MAXTOUCH) { m = npartner[i]; partner[i][m] = tag[j]; shearpartner[i][m][0] = shear[0]; shearpartner[i][m][1] = shear[1]; shearpartner[i][m][2] = shear[2]; } npartner[i]++; if (j < nlocal) { if (npartner[j] < MAXTOUCH) { m = npartner[j]; partner[j][m] = tag[i]; shearpartner[j][m][0] = -shear[0]; shearpartner[j][m][1] = -shear[1]; shearpartner[j][m][2] = -shear[2]; } npartner[j]++; } } } } // test for too many touching neighbors int flag = 0; for (i = 0; i < nlocal; i++) if (npartner[i] >= MAXTOUCH) flag = 1; int flag_all; MPI_Allreduce(&flag,&flag_all,1,MPI_INT,MPI_SUM,world); if (flag_all) error->all("Too many touching neighbors - boost MAXTOUCH"); } /* ---------------------------------------------------------------------- memory usage of local atom-based arrays ------------------------------------------------------------------------- */ double FixShearHistory::memory_usage() { int nmax = atom->nmax; double bytes = nmax * sizeof(int); bytes += nmax*MAXTOUCH * sizeof(int); bytes += nmax*MAXTOUCH*3 * sizeof(double); return bytes; } /* ---------------------------------------------------------------------- allocate local atom-based arrays ------------------------------------------------------------------------- */ void FixShearHistory::grow_arrays(int nmax) { memory->grow(npartner,nmax,"shear_history:npartner"); memory->grow(partner,nmax,MAXTOUCH,"shear_history:partner"); memory->grow(shearpartner,nmax,MAXTOUCH,3,"shear_history:shearpartner"); } /* ---------------------------------------------------------------------- copy values within local atom-based arrays ------------------------------------------------------------------------- */ void FixShearHistory::copy_arrays(int i, int j) { npartner[j] = npartner[i]; for (int m = 0; m < npartner[j]; m++) { partner[j][m] = partner[i][m]; shearpartner[j][m][0] = shearpartner[i][m][0]; shearpartner[j][m][1] = shearpartner[i][m][1]; shearpartner[j][m][2] = shearpartner[i][m][2]; } } /* ---------------------------------------------------------------------- initialize one atom's array values, called when atom is created ------------------------------------------------------------------------- */ void FixShearHistory::set_arrays(int i) { npartner[i] = 0; } /* ---------------------------------------------------------------------- pack values in local atom-based arrays for exchange with another proc ------------------------------------------------------------------------- */ int FixShearHistory::pack_exchange(int i, double *buf) { int m = 0; buf[m++] = npartner[i]; for (int n = 0; n < npartner[i]; n++) { buf[m++] = partner[i][n]; buf[m++] = shearpartner[i][n][0]; buf[m++] = shearpartner[i][n][1]; buf[m++] = shearpartner[i][n][2]; } return m; } /* ---------------------------------------------------------------------- unpack values in local atom-based arrays from exchange with another proc ------------------------------------------------------------------------- */ int FixShearHistory::unpack_exchange(int nlocal, double *buf) { int m = 0; npartner[nlocal] = static_cast (buf[m++]); for (int n = 0; n < npartner[nlocal]; n++) { partner[nlocal][n] = static_cast (buf[m++]); shearpartner[nlocal][n][0] = buf[m++]; shearpartner[nlocal][n][1] = buf[m++]; shearpartner[nlocal][n][2] = buf[m++]; } return m; } /* ---------------------------------------------------------------------- pack values in local atom-based arrays for restart file ------------------------------------------------------------------------- */ int FixShearHistory::pack_restart(int i, double *buf) { int m = 0; buf[m++] = 4*npartner[i] + 2; buf[m++] = npartner[i]; for (int n = 0; n < npartner[i]; n++) { buf[m++] = partner[i][n]; buf[m++] = shearpartner[i][n][0]; buf[m++] = shearpartner[i][n][1]; buf[m++] = shearpartner[i][n][2]; } return m; } /* ---------------------------------------------------------------------- unpack values from atom->extra array to restart the fix ------------------------------------------------------------------------- */ void FixShearHistory::unpack_restart(int nlocal, int nth) { double **extra = atom->extra; // skip to Nth set of extra values int m = 0; for (int i = 0; i < nth; i++) m += static_cast (extra[nlocal][m]); m++; npartner[nlocal] = static_cast (extra[nlocal][m++]); for (int n = 0; n < npartner[nlocal]; n++) { partner[nlocal][n] = static_cast (extra[nlocal][m++]); shearpartner[nlocal][n][0] = extra[nlocal][m++]; shearpartner[nlocal][n][1] = extra[nlocal][m++]; shearpartner[nlocal][n][2] = extra[nlocal][m++]; } } /* ---------------------------------------------------------------------- maxsize of any atom's restart data ------------------------------------------------------------------------- */ int FixShearHistory::maxsize_restart() { return 4*MAXTOUCH + 2; } /* ---------------------------------------------------------------------- size of atom nlocal's restart data ------------------------------------------------------------------------- */ int FixShearHistory::size_restart(int nlocal) { return 4*npartner[nlocal] + 2; } diff --git a/src/force.cpp b/src/force.cpp index a53ac9e25..23a4707d5 100644 --- a/src/force.cpp +++ b/src/force.cpp @@ -1,537 +1,538 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "lmptype.h" #include "stdlib.h" #include "string.h" #include "ctype.h" #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 "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 MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) /* ---------------------------------------------------------------------- */ 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); } /* ---------------------------------------------------------------------- */ 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; } /* ---------------------------------------------------------------------- */ void Force::init() { qqrd2e = qqr2e/dielectric; comm->maxforward_pair = comm->maxreverse_pair = 0; 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(); } /* ---------------------------------------------------------------------- create a pair style, called from input script or restart file ------------------------------------------------------------------------- */ void Force::create_pair(const char *style) { delete [] pair_style; if (pair) delete pair; pair = new_pair(style); int n = strlen(style) + 1; pair_style = new char[n]; strcpy(pair_style,style); } /* ---------------------------------------------------------------------- generate a pair class ------------------------------------------------------------------------- */ Pair *Force::new_pair(const char *style) { if (strcmp(style,"none") == 0) return NULL; #define PAIR_CLASS #define PairStyle(key,Class) \ else if (strcmp(style,#key) == 0) return new Class(lmp); #include "style_pair.h" #undef PAIR_CLASS else error->all("Invalid pair style"); return NULL; } /* ---------------------------------------------------------------------- return ptr to current pair class or hybrid sub-class if exact, then style name must be exact match to word if not exact, style name must contain word return NULL if no match return NULL if not exact and multiple hybrid sub-styles match ------------------------------------------------------------------------- */ Pair *Force::pair_match(const char *word, int exact) { int iwhich,count; if (exact && strcmp(pair_style,word) == 0) return pair; else if (!exact && strstr(pair_style,word)) return pair; else if (strcmp(pair_style,"hybrid") == 0) { PairHybrid *hybrid = (PairHybrid *) pair; count = 0; for (int i = 0; i < hybrid->nstyles; i++) { if (exact && strcmp(hybrid->keywords[i],word) == 0) return hybrid->styles[i]; if (!exact && strstr(hybrid->keywords[i],word)) { iwhich = i; count++; } } if (!exact && count == 1) return hybrid->styles[iwhich]; } else if (strcmp(pair_style,"hybrid/overlay") == 0) { PairHybridOverlay *hybrid = (PairHybridOverlay *) pair; count = 0; for (int i = 0; i < hybrid->nstyles; i++) { if (exact && strcmp(hybrid->keywords[i],word) == 0) return hybrid->styles[i]; else if (!exact && strstr(hybrid->keywords[i],word)) { iwhich = i; count++; } } if (!exact && count == 1) return hybrid->styles[iwhich]; } return NULL; } /* ---------------------------------------------------------------------- create a bond style, called from input script or restart file ------------------------------------------------------------------------- */ void Force::create_bond(const char *style) { delete [] bond_style; if (bond) delete bond; bond = new_bond(style); int n = strlen(style) + 1; bond_style = new char[n]; strcpy(bond_style,style); } /* ---------------------------------------------------------------------- generate a bond class ------------------------------------------------------------------------- */ Bond *Force::new_bond(const char *style) { if (strcmp(style,"none") == 0) return NULL; #define BOND_CLASS #define BondStyle(key,Class) \ else if (strcmp(style,#key) == 0) return new Class(lmp); #include "style_bond.h" #undef BOND_CLASS else error->all("Invalid bond style"); return NULL; } /* ---------------------------------------------------------------------- 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) { delete [] angle_style; if (angle) delete angle; angle = new_angle(style); int n = strlen(style) + 1; angle_style = new char[n]; strcpy(angle_style,style); } /* ---------------------------------------------------------------------- generate an angle class ------------------------------------------------------------------------- */ Angle *Force::new_angle(const char *style) { if (strcmp(style,"none") == 0) return NULL; #define ANGLE_CLASS #define AngleStyle(key,Class) \ else if (strcmp(style,#key) == 0) return new Class(lmp); #include "style_angle.h" #undef ANGLE_CLASS else error->all("Invalid angle style"); return NULL; } /* ---------------------------------------------------------------------- create a dihedral style, called from input script or restart file ------------------------------------------------------------------------- */ void Force::create_dihedral(const char *style) { delete [] dihedral_style; if (dihedral) delete dihedral; dihedral = new_dihedral(style); int n = strlen(style) + 1; dihedral_style = new char[n]; strcpy(dihedral_style,style); } /* ---------------------------------------------------------------------- generate a dihedral class ------------------------------------------------------------------------- */ Dihedral *Force::new_dihedral(const char *style) { if (strcmp(style,"none") == 0) return NULL; #define DIHEDRAL_CLASS #define DihedralStyle(key,Class) \ else if (strcmp(style,#key) == 0) return new Class(lmp); #include "style_dihedral.h" #undef DIHEDRAL_CLASS else error->all("Invalid dihedral style"); return NULL; } /* ---------------------------------------------------------------------- create an improper style, called from input script or restart file ------------------------------------------------------------------------- */ void Force::create_improper(const char *style) { delete [] improper_style; if (improper) delete improper; improper = new_improper(style); int n = strlen(style) + 1; improper_style = new char[n]; strcpy(improper_style,style); } /* ---------------------------------------------------------------------- generate a improper class ------------------------------------------------------------------------- */ Improper *Force::new_improper(const char *style) { if (strcmp(style,"none") == 0) return NULL; #define IMPROPER_CLASS #define ImproperStyle(key,Class) \ else if (strcmp(style,#key) == 0) return new Class(lmp); #include "style_improper.h" #undef IMPROPER_CLASS else error->all("Invalid improper style"); return NULL; } /* ---------------------------------------------------------------------- new kspace style ------------------------------------------------------------------------- */ void Force::create_kspace(int narg, char **arg) { delete [] kspace_style; if (kspace) delete kspace; if (strcmp(arg[0],"none") == 0) kspace = NULL; #define KSPACE_CLASS #define KSpaceStyle(key,Class) \ else if (strcmp(arg[0],#key) == 0) kspace = new Class(lmp,narg-1,&arg[1]); #include "style_kspace.h" #undef KSPACE_CLASS else error->all("Invalid kspace style"); int n = strlen(arg[0]) + 1; kspace_style = new char[n]; strcpy(kspace_style,arg[0]); } /* ---------------------------------------------------------------------- set special bond values ------------------------------------------------------------------------- */ void Force::set_special(int narg, char **arg) { if (narg == 0) error->all("Illegal special_bonds command"); int iarg = 0; while (iarg < narg) { if (strcmp(arg[iarg],"amber") == 0) { if (iarg+1 > narg) error->all("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("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("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("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("Illegal special_bonds command"); special_lj[1] = special_coul[1] = atof(arg[iarg+1]); special_lj[2] = special_coul[2] = atof(arg[iarg+2]); special_lj[3] = special_coul[3] = atof(arg[iarg+3]); iarg += 4; } else if (strcmp(arg[iarg],"lj") == 0) { if (iarg+4 > narg) error->all("Illegal special_bonds command"); special_lj[1] = atof(arg[iarg+1]); special_lj[2] = atof(arg[iarg+2]); special_lj[3] = atof(arg[iarg+3]); iarg += 4; } else if (strcmp(arg[iarg],"coul") == 0) { if (iarg+4 > narg) error->all("Illegal special_bonds command"); special_coul[1] = atof(arg[iarg+1]); special_coul[2] = atof(arg[iarg+2]); special_coul[3] = atof(arg[iarg+3]); iarg += 4; } else if (strcmp(arg[iarg],"angle") == 0) { if (iarg+2 > narg) error->all("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("Illegal special_bonds command"); iarg += 2; } else if (strcmp(arg[iarg],"dihedral") == 0) { if (iarg+2 > narg) error->all("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("Illegal special_bonds command"); iarg += 2; } else if (strcmp(arg[iarg],"extra") == 0) { if (iarg+2 > narg) error->all("Illegal special_bonds command"); special_extra = atoi(arg[iarg+1]); iarg += 2; } else error->all("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("Illegal special_bonds command"); if (special_extra < 0) error->all("Illegal special_bonds command"); } /* ---------------------------------------------------------------------- compute bounds implied by numeric str with a possible wildcard asterik nmax = upper bound 5 possibilities: (1) i = i to i, (2) * = 1 to nmax, (3) i* = i to nmax, (4) *j = 1 to j, (5) i*j = i to j return nlo,nhi ------------------------------------------------------------------------- */ void Force::bounds(char *str, int nmax, int &nlo, int &nhi) { char *ptr = strchr(str,'*'); if (ptr == NULL) { nlo = MAX(atoi(str),1); nhi = MIN(atoi(str),nmax); } else if (strlen(str) == 1) { nlo = 1; nhi = nmax; } else if (ptr == str) { nlo = 1; nhi = MIN(atoi(ptr+1),nmax); } else if (strlen(ptr+1) == 0) { nlo = MAX(atoi(str),1); nhi = nmax; } else { nlo = MAX(atoi(str),1); nhi = MIN(atoi(ptr+1),nmax); } } /* ---------------------------------------------------------------------- read a floating point value from a string generate an error if not a legitimate floating point value called by force fields to check validity of their arguments ------------------------------------------------------------------------- */ double Force::numeric(char *str) { int n = strlen(str); 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("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 force fields to check validity of their arguments ------------------------------------------------------------------------- */ int Force::inumeric(char *str) { int n = strlen(str); for (int i = 0; i < n; i++) { if (isdigit(str[i]) || str[i] == '-' || str[i] == '+') continue; error->all("Expected integer parameter in input script or data file"); } return atoi(str); } /* ---------------------------------------------------------------------- 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/lmptype.h b/src/lmptype.h index a1f6662fe..3ce417c91 100644 --- a/src/lmptype.h +++ b/src/lmptype.h @@ -1,111 +1,117 @@ /* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ // define integer data types used by LAMMPS and associated size limits // smallint = variables for on-procesor system (nlocal, nmax, etc) // tagint = variables for atom IDs (tag) // bigint = variables for total system (natoms, ntimestep, etc) // smallint must be an int, as defined by C compiler // tagint can be 32-bit or 64-bit int, must be >= smallint // NOTE: 64-bit tagint is not yet supported // bigint can be 32-bit or 64-bit int, must be >= tagint // MPI_LMP_TAGINT = MPI data type corresponding to a tagint // MPI_LMP_BIGINT = MPI data type corresponding to a bigint // NOTE: if your machine/MPI does not support "long long" ints, // but only "long" ints, then you will need to change // MPI_LONG_LONG to MPI_LONG, and atoll to atol #ifndef LMP_LMPTYPE_H #define LMP_LMPTYPE_H #define __STDC_LIMIT_MACROS #define __STDC_FORMAT_MACROS #include "limits.h" #include "stdint.h" #include "inttypes.h" namespace LAMMPS_NS { +// reserve 2 hi bits in molecular system neigh list for special bonds flag +// max local + ghost atoms per processor = 2^30 - 1 + +#define SBBITS 30 +#define NEIGHMASK 0x3FFFFFFF + // default settings // 32-bit smallint and tagint, 64-bit bigint typedef int smallint; typedef int tagint; typedef int64_t bigint; #define MAXSMALLINT INT_MAX #define MAXTAGINT INT_MAX #define MAXBIGINT INT64_MAX #define MPI_LMP_TAGINT MPI_INT #define MPI_LMP_BIGINT MPI_LONG_LONG #define TAGINT_FORMAT "%d" #define BIGINT_FORMAT "%" PRId64 #define ATOTAGINT atoi #define ATOBIGINT atoll // for molecular problems that exceed 2 billion (2^31) atoms // 32-bit smallint, 64-bit tagint and bigint // NOTE: 64-bit tagint is not yet supported /* typedef int smallint; typedef int64_t tagint; typedef int64_t bigint; #define MAXSMALLINT INT_MAX #define MAXTAGINT INT64_MAX #define MAXBIGINT INT64_MAX #define MPI_LMP_TAGINT MPI_LONG_LONG #define MPI_LMP_BIGINT MPI_LONG_LONG #define TAGINT_FORMAT "%" PRId64 #define BIGINT_FORMAT "%" PRId64 #define ATOTAGINT atoll #define ATOBIGINT atoll */ // for machines that do not support 64-bit ints // 32-bit smallint and tagint and bigint /* typedef int smallint; typedef int tagint; typedef int bigint; #define MAXSMALLINT INT_MAX #define MAXTAGINT INT_MAX #define MAXBIGINT INT_MAX #define MPI_LMP_TAGINT MPI_INT #define MPI_LMP_BIGINT MPI_INT #define TAGINT_FORMAT "%d" #define BIGINT_FORMAT "%d" #define ATOTAGINT atoi #define ATOBIGINT atoi */ } #endif diff --git a/src/neigh_derive.cpp b/src/neigh_derive.cpp index c33fac9e6..c3d3eb024 100644 --- a/src/neigh_derive.cpp +++ b/src/neigh_derive.cpp @@ -1,507 +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. ------------------------------------------------------------------------- */ #include "neighbor.h" #include "neigh_list.h" #include "atom.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- build half list from full list pair stored once if i,j are both owned and i < j pair stored by me if j is ghost (also stored by proc owning j) works if full list is a skip list ------------------------------------------------------------------------- */ void Neighbor::half_from_full_no_newton(NeighList *list) { - int i,j,ii,jj,n,jnum; + int i,j,ii,jj,n,jnum,joriginal; int *neighptr,*jlist; int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; int **pages = list->pages; int *ilist_full = list->listfull->ilist; int *numneigh_full = list->listfull->numneigh; int **firstneigh_full = list->listfull->firstneigh; int inum_full = list->listfull->inum; int inum = 0; int npage = 0; int npnt = 0; // loop over atoms in full list for (ii = 0; ii < inum_full; ii++) { if (pgsize - npnt < oneatom) { npnt = 0; npage++; if (npage == list->maxpage) pages = list->add_pages(); } neighptr = &pages[npage][npnt]; n = 0; // loop over parent full list i = ilist_full[ii]; jlist = firstneigh_full[i]; jnum = numneigh_full[i]; for (jj = 0; jj < jnum; jj++) { - j = jlist[jj]; - if (j > i) neighptr[n++] = j; + joriginal = jlist[jj]; + j = joriginal & NEIGHMASK; + if (j > i) neighptr[n++] = joriginal; } ilist[inum++] = i; firstneigh[i] = neighptr; numneigh[i] = n; npnt += n; if (n > oneatom || npnt >= pgsize) error->one("Neighbor list overflow, boost neigh_modify one or page"); } list->inum = inum; } /* ---------------------------------------------------------------------- build half list from full list pair stored once if i,j are both owned and i < j if j is ghost, only store if j coords are "above and to the right" of i works if full list is a skip list ------------------------------------------------------------------------- */ void Neighbor::half_from_full_newton(NeighList *list) { int i,j,ii,jj,n,jnum,joriginal; int *neighptr,*jlist; double xtmp,ytmp,ztmp; double **x = atom->x; int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; int **pages = list->pages; int *ilist_full = list->listfull->ilist; int *numneigh_full = list->listfull->numneigh; int **firstneigh_full = list->listfull->firstneigh; int inum_full = list->listfull->inum; int inum = 0; int npage = 0; int npnt = 0; // loop over parent full list for (ii = 0; ii < inum_full; ii++) { if (pgsize - npnt < oneatom) { npnt = 0; npage++; if (npage == list->maxpage) pages = list->add_pages(); } neighptr = &pages[npage][npnt]; n = 0; i = ilist_full[ii]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; // loop over full neighbor list jlist = firstneigh_full[i]; jnum = numneigh_full[i]; for (jj = 0; jj < jnum; jj++) { - j = joriginal = jlist[jj]; + joriginal = jlist[jj]; + j = joriginal & NEIGHMASK; if (j < nlocal) { if (i > j) continue; } else { - if (j >= nall) j %= nall; if (x[j][2] < ztmp) continue; if (x[j][2] == ztmp) { if (x[j][1] < ytmp) continue; if (x[j][1] == ytmp && x[j][0] < xtmp) continue; } } neighptr[n++] = joriginal; } ilist[inum++] = i; firstneigh[i] = neighptr; numneigh[i] = n; npnt += n; if (n > oneatom || npnt >= pgsize) error->one("Neighbor list overflow, boost neigh_modify one or page"); } list->inum = inum; } /* ---------------------------------------------------------------------- build skip list for subset of types from parent list iskip and ijskip flag which atom types and type pairs to skip this is for half and full lists if ghostflag, also store neighbors of ghost atoms & set inum,gnum correctly ------------------------------------------------------------------------- */ void Neighbor::skip_from(NeighList *list) { int i,j,ii,jj,n,itype,jnum,joriginal; int *neighptr,*jlist; int *type = atom->type; int nlocal = atom->nlocal; - int nall = atom->nlocal + atom->nghost; int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; int **pages = list->pages; int *ilist_skip = list->listskip->ilist; int *numneigh_skip = list->listskip->numneigh; int **firstneigh_skip = list->listskip->firstneigh; int num_skip = list->listskip->inum; if (list->ghostflag) num_skip += list->listskip->gnum; int *iskip = list->iskip; int **ijskip = list->ijskip; int inum = 0; int npage = 0; int npnt = 0; // loop over atoms in other list // skip I atom entirely if iskip is set for type[I] // skip I,J pair if ijskip is set for type[I],type[J] for (ii = 0; ii < num_skip; ii++) { i = ilist_skip[ii]; itype = type[i]; if (iskip[itype]) continue; if (pgsize - npnt < oneatom) { npnt = 0; npage++; if (npage == list->maxpage) pages = list->add_pages(); } neighptr = &pages[npage][npnt]; n = 0; // loop over parent non-skip list jlist = firstneigh_skip[i]; jnum = numneigh_skip[i]; for (jj = 0; jj < jnum; jj++) { - j = joriginal = jlist[jj]; - if (j >= nall) j %= nall; + joriginal = jlist[jj]; + j = joriginal & NEIGHMASK; if (ijskip[itype][type[j]]) continue; neighptr[n++] = joriginal; } ilist[inum++] = i; firstneigh[i] = neighptr; numneigh[i] = n; npnt += n; if (n > oneatom || npnt >= pgsize) error->one("Neighbor list overflow, boost neigh_modify one or page"); } list->inum = inum; if (list->ghostflag) { int num = 0; for (i = 0; i < inum; i++) if (ilist[i] < nlocal) num++; else break; list->inum = num; list->gnum = inum - num; } } /* ---------------------------------------------------------------------- build skip list for subset of types from parent list iskip and ijskip flag which atom types and type pairs to skip this is for granular lists with history, copy the history values from parent ------------------------------------------------------------------------- */ void Neighbor::skip_from_granular(NeighList *list) { int i,j,ii,jj,n,nn,itype,jnum,joriginal; int *neighptr,*jlist,*touchptr,*touchptr_skip; double *shearptr,*shearptr_skip; int *type = atom->type; - int nall = atom->nlocal + atom->nghost; int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; int **pages = list->pages; int *ilist_skip = list->listskip->ilist; int *numneigh_skip = list->listskip->numneigh; int **firstneigh_skip = list->listskip->firstneigh; int **firsttouch_skip = list->listskip->listgranhistory->firstneigh; double **firstshear_skip = list->listskip->listgranhistory->firstdouble; int inum_skip = list->listskip->inum; int *iskip = list->iskip; int **ijskip = list->ijskip; NeighList *listgranhistory = list->listgranhistory; int **firsttouch = listgranhistory->firstneigh; double **firstshear = listgranhistory->firstdouble; int **pages_touch = listgranhistory->pages; double **pages_shear = listgranhistory->dpages; int inum = 0; int npage = 0; int npnt = 0; // loop over atoms in other list // skip I atom entirely if iskip is set for type[I] // skip I,J pair if ijskip is set for type[I],type[J] for (ii = 0; ii < inum_skip; ii++) { i = ilist_skip[ii]; itype = type[i]; if (iskip[itype]) continue; if (pgsize - npnt < oneatom) { npnt = 0; npage++; if (npage == list->maxpage) { pages = list->add_pages(); pages_touch = listgranhistory->add_pages(); pages_shear = listgranhistory->dpages; } } n = 0; neighptr = &pages[npage][npnt]; nn = 0; touchptr = &pages_touch[npage][npnt]; shearptr = &pages_shear[npage][3*npnt]; // loop over parent non-skip granular list and its history info touchptr_skip = firsttouch_skip[i]; shearptr_skip = firstshear_skip[i]; jlist = firstneigh_skip[i]; jnum = numneigh_skip[i]; for (jj = 0; jj < jnum; jj++) { - j = joriginal = jlist[jj]; - if (j >= nall) j %= nall; + joriginal = jlist[jj]; + j = joriginal & NEIGHMASK; if (ijskip[itype][type[j]]) continue; neighptr[n] = joriginal; touchptr[n++] = touchptr_skip[jj]; shearptr[nn++] = shearptr_skip[3*jj]; shearptr[nn++] = shearptr_skip[3*jj+1]; shearptr[nn++] = shearptr_skip[3*jj+2]; } ilist[inum++] = i; firstneigh[i] = neighptr; numneigh[i] = n; firsttouch[i] = touchptr; firstshear[i] = shearptr; npnt += n; if (n > oneatom || npnt >= pgsize) error->one("Neighbor list overflow, boost neigh_modify one or page"); } list->inum = inum; } /* ---------------------------------------------------------------------- build skip list for subset of types from parent list iskip and ijskip flag which atom types and type pairs to skip this is for respa lists, copy the inner/middle values from parent ------------------------------------------------------------------------- */ void Neighbor::skip_from_respa(NeighList *list) { int i,j,ii,jj,n,itype,jnum,joriginal,n_inner,n_middle; int *neighptr,*jlist,*neighptr_inner,*neighptr_middle; int *type = atom->type; - int nall = atom->nlocal + atom->nghost; int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; int **pages = list->pages; int *ilist_skip = list->listskip->ilist; int *numneigh_skip = list->listskip->numneigh; int **firstneigh_skip = list->listskip->firstneigh; int inum_skip = list->listskip->inum; int *iskip = list->iskip; int **ijskip = list->ijskip; NeighList *listinner = list->listinner; int *numneigh_inner = listinner->numneigh; int **firstneigh_inner = listinner->firstneigh; int **pages_inner = listinner->pages; int *numneigh_inner_skip = list->listskip->listinner->numneigh; int **firstneigh_inner_skip = list->listskip->listinner->firstneigh; NeighList *listmiddle; int *numneigh_middle,**firstneigh_middle,**pages_middle; int *numneigh_middle_skip,**firstneigh_middle_skip; int respamiddle = list->respamiddle; if (respamiddle) { listmiddle = list->listmiddle; numneigh_middle = listmiddle->numneigh; firstneigh_middle = listmiddle->firstneigh; pages_middle = listmiddle->pages; numneigh_middle_skip = list->listskip->listmiddle->numneigh; firstneigh_middle_skip = list->listskip->listmiddle->firstneigh; } int inum = 0; int npage = 0; int npnt = 0; int npage_inner = 0; int npnt_inner = 0; int npage_middle = 0; int npnt_middle = 0; // loop over atoms in other list // skip I atom entirely if iskip is set for type[I] // skip I,J pair if ijskip is set for type[I],type[J] for (ii = 0; ii < inum_skip; ii++) { i = ilist_skip[ii]; itype = type[i]; if (iskip[itype]) continue; if (pgsize - npnt < oneatom) { npnt = 0; npage++; if (npage == list->maxpage) pages = list->add_pages(); } neighptr = &pages[npage][npnt]; n = 0; if (pgsize - npnt_inner < oneatom) { npnt_inner = 0; npage_inner++; if (npage_inner == listinner->maxpage) pages_inner = listinner->add_pages(); } neighptr_inner = &pages_inner[npage_inner][npnt_inner]; n_inner = 0; if (respamiddle) { if (pgsize - npnt_middle < oneatom) { npnt_middle = 0; npage_middle++; if (npage_middle == listmiddle->maxpage) pages_middle = listmiddle->add_pages(); } neighptr_middle = &pages_middle[npage_middle][npnt_middle]; n_middle = 0; } // loop over parent outer rRESPA list jlist = firstneigh_skip[i]; jnum = numneigh_skip[i]; for (jj = 0; jj < jnum; jj++) { - j = joriginal = jlist[jj]; - if (j >= nall) j %= nall; + joriginal = jlist[jj]; + j = joriginal & NEIGHMASK; if (ijskip[itype][type[j]]) continue; neighptr[n++] = joriginal; } // loop over parent inner rRESPA list jlist = firstneigh_inner_skip[i]; jnum = numneigh_inner_skip[i]; for (jj = 0; jj < jnum; jj++) { - j = joriginal = jlist[jj]; - if (j >= nall) j %= nall; + joriginal = jlist[jj]; + j = joriginal & NEIGHMASK; if (ijskip[itype][type[j]]) continue; neighptr_inner[n_inner++] = joriginal; } // loop over parent middle rRESPA list if (respamiddle) { jlist = firstneigh_middle_skip[i]; jnum = numneigh_middle_skip[i]; for (jj = 0; jj < jnum; jj++) { - j = joriginal = jlist[jj]; - if (j >= nall) j %= nall; + joriginal = jlist[jj]; + j = joriginal & NEIGHMASK; if (ijskip[itype][type[j]]) continue; neighptr_middle[n_middle++] = joriginal; } } ilist[inum++] = i; firstneigh[i] = neighptr; numneigh[i] = n; npnt += n; if (n > oneatom || npnt >= pgsize) error->one("Neighbor list overflow, boost neigh_modify one or page"); firstneigh_inner[i] = neighptr_inner; numneigh_inner[i] = n_inner; npnt_inner += n_inner; if (npnt_inner >= pgsize) error->one("Neighbor list overflow, boost neigh_modify one or page"); if (respamiddle) { firstneigh_middle[i] = neighptr_middle; numneigh_middle[i] = n_middle; npnt_middle += n_middle; if (npnt_middle >= pgsize) error->one("Neighbor list overflow, boost neigh_modify one or page"); } } list->inum = inum; } /* ---------------------------------------------------------------------- create list which is simply a copy of parent list ------------------------------------------------------------------------- */ void Neighbor::copy_from(NeighList *list) { NeighList *listcopy = list->listcopy; list->inum = listcopy->inum; list->gnum = listcopy->gnum; list->ilist = listcopy->ilist; list->numneigh = listcopy->numneigh; list->firstneigh = listcopy->firstneigh; list->firstdouble = listcopy->firstdouble; list->pages = listcopy->pages; list->dpages = listcopy->dpages; } diff --git a/src/neigh_full.cpp b/src/neigh_full.cpp index a173fefeb..c667ab616 100644 --- a/src/neigh_full.cpp +++ b/src/neigh_full.cpp @@ -1,535 +1,533 @@ /* ---------------------------------------------------------------------- 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 "neighbor.h" #include "neigh_list.h" #include "atom.h" #include "group.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- N^2 search for all neighbors every neighbor pair appears in list of both atoms i and j ------------------------------------------------------------------------- */ void Neighbor::full_nsq(NeighList *list) { int i,j,n,itype,jtype,which,bitmask; double xtmp,ytmp,ztmp,delx,dely,delz,rsq; int *neighptr; int **special = atom->special; int **nspecial = atom->nspecial; int *tag = atom->tag; double **x = atom->x; int *type = atom->type; int *mask = atom->mask; int *molecule = atom->molecule; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; int molecular = atom->molecular; if (includegroup) { nlocal = atom->nfirst; bitmask = group->bitmask[includegroup]; } int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; int **pages = list->pages; int inum = 0; int npage = 0; int npnt = 0; // loop over owned atoms, storing neighbors for (i = 0; i < nlocal; i++) { if (pgsize - npnt < oneatom) { npnt = 0; npage++; if (npage == list->maxpage) pages = list->add_pages(); } neighptr = &pages[npage][npnt]; n = 0; itype = type[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; // loop over all atoms, owned and ghost // skip i = j for (j = 0; j < nall; j++) { if (includegroup && !(mask[j] & bitmask)) continue; if (i == j) continue; jtype = type[j]; if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; if (rsq <= cutneighsq[itype][jtype]) { - if (molecular) which = find_special(special[i],nspecial[i],tag[j]); - else which = 0; - if (which == 0) neighptr[n++] = j; - else if (which > 0) neighptr[n++] = which*nall + j; + if (molecular) { + which = find_special(special[i],nspecial[i],tag[j]); + if (which >= 0) neighptr[n++] = j ^ (which << SBBITS); + } else neighptr[n++] = j; } } ilist[inum++] = i; firstneigh[i] = neighptr; numneigh[i] = n; npnt += n; if (n > oneatom || npnt >= pgsize) error->one("Neighbor list overflow, boost neigh_modify one or page"); } list->inum = inum; list->gnum = 0; } /* ---------------------------------------------------------------------- N^2 search for all neighbors include neighbors of ghost atoms every neighbor pair appears in list of both atoms i and j ------------------------------------------------------------------------- */ void Neighbor::full_nsq_ghost(NeighList *list) { int i,j,n,itype,jtype,which; double xtmp,ytmp,ztmp,delx,dely,delz,rsq; int *neighptr; int **special = atom->special; int **nspecial = atom->nspecial; int *tag = atom->tag; double **x = atom->x; int *type = atom->type; int *mask = atom->mask; int *molecule = atom->molecule; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; int molecular = atom->molecular; int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; int **pages = list->pages; int inum = 0; int npage = 0; int npnt = 0; // loop over owned & ghost atoms, storing neighbors for (i = 0; i < nall; i++) { if (pgsize - npnt < oneatom) { npnt = 0; npage++; if (npage == list->maxpage) pages = list->add_pages(); } neighptr = &pages[npage][npnt]; n = 0; itype = type[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; // loop over all atoms, owned and ghost // skip i = j if (i < nlocal) { for (j = 0; j < nall; j++) { if (i == j) continue; jtype = type[j]; if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; if (rsq <= cutneighsq[itype][jtype]) { - if (molecular) which = find_special(special[i],nspecial[i],tag[j]); - else which = 0; - if (which == 0) neighptr[n++] = j; - else if (which > 0) neighptr[n++] = which*nall + j; + if (molecular) { + which = find_special(special[i],nspecial[i],tag[j]); + if (which >= 0) neighptr[n++] = j ^ (which << SBBITS); + } else neighptr[n++] = j; } } } else { for (j = 0; j < nall; j++) { if (i == j) continue; jtype = type[j]; if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; if (rsq <= cutneighghostsq[itype][jtype]) { - if (molecular) which = find_special(special[i],nspecial[i],tag[j]); - else which = 0; - if (which == 0) neighptr[n++] = j; - else if (which > 0) neighptr[n++] = which*nall + j; + if (molecular) { + which = find_special(special[i],nspecial[i],tag[j]); + if (which >= 0) neighptr[n++] = j ^ (which << SBBITS); + } else neighptr[n++] = j; } } } ilist[inum++] = i; firstneigh[i] = neighptr; numneigh[i] = n; npnt += n; if (n > oneatom || npnt >= pgsize) error->one("Neighbor list overflow, boost neigh_modify one or page"); } list->inum = atom->nlocal; list->gnum = inum - atom->nlocal; } /* ---------------------------------------------------------------------- binned neighbor list construction for all neighbors every neighbor pair appears in list of both atoms i and j ------------------------------------------------------------------------- */ void Neighbor::full_bin(NeighList *list) { int i,j,k,n,itype,jtype,ibin,which; double xtmp,ytmp,ztmp,delx,dely,delz,rsq; int *neighptr; // bin owned & ghost atoms bin_atoms(); int **special = atom->special; int **nspecial = atom->nspecial; int *tag = atom->tag; double **x = atom->x; int *type = atom->type; int *mask = atom->mask; int *molecule = atom->molecule; int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; int molecular = atom->molecular; if (includegroup) nlocal = atom->nfirst; int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; int **pages = list->pages; int nstencil = list->nstencil; int *stencil = list->stencil; int inum = 0; int npage = 0; int npnt = 0; // loop over owned atoms, storing neighbors for (i = 0; i < nlocal; i++) { if (pgsize - npnt < oneatom) { npnt = 0; npage++; if (npage == list->maxpage) pages = list->add_pages(); } neighptr = &pages[npage][npnt]; n = 0; itype = type[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; // loop over all atoms in surrounding bins in stencil including self // skip i = j ibin = coord2bin(x[i]); for (k = 0; k < nstencil; k++) { for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) { if (i == j) continue; jtype = type[j]; if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; if (rsq <= cutneighsq[itype][jtype]) { - if (molecular) which = find_special(special[i],nspecial[i],tag[j]); - else which = 0; - if (which == 0) neighptr[n++] = j; - else if (which > 0) neighptr[n++] = which*nall + j; + if (molecular) { + which = find_special(special[i],nspecial[i],tag[j]); + if (which >= 0) neighptr[n++] = j ^ (which << SBBITS); + } else neighptr[n++] = j; } } } ilist[inum++] = i; firstneigh[i] = neighptr; numneigh[i] = n; npnt += n; if (n > oneatom || npnt >= pgsize) error->one("Neighbor list overflow, boost neigh_modify one or page"); } list->inum = inum; list->gnum = 0; } /* ---------------------------------------------------------------------- binned neighbor list construction for all neighbors include neighbors of ghost atoms every neighbor pair appears in list of both atoms i and j ------------------------------------------------------------------------- */ void Neighbor::full_bin_ghost(NeighList *list) { int i,j,k,n,itype,jtype,ibin,which; double xtmp,ytmp,ztmp,delx,dely,delz,rsq; int xbin,ybin,zbin,xbin2,ybin2,zbin2; int *neighptr; // bin owned & ghost atoms bin_atoms(); int **special = atom->special; int **nspecial = atom->nspecial; int *tag = atom->tag; double **x = atom->x; int *type = atom->type; int *mask = atom->mask; int *molecule = atom->molecule; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; int molecular = atom->molecular; int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; int **pages = list->pages; int nstencil = list->nstencil; int *stencil = list->stencil; int **stencilxyz = list->stencilxyz; int inum = 0; int npage = 0; int npnt = 0; // loop over owned & ghost atoms, storing neighbors for (i = 0; i < nall; i++) { if (pgsize - npnt < oneatom) { npnt = 0; npage++; if (npage == list->maxpage) pages = list->add_pages(); } neighptr = &pages[npage][npnt]; n = 0; itype = type[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; // loop over all atoms in surrounding bins in stencil including self // when i is a ghost atom, must check if stencil bin is out of bounds // skip i = j if (i < nlocal) { ibin = coord2bin(x[i]); for (k = 0; k < nstencil; k++) { for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) { if (i == j) continue; jtype = type[j]; if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; if (rsq <= cutneighsq[itype][jtype]) { - if (molecular) which = find_special(special[i],nspecial[i],tag[j]); - else which = 0; - if (which == 0) neighptr[n++] = j; - else if (which > 0) neighptr[n++] = which*nall + j; + if (molecular) { + which = find_special(special[i],nspecial[i],tag[j]); + if (which >= 0) neighptr[n++] = j ^ (which << SBBITS); + } else neighptr[n++] = j; } } } } else { ibin = coord2bin(x[i],xbin,ybin,zbin); for (k = 0; k < nstencil; k++) { xbin2 = xbin + stencilxyz[k][0]; ybin2 = ybin + stencilxyz[k][1]; zbin2 = zbin + stencilxyz[k][2]; if (xbin2 < 0 || xbin2 >= mbinx || ybin2 < 0 || ybin2 >= mbiny || zbin2 < 0 || zbin2 >= mbinz) continue; for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) { if (i == j) continue; jtype = type[j]; if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; if (rsq <= cutneighghostsq[itype][jtype]) { - if (molecular) which = find_special(special[i],nspecial[i],tag[j]); - else which = 0; - if (which == 0) neighptr[n++] = j; - else if (which > 0) neighptr[n++] = which*nall + j; + if (molecular) { + which = find_special(special[i],nspecial[i],tag[j]); + if (which >= 0) neighptr[n++] = j ^ (which << SBBITS); + } else neighptr[n++] = j; } } } } ilist[inum++] = i; firstneigh[i] = neighptr; numneigh[i] = n; npnt += n; if (n > oneatom || npnt >= pgsize) error->one("Neighbor list overflow, boost neigh_modify one or page"); } list->inum = atom->nlocal; list->gnum = inum - atom->nlocal; } /* ---------------------------------------------------------------------- binned neighbor list construction for all neighbors multi-type stencil is itype dependent and is distance checked every neighbor pair appears in list of both atoms i and j ------------------------------------------------------------------------- */ void Neighbor::full_multi(NeighList *list) { int i,j,k,n,itype,jtype,ibin,which,ns; double xtmp,ytmp,ztmp,delx,dely,delz,rsq; int *neighptr,*s; double *cutsq,*distsq; // bin local & ghost atoms bin_atoms(); // loop over each atom, storing neighbors int **special = atom->special; int **nspecial = atom->nspecial; int *tag = atom->tag; double **x = atom->x; int *type = atom->type; int *mask = atom->mask; int *molecule = atom->molecule; int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; int molecular = atom->molecular; if (includegroup) nlocal = atom->nfirst; int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; int **pages = list->pages; int *nstencil_multi = list->nstencil_multi; int **stencil_multi = list->stencil_multi; double **distsq_multi = list->distsq_multi; int inum = 0; int npage = 0; int npnt = 0; for (i = 0; i < nlocal; i++) { if (pgsize - npnt < oneatom) { npnt = 0; npage++; if (npage == list->maxpage) pages = list->add_pages(); } neighptr = &pages[npage][npnt]; n = 0; itype = type[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; // loop over all atoms in other bins in stencil, including self // skip if i,j neighbor cutoff is less than bin distance // skip i = j ibin = coord2bin(x[i]); s = stencil_multi[itype]; distsq = distsq_multi[itype]; cutsq = cutneighsq[itype]; ns = nstencil_multi[itype]; for (k = 0; k < ns; k++) { for (j = binhead[ibin+s[k]]; j >= 0; j = bins[j]) { jtype = type[j]; if (cutsq[jtype] < distsq[k]) continue; if (i == j) continue; if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; if (rsq <= cutneighsq[itype][jtype]) { - if (molecular) which = find_special(special[i],nspecial[i],tag[j]); - else which = 0; - if (which == 0) neighptr[n++] = j; - else if (which > 0) neighptr[n++] = which*nall + j; + if (molecular) { + which = find_special(special[i],nspecial[i],tag[j]); + if (which >= 0) neighptr[n++] = j ^ (which << SBBITS); + } else neighptr[n++] = j; } } } ilist[inum++] = i; firstneigh[i] = neighptr; numneigh[i] = n; npnt += n; if (n > oneatom || npnt >= pgsize) error->one("Neighbor list overflow, boost neigh_modify one or page"); } list->inum = inum; list->gnum = 0; } diff --git a/src/neigh_half_bin.cpp b/src/neigh_half_bin.cpp index 3432b4a0d..e776b8203 100644 --- a/src/neigh_half_bin.cpp +++ b/src/neigh_half_bin.cpp @@ -1,341 +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 "neighbor.h" #include "neigh_list.h" #include "atom.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- binned neighbor list construction with partial Newton's 3rd law each owned atom i checks own bin and other bins in stencil pair stored once if i,j are both owned and i < j pair stored by me if j is ghost (also stored by proc owning j) ------------------------------------------------------------------------- */ void Neighbor::half_bin_no_newton(NeighList *list) { int i,j,k,n,itype,jtype,ibin,which; double xtmp,ytmp,ztmp,delx,dely,delz,rsq; int *neighptr; // bin local & ghost atoms bin_atoms(); // loop over each atom, storing neighbors int **special = atom->special; int **nspecial = atom->nspecial; int *tag = atom->tag; double **x = atom->x; int *type = atom->type; int *mask = atom->mask; int *molecule = atom->molecule; int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; if (includegroup) nlocal = atom->nfirst; int molecular = atom->molecular; int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; int **pages = list->pages; int nstencil = list->nstencil; int *stencil = list->stencil; int inum = 0; int npage = 0; int npnt = 0; for (i = 0; i < nlocal; i++) { if (pgsize - npnt < oneatom) { npnt = 0; npage++; if (npage == list->maxpage) pages = list->add_pages(); } neighptr = &pages[npage][npnt]; n = 0; itype = type[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; // loop over all atoms in other bins in stencil including self // only store pair if i < j // stores own/own pairs only once // stores own/ghost pairs on both procs ibin = coord2bin(x[i]); for (k = 0; k < nstencil; k++) { for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) { if (j <= i) continue; jtype = type[j]; if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; if (rsq <= cutneighsq[itype][jtype]) { - if (molecular) which = find_special(special[i],nspecial[i],tag[j]); - else which = 0; - if (which == 0) neighptr[n++] = j; - else if (which > 0) neighptr[n++] = which*nall + j; + if (molecular) { + which = find_special(special[i],nspecial[i],tag[j]); + if (which >= 0) neighptr[n++] = j ^ (which << SBBITS); + } else neighptr[n++] = j; } } } ilist[inum++] = i; firstneigh[i] = neighptr; numneigh[i] = n; npnt += n; if (n > oneatom || npnt >= pgsize) error->one("Neighbor list overflow, boost neigh_modify one or page"); } list->inum = inum; } /* ---------------------------------------------------------------------- binned neighbor list construction with full Newton's 3rd law each owned atom i checks its own bin and other bins in Newton stencil every pair stored exactly once by some processor ------------------------------------------------------------------------- */ void Neighbor::half_bin_newton(NeighList *list) { int i,j,k,n,itype,jtype,ibin,which; double xtmp,ytmp,ztmp,delx,dely,delz,rsq; int *neighptr; // bin local & ghost atoms bin_atoms(); // loop over each atom, storing neighbors int **special = atom->special; int **nspecial = atom->nspecial; int *tag = atom->tag; double **x = atom->x; int *type = atom->type; int *mask = atom->mask; int *molecule = atom->molecule; int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; - int molecular = atom->molecular; if (includegroup) nlocal = atom->nfirst; + int molecular = atom->molecular; int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; int **pages = list->pages; int nstencil = list->nstencil; int *stencil = list->stencil; int inum = 0; int npage = 0; int npnt = 0; for (i = 0; i < nlocal; i++) { if (pgsize - npnt < oneatom) { npnt = 0; npage++; if (npage == list->maxpage) pages = list->add_pages(); } neighptr = &pages[npage][npnt]; n = 0; itype = type[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; // loop over rest of atoms in i's bin, ghosts are at end of linked list // if j is owned atom, store it, since j is beyond i in linked list // if j is ghost, only store if j coords are "above and to the right" of i for (j = bins[i]; j >= 0; j = bins[j]) { if (j >= nlocal) { if (x[j][2] < ztmp) continue; if (x[j][2] == ztmp) { if (x[j][1] < ytmp) continue; if (x[j][1] == ytmp && x[j][0] < xtmp) continue; } } jtype = type[j]; if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; if (rsq <= cutneighsq[itype][jtype]) { - if (molecular) which = find_special(special[i],nspecial[i],tag[j]); - else which = 0; - if (which == 0) neighptr[n++] = j; - else if (which > 0) neighptr[n++] = which*nall + j; + if (molecular) { + which = find_special(special[i],nspecial[i],tag[j]); + if (which >= 0) neighptr[n++] = j ^ (which << SBBITS); + } else neighptr[n++] = j; } } // loop over all atoms in other bins in stencil, store every pair ibin = coord2bin(x[i]); for (k = 0; k < nstencil; k++) { for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) { jtype = type[j]; if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; if (rsq <= cutneighsq[itype][jtype]) { - if (molecular) which = find_special(special[i],nspecial[i],tag[j]); - else which = 0; - if (which == 0) neighptr[n++] = j; - else if (which > 0) neighptr[n++] = which*nall + j; + if (molecular) { + which = find_special(special[i],nspecial[i],tag[j]); + if (which >= 0) neighptr[n++] = j ^ (which << SBBITS); + } else neighptr[n++] = j; } } } ilist[inum++] = i; firstneigh[i] = neighptr; numneigh[i] = n; npnt += n; if (n > oneatom || npnt >= pgsize) error->one("Neighbor list overflow, boost neigh_modify one or page"); } list->inum = inum; } /* ---------------------------------------------------------------------- binned neighbor list construction with Newton's 3rd law for triclinic each owned atom i checks its own bin and other bins in triclinic stencil every pair stored exactly once by some processor ------------------------------------------------------------------------- */ void Neighbor::half_bin_newton_tri(NeighList *list) { int i,j,k,n,itype,jtype,ibin,which; double xtmp,ytmp,ztmp,delx,dely,delz,rsq; int *neighptr; // bin local & ghost atoms bin_atoms(); // loop over each atom, storing neighbors int **special = atom->special; int **nspecial = atom->nspecial; int *tag = atom->tag; double **x = atom->x; int *type = atom->type; int *mask = atom->mask; int *molecule = atom->molecule; int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; - int molecular = atom->molecular; if (includegroup) nlocal = atom->nfirst; + int molecular = atom->molecular; int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; int **pages = list->pages; int nstencil = list->nstencil; int *stencil = list->stencil; int inum = 0; int npage = 0; int npnt = 0; for (i = 0; i < nlocal; i++) { if (pgsize - npnt < oneatom) { npnt = 0; npage++; if (npage == list->maxpage) pages = list->add_pages(); } neighptr = &pages[npage][npnt]; n = 0; itype = type[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; // loop over all atoms in bins in stencil // pairs for atoms j "below" i are excluded // below = lower z or (equal z and lower y) or (equal zy and lower x) // (equal zyx and j <= i) // latter excludes self-self interaction but allows superposed atoms ibin = coord2bin(x[i]); for (k = 0; k < nstencil; k++) { for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) { if (x[j][2] < ztmp) continue; if (x[j][2] == ztmp) { if (x[j][1] < ytmp) continue; if (x[j][1] == ytmp) { if (x[j][0] < xtmp) continue; if (x[j][0] == xtmp && j <= i) continue; } } jtype = type[j]; if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; if (rsq <= cutneighsq[itype][jtype]) { - if (molecular) which = find_special(special[i],nspecial[i],tag[j]); - else which = 0; - if (which == 0) neighptr[n++] = j; - else if (which > 0) neighptr[n++] = which*nall + j; + if (molecular) { + which = find_special(special[i],nspecial[i],tag[j]); + if (which >= 0) neighptr[n++] = j ^ (which << SBBITS); + } else neighptr[n++] = j; } } } ilist[inum++] = i; firstneigh[i] = neighptr; numneigh[i] = n; npnt += n; if (n > oneatom || npnt >= pgsize) error->one("Neighbor list overflow, boost neigh_modify one or page"); } list->inum = inum; } diff --git a/src/neigh_half_multi.cpp b/src/neigh_half_multi.cpp index b61a53114..d0a8efcd2 100644 --- a/src/neigh_half_multi.cpp +++ b/src/neigh_half_multi.cpp @@ -1,369 +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 "neighbor.h" #include "neigh_list.h" #include "atom.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- binned neighbor list construction with partial Newton's 3rd law each owned atom i checks own bin and other bins in stencil multi-type stencil is itype dependent and is distance checked pair stored once if i,j are both owned and i < j pair stored by me if j is ghost (also stored by proc owning j) ------------------------------------------------------------------------- */ void Neighbor::half_multi_no_newton(NeighList *list) { int i,j,k,n,itype,jtype,ibin,which,ns; double xtmp,ytmp,ztmp,delx,dely,delz,rsq; int *neighptr,*s; double *cutsq,*distsq; // bin local & ghost atoms bin_atoms(); // loop over each atom, storing neighbors int **special = atom->special; int **nspecial = atom->nspecial; int *tag = atom->tag; double **x = atom->x; int *type = atom->type; int *mask = atom->mask; int *molecule = atom->molecule; int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; int molecular = atom->molecular; if (includegroup) nlocal = atom->nfirst; int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; int **pages = list->pages; int *nstencil_multi = list->nstencil_multi; int **stencil_multi = list->stencil_multi; double **distsq_multi = list->distsq_multi; int inum = 0; int npage = 0; int npnt = 0; for (i = 0; i < nlocal; i++) { if (pgsize - npnt < oneatom) { npnt = 0; npage++; if (npage == list->maxpage) pages = list->add_pages(); } neighptr = &pages[npage][npnt]; n = 0; itype = type[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; // loop over all atoms in other bins in stencil including self // only store pair if i < j // skip if i,j neighbor cutoff is less than bin distance // stores own/own pairs only once // stores own/ghost pairs on both procs ibin = coord2bin(x[i]); s = stencil_multi[itype]; distsq = distsq_multi[itype]; cutsq = cutneighsq[itype]; ns = nstencil_multi[itype]; for (k = 0; k < ns; k++) { for (j = binhead[ibin+s[k]]; j >= 0; j = bins[j]) { if (j <= i) continue; jtype = type[j]; if (cutsq[jtype] < distsq[k]) continue; if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; if (rsq <= cutneighsq[itype][jtype]) { - if (molecular) which = find_special(special[i],nspecial[i],tag[j]); - else which = 0; - if (which == 0) neighptr[n++] = j; - else if (which > 0) neighptr[n++] = which*nall + j; + if (molecular) { + which = find_special(special[i],nspecial[i],tag[j]); + if (which >= 0) neighptr[n++] = j ^ (which << SBBITS); + } else neighptr[n++] = j; } } } ilist[inum++] = i; firstneigh[i] = neighptr; numneigh[i] = n; npnt += n; if (n > oneatom || npnt >= pgsize) error->one("Neighbor list overflow, boost neigh_modify one or page"); } list->inum = inum; } /* ---------------------------------------------------------------------- binned neighbor list construction with full Newton's 3rd law each owned atom i checks its own bin and other bins in Newton stencil multi-type stencil is itype dependent and is distance checked every pair stored exactly once by some processor ------------------------------------------------------------------------- */ void Neighbor::half_multi_newton(NeighList *list) { int i,j,k,n,itype,jtype,ibin,which,ns; double xtmp,ytmp,ztmp,delx,dely,delz,rsq; int *neighptr,*s; double *cutsq,*distsq; // bin local & ghost atoms bin_atoms(); // loop over each atom, storing neighbors int **special = atom->special; int **nspecial = atom->nspecial; int *tag = atom->tag; double **x = atom->x; int *type = atom->type; int *mask = atom->mask; int *molecule = atom->molecule; int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; int molecular = atom->molecular; if (includegroup) nlocal = atom->nfirst; int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; int **pages = list->pages; int *nstencil_multi = list->nstencil_multi; int **stencil_multi = list->stencil_multi; double **distsq_multi = list->distsq_multi; int inum = 0; int npage = 0; int npnt = 0; for (i = 0; i < nlocal; i++) { if (pgsize - npnt < oneatom) { npnt = 0; npage++; if (npage == list->maxpage) pages = list->add_pages(); } neighptr = &pages[npage][npnt]; n = 0; itype = type[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; // loop over rest of atoms in i's bin, ghosts are at end of linked list // if j is owned atom, store it, since j is beyond i in linked list // if j is ghost, only store if j coords are "above and to the right" of i for (j = bins[i]; j >= 0; j = bins[j]) { if (j >= nlocal) { if (x[j][2] < ztmp) continue; if (x[j][2] == ztmp) { if (x[j][1] < ytmp) continue; if (x[j][1] == ytmp && x[j][0] < xtmp) continue; } } jtype = type[j]; if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; if (rsq <= cutneighsq[itype][jtype]) { - if (molecular) which = find_special(special[i],nspecial[i],tag[j]); - else which = 0; - if (which == 0) neighptr[n++] = j; - else if (which > 0) neighptr[n++] = which*nall + j; + if (molecular) { + which = find_special(special[i],nspecial[i],tag[j]); + if (which >= 0) neighptr[n++] = j ^ (which << SBBITS); + } else neighptr[n++] = j; } } // loop over all atoms in other bins in stencil, store every pair // skip if i,j neighbor cutoff is less than bin distance ibin = coord2bin(x[i]); s = stencil_multi[itype]; distsq = distsq_multi[itype]; cutsq = cutneighsq[itype]; ns = nstencil_multi[itype]; for (k = 0; k < ns; k++) { for (j = binhead[ibin+s[k]]; j >= 0; j = bins[j]) { jtype = type[j]; if (cutsq[jtype] < distsq[k]) continue; if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; if (rsq <= cutneighsq[itype][jtype]) { - if (molecular) which = find_special(special[i],nspecial[i],tag[j]); - else which = 0; - if (which == 0) neighptr[n++] = j; - else if (which > 0) neighptr[n++] = which*nall + j; + if (molecular) { + which = find_special(special[i],nspecial[i],tag[j]); + if (which >= 0) neighptr[n++] = j ^ (which << SBBITS); + } else neighptr[n++] = j; } } } ilist[inum++] = i; firstneigh[i] = neighptr; numneigh[i] = n; npnt += n; if (n > oneatom || npnt >= pgsize) error->one("Neighbor list overflow, boost neigh_modify one or page"); } list->inum = inum; } /* ---------------------------------------------------------------------- binned neighbor list construction with Newton's 3rd law for triclinic each owned atom i checks its own bin and other bins in triclinic stencil multi-type stencil is itype dependent and is distance checked every pair stored exactly once by some processor ------------------------------------------------------------------------- */ void Neighbor::half_multi_newton_tri(NeighList *list) { int i,j,k,n,itype,jtype,ibin,which,ns; double xtmp,ytmp,ztmp,delx,dely,delz,rsq; int *neighptr,*s; double *cutsq,*distsq; // bin local & ghost atoms bin_atoms(); // loop over each atom, storing neighbors int **special = atom->special; int **nspecial = atom->nspecial; int *tag = atom->tag; double **x = atom->x; int *type = atom->type; int *mask = atom->mask; int *molecule = atom->molecule; int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; int molecular = atom->molecular; if (includegroup) nlocal = atom->nfirst; int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; int **pages = list->pages; int *nstencil_multi = list->nstencil_multi; int **stencil_multi = list->stencil_multi; double **distsq_multi = list->distsq_multi; int inum = 0; int npage = 0; int npnt = 0; for (i = 0; i < nlocal; i++) { if (pgsize - npnt < oneatom) { npnt = 0; npage++; if (npage == list->maxpage) pages = list->add_pages(); } neighptr = &pages[npage][npnt]; n = 0; itype = type[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; // loop over all atoms in bins, including self, in stencil // skip if i,j neighbor cutoff is less than bin distance // bins below self are excluded from stencil // pairs for atoms j "below" i are excluded // below = lower z or (equal z and lower y) or (equal zy and lower x) // (equal zyx and j <= i) // latter excludes self-self interaction but allows superposed atoms ibin = coord2bin(x[i]); s = stencil_multi[itype]; distsq = distsq_multi[itype]; cutsq = cutneighsq[itype]; ns = nstencil_multi[itype]; for (k = 0; k < ns; k++) { for (j = binhead[ibin+s[k]]; j >= 0; j = bins[j]) { jtype = type[j]; if (cutsq[jtype] < distsq[k]) continue; if (x[j][2] < ztmp) continue; if (x[j][2] == ztmp) { if (x[j][1] < ytmp) continue; if (x[j][1] == ytmp) { if (x[j][0] < xtmp) continue; if (x[j][0] == xtmp && j <= i) continue; } } if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; if (rsq <= cutneighsq[itype][jtype]) { - if (molecular) which = find_special(special[i],nspecial[i],tag[j]); - else which = 0; - if (which == 0) neighptr[n++] = j; - else if (which > 0) neighptr[n++] = which*nall + j; + if (molecular) { + which = find_special(special[i],nspecial[i],tag[j]); + if (which >= 0) neighptr[n++] = j ^ (which << SBBITS); + } else neighptr[n++] = j; } } } ilist[inum++] = i; firstneigh[i] = neighptr; numneigh[i] = n; npnt += n; if (n > oneatom || npnt >= pgsize) error->one("Neighbor list overflow, boost neigh_modify one or page"); } list->inum = inum; } diff --git a/src/neigh_half_nsq.cpp b/src/neigh_half_nsq.cpp index 0447c3ffd..1df486598 100644 --- a/src/neigh_half_nsq.cpp +++ b/src/neigh_half_nsq.cpp @@ -1,210 +1,210 @@ /* ---------------------------------------------------------------------- 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 "neighbor.h" #include "neigh_list.h" #include "atom.h" #include "group.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- N^2 / 2 search for neighbor pairs with partial Newton's 3rd law pair stored once if i,j are both owned and i < j pair stored by me if j is ghost (also stored by proc owning j) ------------------------------------------------------------------------- */ void Neighbor::half_nsq_no_newton(NeighList *list) { int i,j,n,itype,jtype,which,bitmask; double xtmp,ytmp,ztmp,delx,dely,delz,rsq; int *neighptr; // loop over each atom, storing neighbors int **special = atom->special; int **nspecial = atom->nspecial; int *tag = atom->tag; double **x = atom->x; int *type = atom->type; int *mask = atom->mask; int *molecule = atom->molecule; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; int molecular = atom->molecular; if (includegroup) { nlocal = atom->nfirst; bitmask = group->bitmask[includegroup]; } int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; int **pages = list->pages; int inum = 0; int npage = 0; int npnt = 0; for (i = 0; i < nlocal; i++) { if (pgsize - npnt < oneatom) { npnt = 0; npage++; if (npage == list->maxpage) pages = list->add_pages(); } neighptr = &pages[npage][npnt]; n = 0; itype = type[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; // loop over remaining atoms, owned and ghost for (j = i+1; j < nall; j++) { if (includegroup && !(mask[j] & bitmask)) continue; jtype = type[j]; if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; if (rsq <= cutneighsq[itype][jtype]) { - if (molecular) which = find_special(special[i],nspecial[i],tag[j]); - else which = 0; - if (which == 0) neighptr[n++] = j; - else if (which > 0) neighptr[n++] = which*nall + j; + if (molecular) { + which = find_special(special[i],nspecial[i],tag[j]); + if (which >= 0) neighptr[n++] = j ^ (which << SBBITS); + } else neighptr[n++] = j; } } ilist[inum++] = i; firstneigh[i] = neighptr; numneigh[i] = n; npnt += n; if (n > oneatom || npnt >= pgsize) error->one("Neighbor list overflow, boost neigh_modify one or page"); } list->inum = inum; } /* ---------------------------------------------------------------------- N^2 / 2 search for neighbor pairs with full Newton's 3rd law every pair stored exactly once by some processor decision on ghost atoms based on itag,jtag tests ------------------------------------------------------------------------- */ void Neighbor::half_nsq_newton(NeighList *list) { int i,j,n,itype,jtype,itag,jtag,which,bitmask; double xtmp,ytmp,ztmp,delx,dely,delz,rsq; int *neighptr; // loop over each atom, storing neighbors int **special = atom->special; int **nspecial = atom->nspecial; int *tag = atom->tag; double **x = atom->x; int *type = atom->type; int *mask = atom->mask; int *molecule = atom->molecule; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; int molecular = atom->molecular; if (includegroup) { nlocal = atom->nfirst; bitmask = group->bitmask[includegroup]; } int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; int **pages = list->pages; int inum = 0; int npage = 0; int npnt = 0; for (i = 0; i < nlocal; i++) { if (pgsize - npnt < oneatom) { npnt = 0; npage++; if (npage == list->maxpage) pages = list->add_pages(); } neighptr = &pages[npage][npnt]; n = 0; itag = tag[i]; itype = type[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; // loop over remaining atoms, owned and ghost // itag = jtag is possible for long cutoffs that include images of self for (j = i+1; j < nall; j++) { if (includegroup && !(mask[j] & bitmask)) continue; if (j >= nlocal) { jtag = tag[j]; if (itag > jtag) { if ((itag+jtag) % 2 == 0) continue; } else if (itag < jtag) { if ((itag+jtag) % 2 == 1) continue; } else { if (x[j][2] < ztmp) continue; if (x[j][2] == ztmp) { if (x[j][1] < ytmp) continue; if (x[j][1] == ytmp && x[j][0] < xtmp) continue; } } } jtype = type[j]; if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; if (rsq <= cutneighsq[itype][jtype]) { - if (molecular) which = find_special(special[i],nspecial[i],tag[j]); - else which = 0; - if (which == 0) neighptr[n++] = j; - else if (which > 0) neighptr[n++] = which*nall + j; + if (molecular) { + which = find_special(special[i],nspecial[i],tag[j]); + if (which >= 0) neighptr[n++] = j ^ (which << SBBITS); + } else neighptr[n++] = j; } } ilist[inum++] = i; firstneigh[i] = neighptr; numneigh[i] = n; npnt += n; if (n > oneatom || npnt >= pgsize) error->one("Neighbor list overflow, boost neigh_modify one or page"); } list->inum = inum; } diff --git a/src/neigh_respa.cpp b/src/neigh_respa.cpp index a1e0194a3..a5190316f 100644 --- a/src/neigh_respa.cpp +++ b/src/neigh_respa.cpp @@ -1,901 +1,907 @@ /* ---------------------------------------------------------------------- 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 "neighbor.h" #include "neigh_list.h" #include "atom.h" #include "group.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- multiple respa lists N^2 / 2 search for neighbor pairs with partial Newton's 3rd law pair added to list if atoms i and j are both owned and i < j pair added if j is ghost (also stored by proc owning j) ------------------------------------------------------------------------- */ void Neighbor::respa_nsq_no_newton(NeighList *list) { int i,j,n,itype,jtype,which,n_inner,n_middle,bitmask; double xtmp,ytmp,ztmp,delx,dely,delz,rsq; int *neighptr,*neighptr_inner,*neighptr_middle; // loop over each atom, storing neighbors int **special = atom->special; int **nspecial = atom->nspecial; int *tag = atom->tag; double **x = atom->x; int *type = atom->type; int *mask = atom->mask; int *molecule = atom->molecule; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; int molecular = atom->molecular; if (includegroup) { nlocal = atom->nfirst; bitmask = group->bitmask[includegroup]; } int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; int **pages = list->pages; NeighList *listinner = list->listinner; int *ilist_inner = listinner->ilist; int *numneigh_inner = listinner->numneigh; int **firstneigh_inner = listinner->firstneigh; int **pages_inner = listinner->pages; NeighList *listmiddle; int *ilist_middle,*numneigh_middle,**firstneigh_middle,**pages_middle; int respamiddle = list->respamiddle; if (respamiddle) { listmiddle = list->listmiddle; ilist_middle = listmiddle->ilist; numneigh_middle = listmiddle->numneigh; firstneigh_middle = listmiddle->firstneigh; pages_middle = listmiddle->pages; } int inum = 0; int npage = 0; int npnt = 0; int npage_inner = 0; int npnt_inner = 0; int npage_middle = 0; int npnt_middle = 0; for (i = 0; i < nlocal; i++) { if (pgsize - npnt < oneatom) { npnt = 0; npage++; if (npage == list->maxpage) pages = list->add_pages(); } neighptr = &pages[npage][npnt]; n = 0; if (pgsize - npnt_inner < oneatom) { npnt_inner = 0; npage_inner++; if (npage_inner == listinner->maxpage) pages_inner = listinner->add_pages(); } neighptr_inner = &pages_inner[npage_inner][npnt_inner]; n_inner = 0; if (respamiddle) { if (pgsize - npnt_middle < oneatom) { npnt_middle = 0; npage_middle++; if (npage_middle == listmiddle->maxpage) pages_middle = listmiddle->add_pages(); } neighptr_middle = &pages_middle[npage_middle][npnt_middle]; n_middle = 0; } itype = type[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; // loop over remaining atoms, owned and ghost for (j = i+1; j < nall; j++) { if (includegroup && !(mask[j] & bitmask)) continue; jtype = type[j]; if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; if (rsq <= cutneighsq[itype][jtype]) { - if (molecular) which = find_special(special[i],nspecial[i],tag[j]); - else which = 0; - if (which == 0) neighptr[n++] = j; - else if (which > 0) neighptr[n++] = which*nall + j; + if (molecular) { + which = find_special(special[i],nspecial[i],tag[j]); + if (which >= 0) neighptr[n++] = j ^ (which << SBBITS); + } else neighptr[n++] = j; if (rsq < cut_inner_sq) { if (which == 0) neighptr_inner[n_inner++] = j; - else if (which > 0) neighptr_inner[n_inner++] = which*nall + j; + else if (which > 0) neighptr_inner[n_inner++] = j ^ (which << SBBITS); } if (respamiddle && rsq < cut_middle_sq && rsq > cut_middle_inside_sq) { if (which == 0) neighptr_middle[n_middle++] = j; - else if (which > 0) neighptr_middle[n_middle++] = which*nall + j; + else if (which > 0) + neighptr_middle[n_middle++] = j ^ (which << SBBITS); } } } ilist[inum] = i; firstneigh[i] = neighptr; numneigh[i] = n; npnt += n; if (n > oneatom || npnt >= pgsize) error->one("Neighbor list overflow, boost neigh_modify one or page"); ilist_inner[inum] = i; firstneigh_inner[i] = neighptr_inner; numneigh_inner[i] = n_inner; npnt_inner += n_inner; if (npnt_inner >= pgsize) error->one("Neighbor list overflow, boost neigh_modify one or page"); if (respamiddle) { ilist_middle[inum] = i; firstneigh_middle[i] = neighptr_middle; numneigh_middle[i] = n_middle; npnt_middle += n_middle; if (npnt_middle >= pgsize) error->one("Neighbor list overflow, boost neigh_modify one or page"); } inum++; } list->inum = inum; listinner->inum = inum; if (respamiddle) listmiddle->inum = inum; } /* ---------------------------------------------------------------------- multiple respa lists N^2 / 2 search for neighbor pairs with full Newton's 3rd law pair added to list if atoms i and j are both owned and i < j if j is ghost only me or other proc adds pair decision based on itag,jtag tests ------------------------------------------------------------------------- */ void Neighbor::respa_nsq_newton(NeighList *list) { int i,j,n,itype,jtype,itag,jtag,which,n_inner,n_middle,bitmask; double xtmp,ytmp,ztmp,delx,dely,delz,rsq; int *neighptr,*neighptr_inner,*neighptr_middle; // loop over each atom, storing neighbors int **special = atom->special; int **nspecial = atom->nspecial; int *tag = atom->tag; double **x = atom->x; int *type = atom->type; int *mask = atom->mask; int *molecule = atom->molecule; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; int molecular = atom->molecular; if (includegroup) { nlocal = atom->nfirst; bitmask = group->bitmask[includegroup]; } int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; int **pages = list->pages; NeighList *listinner = list->listinner; int *ilist_inner = listinner->ilist; int *numneigh_inner = listinner->numneigh; int **firstneigh_inner = listinner->firstneigh; int **pages_inner = listinner->pages; NeighList *listmiddle; int *ilist_middle,*numneigh_middle,**firstneigh_middle,**pages_middle; int respamiddle = list->respamiddle; if (respamiddle) { listmiddle = list->listmiddle; ilist_middle = listmiddle->ilist; numneigh_middle = listmiddle->numneigh; firstneigh_middle = listmiddle->firstneigh; pages_middle = listmiddle->pages; } int inum = 0; int npage = 0; int npnt = 0; int npage_inner = 0; int npnt_inner = 0; int npage_middle = 0; int npnt_middle = 0; for (i = 0; i < nlocal; i++) { if (pgsize - npnt < oneatom) { npnt = 0; npage++; if (npage == list->maxpage) pages = list->add_pages(); } neighptr = &pages[npage][npnt]; n = 0; if (pgsize - npnt_inner < oneatom) { npnt_inner = 0; npage_inner++; if (npage_inner == listinner->maxpage) pages_inner = listinner->add_pages(); } neighptr_inner = &pages_inner[npage_inner][npnt_inner]; n_inner = 0; if (respamiddle) { if (pgsize - npnt_middle < oneatom) { npnt_middle = 0; npage_middle++; if (npage_middle == listmiddle->maxpage) pages_middle = listmiddle->add_pages(); } neighptr_middle = &pages_middle[npage_middle][npnt_middle]; n_middle = 0; } itag = tag[i]; itype = type[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; // loop over remaining atoms, owned and ghost for (j = i+1; j < nall; j++) { if (includegroup && !(mask[j] & bitmask)) continue; if (j >= nlocal) { jtag = tag[j]; if (itag > jtag) { if ((itag+jtag) % 2 == 0) continue; } else if (itag < jtag) { if ((itag+jtag) % 2 == 1) continue; } else { if (x[j][2] < ztmp) continue; if (x[j][2] == ztmp) { if (x[j][1] < ytmp) continue; if (x[j][1] == ytmp && x[j][0] < xtmp) continue; } } } jtype = type[j]; if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; if (rsq <= cutneighsq[itype][jtype]) { - if (molecular) which = find_special(special[i],nspecial[i],tag[j]); - else which = 0; - if (which == 0) neighptr[n++] = j; - else if (which > 0) neighptr[n++] = which*nall + j; + if (molecular) { + which = find_special(special[i],nspecial[i],tag[j]); + if (which >= 0) neighptr[n++] = j ^ (which << SBBITS); + } else neighptr[n++] = j; if (rsq < cut_inner_sq) { if (which == 0) neighptr_inner[n_inner++] = j; - else if (which > 0) neighptr_inner[n_inner++] = which*nall + j; + else if (which > 0) neighptr_inner[n_inner++] = j ^ (which << SBBITS); } if (respamiddle && rsq < cut_middle_sq && rsq > cut_middle_inside_sq) { if (which == 0) neighptr_middle[n_middle++] = j; - else if (which > 0) neighptr_middle[n_middle++] = which*nall + j; + else if (which > 0) + neighptr_middle[n_middle++] = j ^ (which << SBBITS); } } } ilist[inum] = i; firstneigh[i] = neighptr; numneigh[i] = n; npnt += n; if (n > oneatom || npnt >= pgsize) error->one("Neighbor list overflow, boost neigh_modify one or page"); ilist_inner[inum] = i; firstneigh_inner[i] = neighptr_inner; numneigh_inner[i] = n_inner; npnt_inner += n_inner; if (npnt_inner >= pgsize) error->one("Neighbor list overflow, boost neigh_modify one or page"); if (respamiddle) { ilist_middle[inum] = i; firstneigh_middle[i] = neighptr_middle; numneigh_middle[i] = n_middle; npnt_middle += n_middle; if (npnt_middle >= pgsize) error->one("Neighbor list overflow, boost neigh_modify one or page"); } inum++; } list->inum = inum; listinner->inum = inum; if (respamiddle) listmiddle->inum = inum; } /* ---------------------------------------------------------------------- multiple respa lists binned neighbor list construction with partial Newton's 3rd law each owned atom i checks own bin and surrounding bins in non-Newton stencil pair stored once if i,j are both owned and i < j pair stored by me if j is ghost (also stored by proc owning j) ------------------------------------------------------------------------- */ void Neighbor::respa_bin_no_newton(NeighList *list) { int i,j,k,n,itype,jtype,ibin,which,n_inner,n_middle; double xtmp,ytmp,ztmp,delx,dely,delz,rsq; int *neighptr,*neighptr_inner,*neighptr_middle; // bin local & ghost atoms bin_atoms(); // loop over each atom, storing neighbors int **special = atom->special; int **nspecial = atom->nspecial; int *tag = atom->tag; double **x = atom->x; int *type = atom->type; int *mask = atom->mask; int *molecule = atom->molecule; int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; int molecular = atom->molecular; if (includegroup) nlocal = atom->nfirst; int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; int **pages = list->pages; int nstencil = list->nstencil; int *stencil = list->stencil; NeighList *listinner = list->listinner; int *ilist_inner = listinner->ilist; int *numneigh_inner = listinner->numneigh; int **firstneigh_inner = listinner->firstneigh; int **pages_inner = listinner->pages; NeighList *listmiddle; int *ilist_middle,*numneigh_middle,**firstneigh_middle,**pages_middle; int respamiddle = list->respamiddle; if (respamiddle) { listmiddle = list->listmiddle; ilist_middle = listmiddle->ilist; numneigh_middle = listmiddle->numneigh; firstneigh_middle = listmiddle->firstneigh; pages_middle = listmiddle->pages; } int inum = 0; int npage = 0; int npnt = 0; int npage_inner = 0; int npnt_inner = 0; int npage_middle = 0; int npnt_middle = 0; for (i = 0; i < nlocal; i++) { if (pgsize - npnt < oneatom) { npnt = 0; npage++; if (npage == list->maxpage) pages = list->add_pages(); } neighptr = &pages[npage][npnt]; n = 0; if (pgsize - npnt_inner < oneatom) { npnt_inner = 0; npage_inner++; if (npage_inner == listinner->maxpage) pages_inner = listinner->add_pages(); } neighptr_inner = &pages_inner[npage_inner][npnt_inner]; n_inner = 0; if (respamiddle) { if (pgsize - npnt_middle < oneatom) { npnt_middle = 0; npage_middle++; if (npage_middle == listmiddle->maxpage) pages_middle = listmiddle->add_pages(); } neighptr_middle = &pages_middle[npage_middle][npnt_middle]; n_middle = 0; } itype = type[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; ibin = coord2bin(x[i]); // loop over all atoms in surrounding bins in stencil including self // only store pair if i < j // stores own/own pairs only once // stores own/ghost pairs on both procs for (k = 0; k < nstencil; k++) { for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) { if (j <= i) continue; jtype = type[j]; if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; if (rsq <= cutneighsq[itype][jtype]) { - if (molecular) which = find_special(special[i],nspecial[i],tag[j]); - else which = 0; - if (which == 0) neighptr[n++] = j; - else if (which > 0) neighptr[n++] = which*nall + j; + if (molecular) { + which = find_special(special[i],nspecial[i],tag[j]); + if (which >= 0) neighptr[n++] = j ^ (which << SBBITS); + } else neighptr[n++] = j; if (rsq < cut_inner_sq) { if (which == 0) neighptr_inner[n_inner++] = j; - else if (which > 0) neighptr_inner[n_inner++] = which*nall + j; + else if (which > 0) + neighptr_inner[n_inner++] = j ^ (which << SBBITS); } if (respamiddle && rsq < cut_middle_sq && rsq > cut_middle_inside_sq) { if (which == 0) neighptr_middle[n_middle++] = j; - else if (which > 0) neighptr_middle[n_middle++] = which*nall + j; + else if (which > 0) + neighptr_middle[n_middle++] = j ^ (which << SBBITS); } } } } ilist[inum] = i; firstneigh[i] = neighptr; numneigh[i] = n; npnt += n; if (n > oneatom || npnt >= pgsize) error->one("Neighbor list overflow, boost neigh_modify one or page"); ilist_inner[inum] = i; firstneigh_inner[i] = neighptr_inner; numneigh_inner[i] = n_inner; npnt_inner += n_inner; if (npnt_inner >= pgsize) error->one("Neighbor list overflow, boost neigh_modify one or page"); if (respamiddle) { ilist_middle[inum] = i; firstneigh_middle[i] = neighptr_middle; numneigh_middle[i] = n_middle; npnt_middle += n_middle; if (npnt_middle >= pgsize) error->one("Neighbor list overflow, boost neigh_modify one or page"); } inum++; } list->inum = inum; listinner->inum = inum; if (respamiddle) listmiddle->inum = inum; } /* ---------------------------------------------------------------------- multiple respa lists binned neighbor list construction with full Newton's 3rd law each owned atom i checks its own bin and other bins in Newton stencil every pair stored exactly once by some processor ------------------------------------------------------------------------- */ void Neighbor::respa_bin_newton(NeighList *list) { int i,j,k,n,itype,jtype,ibin,which,n_inner,n_middle; double xtmp,ytmp,ztmp,delx,dely,delz,rsq; int *neighptr,*neighptr_inner,*neighptr_middle; // bin local & ghost atoms bin_atoms(); // loop over each atom, storing neighbors int **special = atom->special; int **nspecial = atom->nspecial; int *tag = atom->tag; double **x = atom->x; int *type = atom->type; int *mask = atom->mask; int *molecule = atom->molecule; int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; int molecular = atom->molecular; if (includegroup) nlocal = atom->nfirst; int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; int **pages = list->pages; int nstencil = list->nstencil; int *stencil = list->stencil; NeighList *listinner = list->listinner; int *ilist_inner = listinner->ilist; int *numneigh_inner = listinner->numneigh; int **firstneigh_inner = listinner->firstneigh; int **pages_inner = listinner->pages; NeighList *listmiddle; int *ilist_middle,*numneigh_middle,**firstneigh_middle,**pages_middle; int respamiddle = list->respamiddle; if (respamiddle) { listmiddle = list->listmiddle; ilist_middle = listmiddle->ilist; numneigh_middle = listmiddle->numneigh; firstneigh_middle = listmiddle->firstneigh; pages_middle = listmiddle->pages; } int inum = 0; int npage = 0; int npnt = 0; int npage_inner = 0; int npnt_inner = 0; int npage_middle = 0; int npnt_middle = 0; for (i = 0; i < nlocal; i++) { if (pgsize - npnt < oneatom) { npnt = 0; npage++; if (npage == list->maxpage) pages = list->add_pages(); } neighptr = &pages[npage][npnt]; n = 0; if (pgsize - npnt_inner < oneatom) { npnt_inner = 0; npage_inner++; if (npage_inner == listinner->maxpage) pages_inner = listinner->add_pages(); } neighptr_inner = &pages_inner[npage_inner][npnt_inner]; n_inner = 0; if (respamiddle) { if (pgsize - npnt_middle < oneatom) { npnt_middle = 0; npage_middle++; if (npage_middle == listmiddle->maxpage) pages_middle = listmiddle->add_pages(); } neighptr_middle = &pages_middle[npage_middle][npnt_middle]; n_middle = 0; } itype = type[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; // loop over rest of atoms in i's bin, ghosts are at end of linked list // if j is owned atom, store it, since j is beyond i in linked list // if j is ghost, only store if j coords are "above and to the right" of i for (j = bins[i]; j >= 0; j = bins[j]) { if (j >= nlocal) { if (x[j][2] < ztmp) continue; if (x[j][2] == ztmp) { if (x[j][1] < ytmp) continue; if (x[j][1] == ytmp && x[j][0] < xtmp) continue; } } jtype = type[j]; if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; if (rsq <= cutneighsq[itype][jtype]) { - if (molecular) which = find_special(special[i],nspecial[i],tag[j]); - else which = 0; - if (which == 0) neighptr[n++] = j; - else if (which > 0) neighptr[n++] = which*nall + j; + if (molecular) { + which = find_special(special[i],nspecial[i],tag[j]); + if (which >= 0) neighptr[n++] = j ^ (which << SBBITS); + } else neighptr[n++] = j; if (rsq < cut_inner_sq) { if (which == 0) neighptr_inner[n_inner++] = j; - else if (which > 0) neighptr_inner[n_inner++] = which*nall + j; + else if (which > 0) neighptr_inner[n_inner++] = j ^ (which << SBBITS); } if (respamiddle && rsq < cut_middle_sq && rsq > cut_middle_inside_sq) { if (which == 0) neighptr_middle[n_middle++] = j; - else if (which > 0) neighptr_middle[n_middle++] = which*nall + j; + else if (which > 0) + neighptr_middle[n_middle++] = j ^ (which << SBBITS); } } } // loop over all atoms in other bins in stencil, store every pair ibin = coord2bin(x[i]); for (k = 0; k < nstencil; k++) { for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) { jtype = type[j]; if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; if (rsq <= cutneighsq[itype][jtype]) { - if (molecular) which = find_special(special[i],nspecial[i],tag[j]); - else which = 0; - if (which == 0) neighptr[n++] = j; - else if (which > 0) neighptr[n++] = which*nall + j; + if (molecular) { + which = find_special(special[i],nspecial[i],tag[j]); + if (which >= 0) neighptr[n++] = j ^ (which << SBBITS); + } else neighptr[n++] = j; if (rsq < cut_inner_sq) { if (which == 0) neighptr_inner[n_inner++] = j; - else if (which > 0) neighptr_inner[n_inner++] = which*nall + j; + else if (which > 0) + neighptr_inner[n_inner++] = j ^ (which << SBBITS); } if (respamiddle && rsq < cut_middle_sq && rsq > cut_middle_inside_sq) { if (which == 0) neighptr_middle[n_middle++] = j; - else if (which > 0) neighptr_middle[n_middle++] = which*nall + j; + else if (which > 0) + neighptr_middle[n_middle++] = j ^ (which << SBBITS); } } } } ilist[inum] = i; firstneigh[i] = neighptr; numneigh[i] = n; npnt += n; if (n > oneatom || npnt >= pgsize) error->one("Neighbor list overflow, boost neigh_modify one or page"); ilist_inner[inum] = i; firstneigh_inner[i] = neighptr_inner; numneigh_inner[i] = n_inner; npnt_inner += n_inner; if (npnt_inner >= pgsize) error->one("Neighbor list overflow, boost neigh_modify one or page"); if (respamiddle) { ilist_middle[inum] = i; firstneigh_middle[i] = neighptr_middle; numneigh_middle[i] = n_middle; npnt_middle += n_middle; if (npnt_middle >= pgsize) error->one("Neighbor list overflow, boost neigh_modify one or page"); } inum++; } list->inum = inum; listinner->inum = inum; if (respamiddle) listmiddle->inum = inum; } /* ---------------------------------------------------------------------- multiple respa lists binned neighbor list construction with Newton's 3rd law for triclinic each owned atom i checks its own bin and other bins in triclinic stencil every pair stored exactly once by some processor ------------------------------------------------------------------------- */ void Neighbor::respa_bin_newton_tri(NeighList *list) { int i,j,k,n,itype,jtype,ibin,which,n_inner,n_middle; double xtmp,ytmp,ztmp,delx,dely,delz,rsq; int *neighptr,*neighptr_inner,*neighptr_middle; // bin local & ghost atoms bin_atoms(); // loop over each atom, storing neighbors int **special = atom->special; int **nspecial = atom->nspecial; int *tag = atom->tag; double **x = atom->x; int *type = atom->type; int *mask = atom->mask; int *molecule = atom->molecule; int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; int molecular = atom->molecular; if (includegroup) nlocal = atom->nfirst; int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; int **pages = list->pages; int nstencil = list->nstencil; int *stencil = list->stencil; NeighList *listinner = list->listinner; int *ilist_inner = listinner->ilist; int *numneigh_inner = listinner->numneigh; int **firstneigh_inner = listinner->firstneigh; int **pages_inner = listinner->pages; NeighList *listmiddle; int *ilist_middle,*numneigh_middle,**firstneigh_middle,**pages_middle; int respamiddle = list->respamiddle; if (respamiddle) { listmiddle = list->listmiddle; ilist_middle = listmiddle->ilist; numneigh_middle = listmiddle->numneigh; firstneigh_middle = listmiddle->firstneigh; pages_middle = listmiddle->pages; } int inum = 0; int npage = 0; int npnt = 0; int npage_inner = 0; int npnt_inner = 0; int npage_middle = 0; int npnt_middle = 0; for (i = 0; i < nlocal; i++) { if (pgsize - npnt < oneatom) { npnt = 0; npage++; if (npage == list->maxpage) pages = list->add_pages(); } neighptr = &pages[npage][npnt]; n = 0; if (pgsize - npnt_inner < oneatom) { npnt_inner = 0; npage_inner++; if (npage_inner == listinner->maxpage) pages_inner = listinner->add_pages(); } neighptr_inner = &pages_inner[npage_inner][npnt_inner]; n_inner = 0; if (respamiddle) { if (pgsize - npnt_middle < oneatom) { npnt_middle = 0; npage_middle++; if (npage_middle == listmiddle->maxpage) pages_middle = listmiddle->add_pages(); } neighptr_middle = &pages_middle[npage_middle][npnt_middle]; n_middle = 0; } itype = type[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; // loop over all atoms in bins in stencil // pairs for atoms j "below" i are excluded // below = lower z or (equal z and lower y) or (equal zy and lower x) // (equal zyx and j <= i) // latter excludes self-self interaction but allows superposed atoms ibin = coord2bin(x[i]); for (k = 0; k < nstencil; k++) { for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) { if (x[j][2] < ztmp) continue; if (x[j][2] == ztmp) { if (x[j][1] < ytmp) continue; if (x[j][1] == ytmp) { if (x[j][0] < xtmp) continue; if (x[j][0] == xtmp && j <= i) continue; } } jtype = type[j]; if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; if (rsq <= cutneighsq[itype][jtype]) { - if (molecular) which = find_special(special[i],nspecial[i],tag[j]); - else which = 0; - if (which == 0) neighptr[n++] = j; - else if (which > 0) neighptr[n++] = which*nall + j; + if (molecular) { + which = find_special(special[i],nspecial[i],tag[j]); + if (which >= 0) neighptr[n++] = j ^ (which << SBBITS); + } else neighptr[n++] = j; if (rsq < cut_inner_sq) { if (which == 0) neighptr_inner[n_inner++] = j; - else if (which > 0) neighptr_inner[n_inner++] = which*nall + j; + else if (which > 0) + neighptr_inner[n_inner++] = j ^ (which << SBBITS); } if (respamiddle && rsq < cut_middle_sq && rsq > cut_middle_inside_sq) { if (which == 0) neighptr_middle[n_middle++] = j; - else if (which > 0) neighptr_middle[n_middle++] = which*nall + j; + else if (which > 0) + neighptr_middle[n_middle++] = j ^ (which << SBBITS); } } } } ilist[inum] = i; firstneigh[i] = neighptr; numneigh[i] = n; npnt += n; if (n > oneatom || npnt >= pgsize) error->one("Neighbor list overflow, boost neigh_modify one or page"); ilist_inner[inum] = i; firstneigh_inner[i] = neighptr_inner; numneigh_inner[i] = n_inner; npnt_inner += n_inner; if (npnt_inner >= pgsize) error->one("Neighbor list overflow, boost neigh_modify one or page"); if (respamiddle) { ilist_middle[inum] = i; firstneigh_middle[i] = neighptr_middle; numneigh_middle[i] = n_middle; npnt_middle += n_middle; if (npnt_middle >= pgsize) error->one("Neighbor list overflow, boost neigh_modify one or page"); } inum++; } list->inum = inum; listinner->inum = inum; if (respamiddle) listmiddle->inum = inum; } diff --git a/src/neighbor.cpp b/src/neighbor.cpp index 86cad4b06..fc4f1125e 100644 --- a/src/neighbor.cpp +++ b/src/neighbor.cpp @@ -1,1741 +1,1743 @@ /* ---------------------------------------------------------------------- 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 (triclinic and multi-neigh) : Pieter in 't Veld (SNL) ------------------------------------------------------------------------- */ #include "lmptype.h" #include "mpi.h" #include "math.h" #include "stdlib.h" #include "string.h" #include "neighbor.h" #include "neigh_list.h" #include "neigh_request.h" #include "atom.h" #include "atom_vec.h" #include "comm.h" #include "force.h" #include "pair.h" #include "domain.h" #include "group.h" #include "modify.h" #include "fix.h" #include "compute.h" #include "update.h" #include "respa.h" #include "output.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define RQDELTA 1 #define EXDELTA 1 #define LB_FACTOR 1.5 #define SMALL 1.0e-6 #define BIG 1.0e20 #define CUT2BIN_RATIO 100 #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) enum{NSQ,BIN,MULTI}; // also in neigh_list.cpp //#define NEIGH_LIST_DEBUG 1 /* ---------------------------------------------------------------------- */ Neighbor::Neighbor(LAMMPS *lmp) : Pointers(lmp) { MPI_Comm_rank(world,&me); MPI_Comm_size(world,&nprocs); style = BIN; every = 1; delay = 10; dist_check = 1; pgsize = 100000; oneatom = 2000; binsizeflag = 0; build_once = 0; cutneighsq = NULL; cutneighghostsq = NULL; cuttype = NULL; cuttypesq = NULL; fixchecklist = NULL; // coords at last neighboring maxhold = 0; xhold = NULL; // binning maxhead = 0; binhead = NULL; maxbin = 0; bins = NULL; // pair exclusion list info includegroup = 0; nex_type = maxex_type = 0; ex1_type = ex2_type = NULL; ex_type = NULL; nex_group = maxex_group = 0; ex1_group = ex2_group = ex1_bit = ex2_bit = NULL; nex_mol = maxex_mol = 0; ex_mol_group = ex_mol_bit = NULL; // pair lists maxatom = 0; nblist = nglist = nslist = 0; nlist = 0; lists = NULL; pair_build = NULL; stencil_create = NULL; blist = glist = slist = NULL; anyghostlist = 0; nrequest = maxrequest = 0; requests = NULL; old_style = BIN; old_triclinic = 0; old_nrequest = 0; old_requests = NULL; // bond lists maxbond = 0; bondlist = NULL; maxangle = 0; anglelist = NULL; maxdihedral = 0; dihedrallist = NULL; maximproper = 0; improperlist = NULL; } /* ---------------------------------------------------------------------- */ Neighbor::~Neighbor() { memory->destroy(cutneighsq); memory->destroy(cutneighghostsq); delete [] cuttype; delete [] cuttypesq; delete [] fixchecklist; memory->destroy(xhold); memory->destroy(binhead); memory->destroy(bins); memory->destroy(ex1_type); memory->destroy(ex2_type); memory->destroy(ex_type); memory->destroy(ex1_group); memory->destroy(ex2_group); delete [] ex1_bit; delete [] ex2_bit; memory->destroy(ex_mol_group); delete [] ex_mol_bit; for (int i = 0; i < nlist; i++) delete lists[i]; delete [] lists; delete [] pair_build; delete [] stencil_create; delete [] blist; delete [] glist; delete [] slist; for (int i = 0; i < nrequest; i++) delete requests[i]; memory->sfree(requests); for (int i = 0; i < old_nrequest; i++) delete old_requests[i]; memory->sfree(old_requests); memory->destroy(bondlist); memory->destroy(anglelist); memory->destroy(dihedrallist); memory->destroy(improperlist); } /* ---------------------------------------------------------------------- */ void Neighbor::init() { int i,j,m,n; ncalls = ndanger = 0; dimension = domain->dimension; triclinic = domain->triclinic; newton_pair = force->newton_pair; // error check if (delay > 0 && (delay % every) != 0) error->all("Neighbor delay must be 0 or multiple of every setting"); if (pgsize < 10*oneatom) error->all("Neighbor page size must be >= 10x the one atom setting"); // ------------------------------------------------------------------ // settings // bbox lo/hi = bounding box of entire domain, stored by Domain if (triclinic == 0) { bboxlo = domain->boxlo; bboxhi = domain->boxhi; } else { bboxlo = domain->boxlo_bound; bboxhi = domain->boxhi_bound; } // set neighbor cutoffs (force cutoff + skin) // trigger determines when atoms migrate and neighbor lists are rebuilt // needs to be non-zero for migration distance check // even if pair = NULL and no neighbor lists are used // cutneigh = force cutoff + skin if cutforce > 0, else cutneigh = 0 triggersq = 0.25*skin*skin; boxcheck = 0; if (domain->box_change && (domain->xperiodic || domain->yperiodic || (dimension == 3 && domain->zperiodic))) boxcheck = 1; n = atom->ntypes; if (cutneighsq == NULL) { memory->create(cutneighsq,n+1,n+1,"neigh:cutneighsq"); memory->create(cutneighghostsq,n+1,n+1,"neigh:cutneighghostsq"); cuttype = new double[n+1]; cuttypesq = new double[n+1]; } double cutoff,delta,cut; cutneighmin = BIG; cutneighmax = 0.0; for (i = 1; i <= n; i++) { cuttype[i] = cuttypesq[i] = 0.0; for (j = 1; j <= n; j++) { if (force->pair) cutoff = sqrt(force->pair->cutsq[i][j]); else cutoff = 0.0; if (cutoff > 0.0) delta = skin; else delta = 0.0; cut = cutoff + delta; cutneighsq[i][j] = cut*cut; cuttype[i] = MAX(cuttype[i],cut); cuttypesq[i] = MAX(cuttypesq[i],cut*cut); cutneighmin = MIN(cutneighmin,cut); cutneighmax = MAX(cutneighmax,cut); if (force->pair && force->pair->ghostneigh) { cut = force->pair->cutghost[i][j] + skin; cutneighghostsq[i][j] = cut*cut; } } } cutneighmaxsq = cutneighmax * cutneighmax; // check other classes that can induce reneighboring in decide() // don't check if build_once is set restart_check = 0; if (output->restart_every) restart_check = 1; delete [] fixchecklist; fixchecklist = NULL; fixchecklist = new int[modify->nfix]; fix_check = 0; for (i = 0; i < modify->nfix; i++) if (modify->fix[i]->force_reneighbor) fixchecklist[fix_check++] = i; must_check = 0; if (restart_check || fix_check) must_check = 1; if (build_once) must_check = 0; // set special_flag for 1-2, 1-3, 1-4 neighbors // flag[0] is not used, flag[1] = 1-2, flag[2] = 1-3, flag[3] = 1-4 // flag = 0 if both LJ/Coulomb special values are 0.0 // flag = 1 if both LJ/Coulomb special values are 1.0 // flag = 2 otherwise or if KSpace solver is enabled // pairwise portion of KSpace solver uses all 1-2,1-3,1-4 neighbors if (force->special_lj[1] == 0.0 && force->special_coul[1] == 0.0) special_flag[1] = 0; else if (force->special_lj[1] == 1.0 && force->special_coul[1] == 1.0) special_flag[1] = 1; else special_flag[1] = 2; if (force->special_lj[2] == 0.0 && force->special_coul[2] == 0.0) special_flag[2] = 0; else if (force->special_lj[2] == 1.0 && force->special_coul[2] == 1.0) special_flag[2] = 1; else special_flag[2] = 2; if (force->special_lj[3] == 0.0 && force->special_coul[3] == 0.0) special_flag[3] = 0; else if (force->special_lj[3] == 1.0 && force->special_coul[3] == 1.0) special_flag[3] = 1; else special_flag[3] = 2; if (force->kspace) special_flag[1] = special_flag[2] = special_flag[3] = 2; // maxwt = max multiplicative factor on atom indices stored in neigh list maxwt = 0; if (special_flag[1] == 2) maxwt = 2; if (special_flag[2] == 2) maxwt = 3; if (special_flag[3] == 2) maxwt = 4; // rRESPA cutoffs int respa = 0; if (update->whichflag == 1 && strcmp(update->integrate_style,"respa") == 0) { if (((Respa *) update->integrate)->level_inner >= 0) respa = 1; if (((Respa *) update->integrate)->level_middle >= 0) respa = 2; } if (respa) { double *cut_respa = ((Respa *) update->integrate)->cutoff; cut_inner_sq = (cut_respa[1] + skin) * (cut_respa[1] + skin); cut_middle_sq = (cut_respa[3] + skin) * (cut_respa[3] + skin); cut_middle_inside_sq = (cut_respa[0] - skin) * (cut_respa[0] - skin); } // ------------------------------------------------------------------ // xhold, bins, exclusion lists // free xhold and bins if not needed for this run if (dist_check == 0) { memory->destroy(xhold); maxhold = 0; xhold = NULL; } if (style == NSQ) { memory->destroy(bins); memory->destroy(binhead); maxbin = maxhead = 0; binhead = NULL; bins = NULL; } // 1st time allocation of xhold and bins if (dist_check) { if (maxhold == 0) { maxhold = atom->nmax; memory->create(xhold,maxhold,3,"neigh:xhold"); } } if (style != NSQ) { if (maxbin == 0) { maxbin = atom->nmax; memory->create(bins,maxbin,"bins"); } } // exclusion lists for type, group, molecule settings from neigh_modify n = atom->ntypes; if (nex_type == 0 && nex_group == 0 && nex_mol == 0) exclude = 0; else exclude = 1; if (nex_type) { memory->destroy(ex_type); memory->create(ex_type,n+1,n+1,"neigh:ex_type"); for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) ex_type[i][j] = 0; for (i = 0; i < nex_type; i++) { if (ex1_type[i] <= 0 || ex1_type[i] > n || ex2_type[i] <= 0 || ex2_type[i] > n) error->all("Invalid atom type in neighbor exclusion list"); ex_type[ex1_type[i]][ex2_type[i]] = 1; ex_type[ex2_type[i]][ex1_type[i]] = 1; } } if (nex_group) { delete [] ex1_bit; delete [] ex2_bit; ex1_bit = new int[nex_group]; ex2_bit = new int[nex_group]; for (i = 0; i < nex_group; i++) { ex1_bit[i] = group->bitmask[ex1_group[i]]; ex2_bit[i] = group->bitmask[ex2_group[i]]; } } if (nex_mol) { delete [] ex_mol_bit; ex_mol_bit = new int[nex_mol]; for (i = 0; i < nex_mol; i++) ex_mol_bit[i] = group->bitmask[ex_mol_group[i]]; } // ------------------------------------------------------------------ // pairwise lists // test if pairwise lists need to be re-created // no need to re-create if: // neigh style and triclinic has not changed and // current requests = old requests int same = 1; if (style != old_style) same = 0; if (triclinic != old_triclinic) same = 0; if (nrequest != old_nrequest) same = 0; else for (i = 0; i < nrequest; i++) if (requests[i]->identical(old_requests[i]) == 0) same = 0; #ifdef NEIGH_LIST_DEBUG if (comm->me == 0) printf("SAME flag %d\n",same); #endif // if old and new are not the same, create new pairwise lists if (!same) { // delete old lists and create new ones for (i = 0; i < nlist; i++) delete lists[i]; delete [] lists; delete [] pair_build; delete [] stencil_create; nlist = nrequest; lists = new NeighList*[nlist]; pair_build = new PairPtr[nlist]; stencil_create = new StencilPtr[nlist]; // create individual lists, one per request // copy dnum setting from request to list // pass list ptr back to requestor (except for Command class) for (i = 0; i < nlist; i++) { lists[i] = new NeighList(lmp,pgsize); lists[i]->index = i; lists[i]->dnum = requests[i]->dnum; if (requests[i]->pair) { Pair *pair = (Pair *) requests[i]->requestor; pair->init_list(requests[i]->id,lists[i]); } else if (requests[i]->fix) { Fix *fix = (Fix *) requests[i]->requestor; fix->init_list(requests[i]->id,lists[i]); } else if (requests[i]->compute) { Compute *compute = (Compute *) requests[i]->requestor; compute->init_list(requests[i]->id,lists[i]); } } // detect lists that are connected to other lists // if-then-else sequence is important // since don't want to re-process skip or copy lists further down // copy: point this list at request->otherlist, could be a skip list // skip: point this list at request->otherlist, copy skip info from request // half_from_full: point this list at preceeding full list // granhistory: set preceeding list's listgranhistory to this list // also set preceeding list's ptr to FixShearHistory // respaouter: point this list at preceeding 1/2 inner/middle lists // pair and half: if there is a full non-occasional non-skip list // change this list to half_from_full and point at the full list // parent could be copy list or pair or fix // fix/compute requests: // kind of request = half or full, occasional or not doesn't matter // if request = half and non-skip pair half/respaouter exists, // become copy of that list // if request = full and non-skip pair full exists, // become copy of that list // if request = half and non-skip pair full exists, // become half_from_full of that list // if no matches, do nothing, fix/compute list will be built directly // ok if parent is copy list for (i = 0; i < nlist; i++) { if (requests[i]->copy) lists[i]->listcopy = lists[requests[i]->otherlist]; else if (requests[i]->skip) { lists[i]->listskip = lists[requests[i]->otherlist]; lists[i]->copy_skip_info(requests[i]->iskip,requests[i]->ijskip); } else if (requests[i]->half_from_full) lists[i]->listfull = lists[i-1]; else if (requests[i]->granhistory) { lists[i-1]->listgranhistory = lists[i]; for (int ifix = 0; ifix < modify->nfix; ifix++) if (strcmp(modify->fix[ifix]->style,"SHEAR_HISTORY") == 0) lists[i-1]->fix_history = (FixShearHistory *) modify->fix[ifix]; } else if (requests[i]->respaouter) { if (requests[i-1]->respainner) { lists[i]->respamiddle = 0; lists[i]->listinner = lists[i-1]; } else { lists[i]->respamiddle = 1; lists[i]->listmiddle = lists[i-1]; lists[i]->listinner = lists[i-2]; } } else if (requests[i]->pair && requests[i]->half) { for (j = 0; j < nlist; j++) if (requests[j]->full && requests[j]->occasional == 0 && requests[j]->skip == 0) break; if (j < nlist) { requests[i]->half = 0; requests[i]->half_from_full = 1; lists[i]->listfull = lists[j]; } } else if (requests[i]->fix || requests[i]->compute) { for (j = 0; j < nlist; j++) { if (requests[i]->half && requests[j]->pair && requests[j]->skip == 0 && requests[j]->half) break; if (requests[i]->full && requests[j]->pair && requests[j]->skip == 0 && requests[j]->full) break; if (requests[i]->half && requests[j]->pair && requests[j]->skip == 0 && requests[j]->respaouter) break; } if (j < nlist) { requests[i]->copy = 1; lists[i]->listcopy = lists[j]; } else { for (j = 0; j < nlist; j++) { if (requests[i]->half && requests[j]->pair && requests[j]->skip == 0 && requests[j]->full) break; } if (j < nlist) { requests[i]->half = 0; requests[i]->half_from_full = 1; lists[i]->listfull = lists[j]; } } } } // set ptrs to pair_build and stencil_create functions for each list // ptrs set to NULL if not set explicitly for (i = 0; i < nlist; i++) { choose_build(i,requests[i]); if (style != NSQ) choose_stencil(i,requests[i]); else stencil_create[i] = NULL; } // set each list's build/grow/stencil/ghost flags based on neigh request // buildflag = 1 if its pair_build() invoked every reneighbor // growflag = 1 if it stores atom-based arrays and pages // stencilflag = 1 if it stores stencil arrays // ghostflag = 1 if it stores neighbors of ghosts // anyghostlist = 1 if any non-occasional list stores neighbors of ghosts anyghostlist = 0; for (i = 0; i < nlist; i++) { lists[i]->buildflag = 1; if (pair_build[i] == NULL) lists[i]->buildflag = 0; if (requests[i]->occasional) lists[i]->buildflag = 0; lists[i]->growflag = 1; if (requests[i]->copy) lists[i]->growflag = 0; lists[i]->stencilflag = 1; if (style == NSQ) lists[i]->stencilflag = 0; if (stencil_create[i] == NULL) lists[i]->stencilflag = 0; lists[i]->ghostflag = 0; if (requests[i]->ghost) lists[i]->ghostflag = 1; if (requests[i]->ghost && !requests[i]->occasional) anyghostlist = 1; } #ifdef NEIGH_LIST_DEBUG for (i = 0; i < nlist; i++) lists[i]->print_attributes(); #endif // allocate atom arrays and 1st pages of lists that store them maxatom = atom->nmax; for (i = 0; i < nlist; i++) if (lists[i]->growflag) { lists[i]->grow(maxatom); lists[i]->add_pages(); } // setup 3 vectors of pairwise neighbor lists // blist = lists whose pair_build() is invoked every reneighbor // glist = lists who store atom arrays which are used every reneighbor // slist = lists who store stencil arrays which are used every reneighbor // blist and glist vectors are used by neighbor::build() // slist vector is used by neighbor::setup_bins() nblist = nglist = nslist = 0; delete [] blist; delete [] glist; delete [] slist; blist = new int[nlist]; glist = new int[nlist]; slist = new int[nlist]; for (i = 0; i < nlist; i++) { if (lists[i]->buildflag) blist[nblist++] = i; if (lists[i]->growflag && requests[i]->occasional == 0) glist[nglist++] = i; if (lists[i]->stencilflag && requests[i]->occasional == 0) slist[nslist++] = i; } #ifdef NEIGH_LIST_DEBUG print_lists_of_lists(); #endif // reorder build vector if necessary // relevant for lists that copy/skip/half-full from parent // the derived list must appear in blist after the parent list // no occasional lists are in build vector // swap two lists within blist when dependency is mis-ordered // done when entire pass thru blist results in no swaps int done = 0; while (!done) { done = 1; for (i = 0; i < nblist; i++) { NeighList *ptr = NULL; if (lists[blist[i]]->listfull) ptr = lists[blist[i]]->listfull; if (lists[blist[i]]->listcopy) ptr = lists[blist[i]]->listcopy; if (lists[blist[i]]->listskip) ptr = lists[blist[i]]->listskip; if (ptr == NULL) continue; for (m = 0; m < nlist; m++) if (ptr == lists[m]) break; for (j = 0; j < nblist; j++) if (m == blist[j]) break; if (j < i) continue; int tmp = blist[i]; blist[i] = blist[j]; blist[j] = tmp; done = 0; break; } } #ifdef NEIGH_LIST_DEBUG print_lists_of_lists(); #endif } // delete old requests // copy current requests and style to old for next run for (i = 0; i < old_nrequest; i++) delete old_requests[i]; memory->sfree(old_requests); old_nrequest = nrequest; old_requests = requests; nrequest = maxrequest = 0; requests = NULL; old_style = style; old_triclinic = triclinic; // ------------------------------------------------------------------ // topology lists // 1st time allocation of topology lists if (atom->molecular && atom->nbonds && maxbond == 0) { if (nprocs == 1) maxbond = atom->nbonds; else maxbond = static_cast (LB_FACTOR * atom->nbonds / nprocs); memory->create(bondlist,maxbond,3,"neigh:bondlist"); } if (atom->molecular && atom->nangles && maxangle == 0) { if (nprocs == 1) maxangle = atom->nangles; else maxangle = static_cast (LB_FACTOR * atom->nangles / nprocs); memory->create(anglelist,maxangle,4,"neigh:anglelist"); } if (atom->molecular && atom->ndihedrals && maxdihedral == 0) { if (nprocs == 1) maxdihedral = atom->ndihedrals; else maxdihedral = static_cast (LB_FACTOR * atom->ndihedrals / nprocs); memory->create(dihedrallist,maxdihedral,5,"neigh:dihedrallist"); } if (atom->molecular && atom->nimpropers && maximproper == 0) { if (nprocs == 1) maximproper = atom->nimpropers; else maximproper = static_cast (LB_FACTOR * atom->nimpropers / nprocs); memory->create(improperlist,maximproper,5,"neigh:improperlist"); } // set flags that determine which topology neighboring routines to use // SHAKE sets bonds and angles negative // bond_quartic sets bonds to 0 // delete_bonds sets all interactions negative int bond_off = 0; int angle_off = 0; for (i = 0; i < modify->nfix; i++) if (strcmp(modify->fix[i]->style,"shake") == 0) bond_off = angle_off = 1; if (force->bond && force->bond_match("quartic")) bond_off = 1; if (atom->avec->bonds_allow) { for (i = 0; i < atom->nlocal; i++) { if (bond_off) break; for (m = 0; m < atom->num_bond[i]; m++) if (atom->bond_type[i][m] <= 0) bond_off = 1; } } if (atom->avec->angles_allow) { for (i = 0; i < atom->nlocal; i++) { if (angle_off) break; for (m = 0; m < atom->num_angle[i]; m++) if (atom->angle_type[i][m] <= 0) angle_off = 1; } } int dihedral_off = 0; if (atom->avec->dihedrals_allow) { for (i = 0; i < atom->nlocal; i++) { if (dihedral_off) break; for (m = 0; m < atom->num_dihedral[i]; m++) if (atom->dihedral_type[i][m] <= 0) dihedral_off = 1; } } int improper_off = 0; if (atom->avec->impropers_allow) { for (i = 0; i < atom->nlocal; i++) { if (improper_off) break; for (m = 0; m < atom->num_improper[i]; m++) if (atom->improper_type[i][m] <= 0) improper_off = 1; } } // set ptrs to topology build functions if (bond_off) bond_build = &Neighbor::bond_partial; else bond_build = &Neighbor::bond_all; if (angle_off) angle_build = &Neighbor::angle_partial; else angle_build = &Neighbor::angle_all; if (dihedral_off) dihedral_build = &Neighbor::dihedral_partial; else dihedral_build = &Neighbor::dihedral_all; if (improper_off) improper_build = &Neighbor::improper_partial; else improper_build = &Neighbor::improper_all; // set topology neighbor list counts to 0 // in case all are turned off but potential is still defined nbondlist = nanglelist = ndihedrallist = nimproperlist = 0; } /* ---------------------------------------------------------------------- */ int Neighbor::request(void *requestor) { if (nrequest == maxrequest) { maxrequest += RQDELTA; requests = (NeighRequest **) memory->srealloc(requests,maxrequest*sizeof(NeighRequest *), "neighbor:requests"); } requests[nrequest] = new NeighRequest(lmp); requests[nrequest]->requestor = requestor; nrequest++; return nrequest-1; } /* ---------------------------------------------------------------------- determine which pair_build function each neigh list needs based on settings of neigh request copy -> copy_from function skip -> granular function if gran with granhistory, respa function if respaouter, skip_from function for everything else half_from_full, half, full, gran, respaouter -> choose by newton and rq->newton and tri settings style NSQ options = newton off, newton on style BIN options = newton off, newton on and not tri, newton on and tri stlye MULTI options = same options as BIN if none of these, ptr = NULL since pair_build is not invoked for this list use "else if" b/c skip,copy can be set in addition to half,full,etc ------------------------------------------------------------------------- */ void Neighbor::choose_build(int index, NeighRequest *rq) { PairPtr pb = NULL; if (rq->copy) pb = &Neighbor::copy_from; else if (rq->skip) { if (rq->gran && lists[index]->listgranhistory) pb = &Neighbor::skip_from_granular; else if (rq->respaouter) pb = &Neighbor::skip_from_respa; else pb = &Neighbor::skip_from; } else if (rq->half_from_full) { if (newton_pair == 0) pb = &Neighbor::half_from_full_no_newton; else if (newton_pair == 1) pb = &Neighbor::half_from_full_newton; } else if (rq->half) { if (style == NSQ) { if (rq->newton == 0) { if (newton_pair == 0) pb = &Neighbor::half_nsq_no_newton; else if (newton_pair == 1) pb = &Neighbor::half_nsq_newton; } else if (rq->newton == 1) { pb = &Neighbor::half_nsq_newton; } else if (rq->newton == 2) { pb = &Neighbor::half_nsq_no_newton; } } else if (style == BIN) { if (rq->newton == 0) { if (newton_pair == 0) pb = &Neighbor::half_bin_no_newton; else if (triclinic == 0) pb = &Neighbor::half_bin_newton; else if (triclinic == 1) pb = &Neighbor::half_bin_newton_tri; } else if (rq->newton == 1) { if (triclinic == 0) pb = &Neighbor::half_bin_newton; else if (triclinic == 1) pb = &Neighbor::half_bin_newton_tri; } else if (rq->newton == 2) pb = &Neighbor::half_bin_no_newton; } else if (style == MULTI) { if (rq->newton == 0) { if (newton_pair == 0) pb = &Neighbor::half_multi_no_newton; else if (triclinic == 0) pb = &Neighbor::half_multi_newton; else if (triclinic == 1) pb = &Neighbor::half_multi_newton_tri; } else if (rq->newton == 1) { if (triclinic == 0) pb = &Neighbor::half_multi_newton; else if (triclinic == 1) pb = &Neighbor::half_multi_newton_tri; } else if (rq->newton == 2) pb = &Neighbor::half_multi_no_newton; } } else if (rq->full) { if (style == NSQ) { if (rq->ghost == 0) pb = &Neighbor::full_nsq; else if (includegroup) error->all("Neighbor include group not allowed with ghost neighbors"); else if (rq->ghost == 1) pb = &Neighbor::full_nsq_ghost; } else if (style == BIN) { if (rq->ghost == 0) pb = &Neighbor::full_bin; else if (includegroup) error->all("Neighbor include group not allowed with ghost neighbors"); else if (rq->ghost == 1) pb = &Neighbor::full_bin_ghost; } else if (style == MULTI) { if (rq->ghost == 0) pb = &Neighbor::full_multi; else error->all("Neighbor multi not yet enabled for ghost neighbors"); } } else if (rq->gran) { if (style == NSQ) { if (newton_pair == 0) pb = &Neighbor::granular_nsq_no_newton; else if (newton_pair == 1) pb = &Neighbor::granular_nsq_newton; } else if (style == BIN) { if (newton_pair == 0) pb = &Neighbor::granular_bin_no_newton; else if (triclinic == 0) pb = &Neighbor::granular_bin_newton; else if (triclinic == 1) pb = &Neighbor::granular_bin_newton_tri; } else if (style == MULTI) error->all("Neighbor multi not yet enabled for granular"); } else if (rq->respaouter) { if (style == NSQ) { if (newton_pair == 0) pb = &Neighbor::respa_nsq_no_newton; else if (newton_pair == 1) pb = &Neighbor::respa_nsq_newton; } else if (style == BIN) { if (newton_pair == 0) pb = &Neighbor::respa_bin_no_newton; else if (triclinic == 0) pb = &Neighbor::respa_bin_newton; else if (triclinic == 1) pb = &Neighbor::respa_bin_newton_tri; } else if (style == MULTI) error->all("Neighbor multi not yet enabled for rRESPA"); } // general error check if (rq->ghost && !rq->full) error->all("Neighbors of ghost atoms only allowed for full neighbor lists"); pair_build[index] = pb; } /* ---------------------------------------------------------------------- determine which stencil_create function each neigh list needs based on settings of neigh request, only called if style != NSQ skip or copy or half_from_full -> no stencil half, gran, respaouter, full -> choose by newton and tri and dimension if none of these, ptr = NULL since this list needs no stencils use "else if" b/c skip,copy can be set in addition to half,full,etc ------------------------------------------------------------------------- */ void Neighbor::choose_stencil(int index, NeighRequest *rq) { StencilPtr sc = NULL; if (rq->skip || rq->copy || rq->half_from_full) sc = NULL; else if (rq->half || rq->gran || rq->respaouter) { if (style == BIN) { if (rq->newton == 0) { if (newton_pair == 0) { if (dimension == 2) sc = &Neighbor::stencil_half_bin_2d_no_newton; else if (dimension == 3) sc = &Neighbor::stencil_half_bin_3d_no_newton; } else if (triclinic == 0) { if (dimension == 2) sc = &Neighbor::stencil_half_bin_2d_newton; else if (dimension == 3) sc = &Neighbor::stencil_half_bin_3d_newton; } else if (triclinic == 1) { if (dimension == 2) sc = &Neighbor::stencil_half_bin_2d_newton_tri; else if (dimension == 3) sc = &Neighbor::stencil_half_bin_3d_newton_tri; } } else if (rq->newton == 1) { if (triclinic == 0) { if (dimension == 2) sc = &Neighbor::stencil_half_bin_2d_newton; else if (dimension == 3) sc = &Neighbor::stencil_half_bin_3d_newton; } else if (triclinic == 1) { if (dimension == 2) sc = &Neighbor::stencil_half_bin_2d_newton_tri; else if (dimension == 3) sc = &Neighbor::stencil_half_bin_3d_newton_tri; } } else if (rq->newton == 2) { if (dimension == 2) sc = &Neighbor::stencil_half_bin_2d_no_newton; else if (dimension == 3) sc = &Neighbor::stencil_half_bin_3d_no_newton; } } else if (style == MULTI) { if (rq->newton == 0) { if (newton_pair == 0) { if (dimension == 2) sc = &Neighbor::stencil_half_multi_2d_no_newton; else if (dimension == 3) sc = &Neighbor::stencil_half_multi_3d_no_newton; } else if (triclinic == 0) { if (dimension == 2) sc = &Neighbor::stencil_half_multi_2d_newton; else if (dimension == 3) sc = &Neighbor::stencil_half_multi_3d_newton; } else if (triclinic == 1) { if (dimension == 2) sc = &Neighbor::stencil_half_multi_2d_newton_tri; else if (dimension == 3) sc = &Neighbor::stencil_half_multi_3d_newton_tri; } } else if (rq->newton == 1) { if (triclinic == 0) { if (dimension == 2) sc = &Neighbor::stencil_half_multi_2d_newton; else if (dimension == 3) sc = &Neighbor::stencil_half_multi_3d_newton; } else if (triclinic == 1) { if (dimension == 2) sc = &Neighbor::stencil_half_multi_2d_newton_tri; else if (dimension == 3) sc = &Neighbor::stencil_half_multi_3d_newton_tri; } } else if (rq->newton == 2) { if (dimension == 2) sc = &Neighbor::stencil_half_multi_2d_no_newton; else if (dimension == 3) sc = &Neighbor::stencil_half_multi_3d_no_newton; } } } else if (rq->full) { if (style == BIN) { if (dimension == 2) { if (rq->ghost) sc = &Neighbor::stencil_full_ghost_bin_2d; else sc = &Neighbor::stencil_full_bin_2d; } else if (dimension == 3) { if (rq->ghost) sc = &Neighbor::stencil_full_ghost_bin_3d; else sc = &Neighbor::stencil_full_bin_3d; } } else if (style == MULTI) { if (dimension == 2) sc = &Neighbor::stencil_full_multi_2d; else if (dimension == 3) sc = &Neighbor::stencil_full_multi_3d; } } stencil_create[index] = sc; } /* ---------------------------------------------------------------------- */ void Neighbor::print_lists_of_lists() { if (comm->me == 0) { printf("Build lists = %d: ",nblist); for (int i = 0; i < nblist; i++) printf("%d ",blist[i]); printf("\n"); printf("Grow lists = %d: ",nglist); for (int i = 0; i < nglist; i++) printf("%d ",glist[i]); printf("\n"); printf("Stencil lists = %d: ",nslist); for (int i = 0; i < nslist; i++) printf("%d ",slist[i]); printf("\n"); } } /* ---------------------------------------------------------------------- */ int Neighbor::decide() { if (must_check) { int n = update->ntimestep; if (restart_check && n == output->next_restart) return 1; for (int i = 0; i < fix_check; i++) if (n == modify->fix[fixchecklist[i]]->next_reneighbor) return 1; } ago++; if (ago >= delay && ago % every == 0) { if (build_once) return 0; if (dist_check == 0) return 1; return check_distance(); } else return 0; } /* ---------------------------------------------------------------------- if any atom moved trigger distance (half of neighbor skin) return 1 shrink trigger distance if box size has changed conservative shrink procedure: compute distance each of 8 corners of box has moved since last reneighbor reduce skin distance by sum of 2 largest of the 8 values new trigger = 1/2 of reduced skin distance for orthogonal box, only need 2 lo/hi corners for triclinic, need all 8 corners since deformations can displace all 8 ------------------------------------------------------------------------- */ int Neighbor::check_distance() { double delx,dely,delz,rsq; double delta,deltasq,delta1,delta2; if (boxcheck) { if (triclinic == 0) { delx = bboxlo[0] - boxlo_hold[0]; dely = bboxlo[1] - boxlo_hold[1]; delz = bboxlo[2] - boxlo_hold[2]; delta1 = sqrt(delx*delx + dely*dely + delz*delz); delx = bboxhi[0] - boxhi_hold[0]; dely = bboxhi[1] - boxhi_hold[1]; delz = bboxhi[2] - boxhi_hold[2]; delta2 = sqrt(delx*delx + dely*dely + delz*delz); delta = 0.5 * (skin - (delta1+delta2)); deltasq = delta*delta; } else { domain->box_corners(); delta1 = delta2 = 0.0; for (int i = 0; i < 8; i++) { delx = corners[i][0] - corners_hold[i][0]; dely = corners[i][1] - corners_hold[i][1]; delz = corners[i][2] - corners_hold[i][2]; delta = sqrt(delx*delx + dely*dely + delz*delz); if (delta > delta1) delta1 = delta; else if (delta > delta2) delta2 = delta; } delta = 0.5 * (skin - (delta1+delta2)); deltasq = delta*delta; } } else deltasq = triggersq; double **x = atom->x; int nlocal = atom->nlocal; if (includegroup) nlocal = atom->nfirst; int flag = 0; for (int i = 0; i < nlocal; i++) { delx = x[i][0] - xhold[i][0]; dely = x[i][1] - xhold[i][1]; delz = x[i][2] - xhold[i][2]; rsq = delx*delx + dely*dely + delz*delz; if (rsq > deltasq) flag = 1; } int flagall; MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_MAX,world); if (flagall && ago == MAX(every,delay)) ndanger++; return flagall; } /* ---------------------------------------------------------------------- build all perpetual neighbor lists every few timesteps pairwise & topology lists are created as needed ------------------------------------------------------------------------- */ void Neighbor::build() { int i; ago = 0; ncalls++; // store current atom positions and box size if needed if (dist_check) { double **x = atom->x; int nlocal = atom->nlocal; if (includegroup) nlocal = atom->nfirst; if (nlocal > maxhold) { maxhold = atom->nmax; memory->destroy(xhold); memory->create(xhold,maxhold,3,"neigh:xhold"); } for (i = 0; i < nlocal; i++) { xhold[i][0] = x[i][0]; xhold[i][1] = x[i][1]; xhold[i][2] = x[i][2]; } if (boxcheck) { if (triclinic == 0) { boxlo_hold[0] = bboxlo[0]; boxlo_hold[1] = bboxlo[1]; boxlo_hold[2] = bboxlo[2]; boxhi_hold[0] = bboxhi[0]; boxhi_hold[1] = bboxhi[1]; boxhi_hold[2] = bboxhi[2]; } else { domain->box_corners(); corners = domain->corners; for (i = 0; i < 8; i++) { corners_hold[i][0] = corners[i][0]; corners_hold[i][1] = corners[i][1]; corners_hold[i][2] = corners[i][2]; } } } } // if any lists store neighbors of ghosts: // invoke grow() if nlocal+nghost exceeds previous list size // else only invoke grow() if nlocal exceeds previous list size // only done for lists with growflag set and which are perpetual if (anyghostlist && atom->nlocal+atom->nghost > maxatom) { maxatom = atom->nmax; for (i = 0; i < nglist; i++) lists[glist[i]]->grow(maxatom); } else if (atom->nlocal > maxatom) { maxatom = atom->nmax; for (i = 0; i < nglist; i++) lists[glist[i]]->grow(maxatom); } // extend atom bin list if necessary if (style != NSQ && atom->nmax > maxbin) { maxbin = atom->nmax; memory->destroy(bins); memory->create(bins,maxbin,"bins"); } - // check that pairwise lists with special bond weighting will not overflow + // check that neighbor list with special bond flags will not overflow - if (atom->molecular && maxwt && nblist) { - bigint max = maxwt * static_cast (atom->nlocal + atom->nghost); - if (max > MAXSMALLINT) - error->one("Weighted neighbor list values are too big"); - } + if (atom->nlocal+atom->nghost > NEIGHMASK) + error->one("Too many local+ghost atoms for neighbor list"); // invoke building of pair and molecular neighbor lists // only for pairwise lists with buildflag set for (i = 0; i < nblist; i++) (this->*pair_build[blist[i]])(lists[blist[i]]); if (atom->molecular) { if (force->bond) (this->*bond_build)(); if (force->angle) (this->*angle_build)(); if (force->dihedral) (this->*dihedral_build)(); if (force->improper) (this->*improper_build)(); } } /* ---------------------------------------------------------------------- build a single occasional pairwise neighbor list indexed by I called by other classes ------------------------------------------------------------------------- */ void Neighbor::build_one(int i) { // update stencils and grow atom arrays and bins as needed // only for relevant settings of stencilflag and growflag // grow atom array for this list to current size of perpetual lists if (lists[i]->stencilflag) { lists[i]->stencil_allocate(smax,style); (this->*stencil_create[i])(lists[i],sx,sy,sz); } if (lists[i]->growflag) lists[i]->grow(maxatom); if (style != NSQ && atom->nmax > maxbin) { maxbin = atom->nmax; memory->destroy(bins); memory->create(bins,maxbin,"bins"); } + // check that neighbor list with special bond flags will not overflow + + if (atom->nlocal+atom->nghost > NEIGHMASK) + error->one("Too many local+ghost atoms for neighbor list"); + // when occasional list built, LAMMPS can crash if atoms have moved too far // why is this?, give warning if this is the case // no easy workaround b/c all neighbor lists really need to be rebuilt // solution is for input script to check more often for rebuild // only check_distance if running a simulation, not between simulations int flag = 0; if (dist_check && update->whichflag) flag = check_distance(); if (flag && me == 0) error->warning("Building an occasional neighobr list when " "atoms may have moved too far"); (this->*pair_build[i])(lists[i]); } /* ---------------------------------------------------------------------- setup neighbor binning parameters bin numbering in each dimension is global: 0 = 0.0 to binsize, 1 = binsize to 2*binsize, etc nbin-1,nbin,etc = bbox-binsize to bbox, bbox to bbox+binsize, etc -1,-2,etc = -binsize to 0.0, -2*binsize to -binsize, etc code will work for any binsize since next(xyz) and stencil extend as far as necessary binsize = 1/2 of cutoff is roughly optimal for orthogonal boxes: a dim must be filled exactly by integer # of bins in periodic, procs on both sides of PBC must see same bin boundary in non-periodic, coord2bin() still assumes this by use of nbin xyz for triclinic boxes: tilted simulation box cannot contain integer # of bins stencil & neigh list built differently to account for this mbinlo = lowest global bin any of my ghost atoms could fall into mbinhi = highest global bin any of my ghost atoms could fall into mbin = number of bins I need in a dimension ------------------------------------------------------------------------- */ void Neighbor::setup_bins() { // bbox = size of bbox of entire domain // bsubbox lo/hi = bounding box of my subdomain extended by comm->cutghost // for triclinic: // bbox bounds all 8 corners of tilted box // subdomain is in lamda coords // include dimension-dependent extension via comm->cutghost // domain->bbox() converts lamda extent to box coords and computes bbox double bbox[3],bsubboxlo[3],bsubboxhi[3]; double *cutghost = comm->cutghost; if (triclinic == 0) { bsubboxlo[0] = domain->sublo[0] - cutghost[0]; bsubboxlo[1] = domain->sublo[1] - cutghost[1]; bsubboxlo[2] = domain->sublo[2] - cutghost[2]; bsubboxhi[0] = domain->subhi[0] + cutghost[0]; bsubboxhi[1] = domain->subhi[1] + cutghost[1]; bsubboxhi[2] = domain->subhi[2] + cutghost[2]; } else { double lo[3],hi[3]; lo[0] = domain->sublo_lamda[0] - cutghost[0]; lo[1] = domain->sublo_lamda[1] - cutghost[1]; lo[2] = domain->sublo_lamda[2] - cutghost[2]; hi[0] = domain->subhi_lamda[0] + cutghost[0]; hi[1] = domain->subhi_lamda[1] + cutghost[1]; hi[2] = domain->subhi_lamda[2] + cutghost[2]; domain->bbox(lo,hi,bsubboxlo,bsubboxhi); } bbox[0] = bboxhi[0] - bboxlo[0]; bbox[1] = bboxhi[1] - bboxlo[1]; bbox[2] = bboxhi[2] - bboxlo[2]; // optimal bin size is roughly 1/2 the cutoff // for BIN style, binsize = 1/2 of max neighbor cutoff // for MULTI style, binsize = 1/2 of min neighbor cutoff // special case of all cutoffs = 0.0, binsize = box size double binsize_optimal; if (binsizeflag) binsize_optimal = binsize_user; else if (style == BIN) binsize_optimal = 0.5*cutneighmax; else binsize_optimal = 0.5*cutneighmin; if (binsize_optimal == 0.0) binsize_optimal = bbox[0]; double binsizeinv = 1.0/binsize_optimal; // test for too many global bins in any dimension due to huge global domain if (bbox[0]*binsizeinv > MAXSMALLINT || bbox[1]*binsizeinv > MAXSMALLINT || bbox[2]*binsizeinv > MAXSMALLINT) error->all("Domain too large for neighbor bins"); // create actual bins // always have one bin even if cutoff > bbox // for 2d, nbinz = 1 nbinx = static_cast (bbox[0]*binsizeinv); nbiny = static_cast (bbox[1]*binsizeinv); if (dimension == 3) nbinz = static_cast (bbox[2]*binsizeinv); else nbinz = 1; if (nbinx == 0) nbinx = 1; if (nbiny == 0) nbiny = 1; if (nbinz == 0) nbinz = 1; // compute actual bin size for nbins to fit into box exactly // error if actual bin size << cutoff, since will create a zillion bins // this happens when nbin = 1 and box size << cutoff // typically due to non-periodic, flat system in a particular dim // in that extreme case, should use NSQ not BIN neighbor style binsizex = bbox[0]/nbinx; binsizey = bbox[1]/nbiny; binsizez = bbox[2]/nbinz; bininvx = 1.0 / binsizex; bininvy = 1.0 / binsizey; bininvz = 1.0 / binsizez; if (binsize_optimal*bininvx > CUT2BIN_RATIO || binsize_optimal*bininvy > CUT2BIN_RATIO || binsize_optimal*bininvz > CUT2BIN_RATIO) error->all("Cannot use neighbor bins - box size << cutoff"); // mbinlo/hi = lowest and highest global bins my ghost atoms could be in // coord = lowest and highest values of coords for my ghost atoms // static_cast(-1.5) = -1, so subract additional -1 // add in SMALL for round-off safety int mbinxhi,mbinyhi,mbinzhi; double coord; coord = bsubboxlo[0] - SMALL*bbox[0]; mbinxlo = static_cast ((coord-bboxlo[0])*bininvx); if (coord < bboxlo[0]) mbinxlo = mbinxlo - 1; coord = bsubboxhi[0] + SMALL*bbox[0]; mbinxhi = static_cast ((coord-bboxlo[0])*bininvx); coord = bsubboxlo[1] - SMALL*bbox[1]; mbinylo = static_cast ((coord-bboxlo[1])*bininvy); if (coord < bboxlo[1]) mbinylo = mbinylo - 1; coord = bsubboxhi[1] + SMALL*bbox[1]; mbinyhi = static_cast ((coord-bboxlo[1])*bininvy); if (dimension == 3) { coord = bsubboxlo[2] - SMALL*bbox[2]; mbinzlo = static_cast ((coord-bboxlo[2])*bininvz); if (coord < bboxlo[2]) mbinzlo = mbinzlo - 1; coord = bsubboxhi[2] + SMALL*bbox[2]; mbinzhi = static_cast ((coord-bboxlo[2])*bininvz); } // extend bins by 1 to insure stencil extent is included // if 2d, only 1 bin in z mbinxlo = mbinxlo - 1; mbinxhi = mbinxhi + 1; mbinx = mbinxhi - mbinxlo + 1; mbinylo = mbinylo - 1; mbinyhi = mbinyhi + 1; mbiny = mbinyhi - mbinylo + 1; if (dimension == 3) { mbinzlo = mbinzlo - 1; mbinzhi = mbinzhi + 1; } else mbinzlo = mbinzhi = 0; mbinz = mbinzhi - mbinzlo + 1; // memory for bin ptrs bigint bbin = mbinx*mbiny*mbinz; if (bbin > MAXSMALLINT) error->one("Too many neighbor bins"); mbins = bbin; if (mbins > maxhead) { maxhead = mbins; memory->destroy(binhead); memory->create(binhead,maxhead,"neigh:binhead"); } // create stencil of bins to search over in neighbor list construction // sx,sy,sz = max range of stencil in each dim // smax = max possible size of entire 3d stencil // stencil is empty if cutneighmax = 0.0 sx = static_cast (cutneighmax*bininvx); if (sx*binsizex < cutneighmax) sx++; sy = static_cast (cutneighmax*bininvy); if (sy*binsizey < cutneighmax) sy++; sz = static_cast (cutneighmax*bininvz); if (sz*binsizez < cutneighmax) sz++; if (dimension == 2) sz = 0; smax = (2*sx+1) * (2*sy+1) * (2*sz+1); // create stencils for pairwise neighbor lists // only done for lists with stencilflag and buildflag set for (int i = 0; i < nslist; i++) { lists[slist[i]]->stencil_allocate(smax,style); (this->*stencil_create[slist[i]])(lists[slist[i]],sx,sy,sz); } } /* ---------------------------------------------------------------------- compute closest distance between central bin (0,0,0) and bin (i,j,k) ------------------------------------------------------------------------- */ double Neighbor::bin_distance(int i, int j, int k) { double delx,dely,delz; if (i > 0) delx = (i-1)*binsizex; else if (i == 0) delx = 0.0; else delx = (i+1)*binsizex; if (j > 0) dely = (j-1)*binsizey; else if (j == 0) dely = 0.0; else dely = (j+1)*binsizey; if (k > 0) delz = (k-1)*binsizez; else if (k == 0) delz = 0.0; else delz = (k+1)*binsizez; return (delx*delx + dely*dely + delz*delz); } /* ---------------------------------------------------------------------- set neighbor style and skin distance ------------------------------------------------------------------------- */ void Neighbor::set(int narg, char **arg) { if (narg != 2) error->all("Illegal neighbor command"); skin = atof(arg[0]); if (skin < 0.0) error->all("Illegal neighbor command"); if (strcmp(arg[1],"nsq") == 0) style = NSQ; else if (strcmp(arg[1],"bin") == 0) style = BIN; else if (strcmp(arg[1],"multi") == 0) style = MULTI; else error->all("Illegal neighbor command"); } /* ---------------------------------------------------------------------- modify parameters of the pair-wise neighbor build ------------------------------------------------------------------------- */ void Neighbor::modify_params(int narg, char **arg) { int iarg = 0; while (iarg < narg) { if (strcmp(arg[iarg],"every") == 0) { if (iarg+2 > narg) error->all("Illegal neigh_modify command"); every = atoi(arg[iarg+1]); if (every <= 0) error->all("Illegal neigh_modify command"); iarg += 2; } else if (strcmp(arg[iarg],"delay") == 0) { if (iarg+2 > narg) error->all("Illegal neigh_modify command"); delay = atoi(arg[iarg+1]); if (delay < 0) error->all("Illegal neigh_modify command"); iarg += 2; } else if (strcmp(arg[iarg],"check") == 0) { if (iarg+2 > narg) error->all("Illegal neigh_modify command"); if (strcmp(arg[iarg+1],"yes") == 0) dist_check = 1; else if (strcmp(arg[iarg+1],"no") == 0) dist_check = 0; else error->all("Illegal neigh_modify command"); iarg += 2; } else if (strcmp(arg[iarg],"once") == 0) { if (iarg+2 > narg) error->all("Illegal neigh_modify command"); if (strcmp(arg[iarg+1],"yes") == 0) build_once = 1; else if (strcmp(arg[iarg+1],"no") == 0) build_once = 0; else error->all("Illegal neigh_modify command"); iarg += 2; } else if (strcmp(arg[iarg],"page") == 0) { if (iarg+2 > narg) error->all("Illegal neigh_modify command"); pgsize = atoi(arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"one") == 0) { if (iarg+2 > narg) error->all("Illegal neigh_modify command"); oneatom = atoi(arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"binsize") == 0) { if (iarg+2 > narg) error->all("Illegal neigh_modify command"); binsize_user = atof(arg[iarg+1]); if (binsize_user <= 0.0) binsizeflag = 0; else binsizeflag = 1; iarg += 2; } else if (strcmp(arg[iarg],"include") == 0) { if (iarg+2 > narg) error->all("Illegal neigh_modify command"); includegroup = group->find(arg[iarg+1]); if (includegroup < 0) error->all("Invalid group ID in neigh_modify command"); if (includegroup && (atom->firstgroupname == NULL || strcmp(arg[iarg+1],atom->firstgroupname) != 0)) error->all("Neigh_modify include group != atom_modify first group"); iarg += 2; } else if (strcmp(arg[iarg],"exclude") == 0) { if (iarg+2 > narg) error->all("Illegal neigh_modify command"); if (strcmp(arg[iarg+1],"type") == 0) { if (iarg+4 > narg) error->all("Illegal neigh_modify command"); if (nex_type == maxex_type) { maxex_type += EXDELTA; memory->grow(ex1_type,maxex_type,"neigh:ex1_type"); memory->grow(ex2_type,maxex_type,"neigh:ex2_type"); } ex1_type[nex_type] = atoi(arg[iarg+2]); ex2_type[nex_type] = atoi(arg[iarg+3]); nex_type++; iarg += 4; } else if (strcmp(arg[iarg+1],"group") == 0) { if (iarg+4 > narg) error->all("Illegal neigh_modify command"); if (nex_group == maxex_group) { maxex_group += EXDELTA; memory->grow(ex1_group,maxex_group,"neigh:ex1_group"); memory->grow(ex2_group,maxex_group,"neigh:ex2_group"); } ex1_group[nex_group] = group->find(arg[iarg+2]); ex2_group[nex_group] = group->find(arg[iarg+3]); if (ex1_group[nex_group] == -1 || ex2_group[nex_group] == -1) error->all("Invalid group ID in neigh_modify command"); nex_group++; iarg += 4; } else if (strcmp(arg[iarg+1],"molecule") == 0) { if (iarg+3 > narg) error->all("Illegal neigh_modify command"); if (atom->molecule_flag == 0) { char *str = (char *) "Neigh_modify exclude molecule requires atom attribute molecule"; error->all(str); } if (nex_mol == maxex_mol) { maxex_mol += EXDELTA; memory->grow(ex_mol_group,maxex_mol,"neigh:ex_mol_group"); } ex_mol_group[nex_mol] = group->find(arg[iarg+2]); if (ex_mol_group[nex_mol] == -1) error->all("Invalid group ID in neigh_modify command"); nex_mol++; iarg += 3; } else if (strcmp(arg[iarg+1],"none") == 0) { nex_type = nex_group = nex_mol = 0; iarg += 2; } else error->all("Illegal neigh_modify command"); } else error->all("Illegal neigh_modify command"); } } /* ---------------------------------------------------------------------- bin owned and ghost atoms ------------------------------------------------------------------------- */ void Neighbor::bin_atoms() { int i,ibin; for (i = 0; i < mbins; i++) binhead[i] = -1; // bin in reverse order so linked list will be in forward order // also puts ghost atoms at end of list, which is necessary double **x = atom->x; int *mask = atom->mask; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; if (includegroup) { int bitmask = group->bitmask[includegroup]; for (i = nall-1; i >= nlocal; i--) { if (mask[i] & bitmask) { ibin = coord2bin(x[i]); bins[i] = binhead[ibin]; binhead[ibin] = i; } } for (i = atom->nfirst-1; i >= 0; i--) { ibin = coord2bin(x[i]); bins[i] = binhead[ibin]; binhead[ibin] = i; } } else { for (i = nall-1; i >= 0; i--) { ibin = coord2bin(x[i]); bins[i] = binhead[ibin]; binhead[ibin] = i; } } } /* ---------------------------------------------------------------------- convert atom coords into local bin # for orthogonal, only ghost atoms will have coord >= bboxhi or coord < bboxlo take special care to insure ghosts are in correct bins even w/ roundoff hi ghost atoms = nbin,nbin+1,etc owned atoms = 0 to nbin-1 lo ghost atoms = -1,-2,etc this is necessary so that both procs on either side of PBC treat a pair of atoms straddling the PBC in a consistent way for triclinic, doesn't matter since stencil & neigh list built differently ------------------------------------------------------------------------- */ int Neighbor::coord2bin(double *x) { int ix,iy,iz; if (x[0] >= bboxhi[0]) ix = static_cast ((x[0]-bboxhi[0])*bininvx) + nbinx; else if (x[0] >= bboxlo[0]) { ix = static_cast ((x[0]-bboxlo[0])*bininvx); ix = MIN(ix,nbinx-1); } else ix = static_cast ((x[0]-bboxlo[0])*bininvx) - 1; if (x[1] >= bboxhi[1]) iy = static_cast ((x[1]-bboxhi[1])*bininvy) + nbiny; else if (x[1] >= bboxlo[1]) { iy = static_cast ((x[1]-bboxlo[1])*bininvy); iy = MIN(iy,nbiny-1); } else iy = static_cast ((x[1]-bboxlo[1])*bininvy) - 1; if (x[2] >= bboxhi[2]) iz = static_cast ((x[2]-bboxhi[2])*bininvz) + nbinz; else if (x[2] >= bboxlo[2]) { iz = static_cast ((x[2]-bboxlo[2])*bininvz); iz = MIN(iz,nbinz-1); } else iz = static_cast ((x[2]-bboxlo[2])*bininvz) - 1; return (iz-mbinzlo)*mbiny*mbinx + (iy-mbinylo)*mbinx + (ix-mbinxlo); } /* ---------------------------------------------------------------------- same as coord2bin, but also return ix,iy,iz offsets in each dim ------------------------------------------------------------------------- */ int Neighbor::coord2bin(double *x, int &ix, int &iy, int &iz) { if (x[0] >= bboxhi[0]) ix = static_cast ((x[0]-bboxhi[0])*bininvx) + nbinx; else if (x[0] >= bboxlo[0]) { ix = static_cast ((x[0]-bboxlo[0])*bininvx); ix = MIN(ix,nbinx-1); } else ix = static_cast ((x[0]-bboxlo[0])*bininvx) - 1; if (x[1] >= bboxhi[1]) iy = static_cast ((x[1]-bboxhi[1])*bininvy) + nbiny; else if (x[1] >= bboxlo[1]) { iy = static_cast ((x[1]-bboxlo[1])*bininvy); iy = MIN(iy,nbiny-1); } else iy = static_cast ((x[1]-bboxlo[1])*bininvy) - 1; if (x[2] >= bboxhi[2]) iz = static_cast ((x[2]-bboxhi[2])*bininvz) + nbinz; else if (x[2] >= bboxlo[2]) { iz = static_cast ((x[2]-bboxlo[2])*bininvz); iz = MIN(iz,nbinz-1); } else iz = static_cast ((x[2]-bboxlo[2])*bininvz) - 1; ix -= mbinxlo; iy -= mbinylo; iz -= mbinzlo; return iz*mbiny*mbinx + iy*mbinx + ix; } /* ---------------------------------------------------------------------- test if atom pair i,j is excluded from neighbor list due to type, group, molecule settings from neigh_modify command return 1 if should be excluded, 0 if included ------------------------------------------------------------------------- */ int Neighbor::exclusion(int i, int j, int itype, int jtype, int *mask, int *molecule) { int m; if (nex_type && ex_type[itype][jtype]) return 1; if (nex_group) { for (m = 0; m < nex_group; m++) { if (mask[i] & ex1_bit[m] && mask[j] & ex2_bit[m]) return 1; if (mask[i] & ex2_bit[m] && mask[j] & ex1_bit[m]) return 1; } } if (nex_mol) { for (m = 0; m < nex_mol; m++) if (mask[i] & ex_mol_bit[m] && mask[j] & ex_mol_bit[m] && molecule[i] == molecule[j]) return 1; } return 0; } /* ---------------------------------------------------------------------- return # of bytes of allocated memory ------------------------------------------------------------------------- */ bigint Neighbor::memory_usage() { bigint bytes = 0; bytes += memory->usage(xhold,maxhold,3); if (style != NSQ) { bytes += memory->usage(bins,maxbin); bytes += memory->usage(binhead,maxhead); } for (int i = 0; i < nlist; i++) bytes += lists[i]->memory_usage(); bytes += memory->usage(bondlist,maxbond,3); bytes += memory->usage(anglelist,maxangle,4); bytes += memory->usage(dihedrallist,maxdihedral,5); bytes += memory->usage(improperlist,maximproper,5); return bytes; } diff --git a/src/neighbor.h b/src/neighbor.h index 64d12788a..97e0f354c 100644 --- a/src/neighbor.h +++ b/src/neighbor.h @@ -1,291 +1,291 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #ifndef LMP_NEIGHBOR_H #define LMP_NEIGHBOR_H #include "pointers.h" namespace LAMMPS_NS { class Neighbor : protected Pointers { public: int style; // 0,1,2 = nsq, bin, multi int every; // build every this many steps int delay; // delay build for this many steps int dist_check; // 0 = always build, 1 = only if 1/2 dist int ago; // how many steps ago neighboring occurred int pgsize; // size of neighbor page int oneatom; // max # of neighbors for one atom int includegroup; // only build pairwise lists for this group int build_once; // 1 if only build lists once per run double skin; // skin distance double cutneighmin; // min neighbor cutoff for all type pairs double cutneighmax; // max neighbor cutoff for all type pairs double *cuttype; // for each type, max neigh cut w/ others int ncalls; // # of times build has been called int ndanger; // # of dangerous builds int nrequest; // requests for pairwise neighbor lists class NeighRequest **requests; // from Pair, Fix, Compute, Command classes int maxrequest; int old_style; // previous run info to avoid int old_nrequest; // re-creation of pairwise neighbor lists int old_triclinic; class NeighRequest **old_requests; int nlist; // pairwise neighbor lists class NeighList **lists; int nbondlist; // list of bonds to compute int **bondlist; int nanglelist; // list of angles to compute int **anglelist; int ndihedrallist; // list of dihedrals to compute int **dihedrallist; int nimproperlist; // list of impropers to compute int **improperlist; Neighbor(class LAMMPS *); ~Neighbor(); void init(); int request(void *); // another class requests a neighbor list void print_lists_of_lists(); // debug print out int decide(); // decide whether to build or not int check_distance(); // check max distance moved since last build void setup_bins(); // setup bins based on box and cutoff void build(); // create all neighbor lists (pair,bond) void build_one(int); // create a single neighbor list void set(int, char **); // set neighbor style and skin distance void modify_params(int, char**); // modify parameters that control builds bigint memory_usage(); private: int me,nprocs; int maxatom; // size of atom-based NeighList arrays int maxbond,maxangle,maxdihedral,maximproper; // size of bond lists int maxwt; // max weighting factor applied + 1 int must_check; // 1 if must check other classes to reneigh int restart_check; // 1 if restart enabled, 0 if no int fix_check; // # of fixes that induce reneigh int *fixchecklist; // which fixes to check double **cutneighsq; // neighbor cutneigh sq for each type pair double **cutneighghostsq; // neighbor cutnsq for each ghost type pair double cutneighmaxsq; // cutneighmax squared double *cuttypesq; // cuttype squared double triggersq; // trigger = build when atom moves this dist double **xhold; // atom coords at last neighbor build int maxhold; // size of xhold array int boxcheck; // 1 if need to store box size double boxlo_hold[3],boxhi_hold[3]; // box size at last neighbor build double corners_hold[8][3]; // box corners at last neighbor build int nbinx,nbiny,nbinz; // # of global bins int *bins; // ptr to next atom in each bin int maxbin; // size of bins array int *binhead; // ptr to 1st atom in each bin int maxhead; // size of binhead array int mbins; // # of local bins and offset int mbinx,mbiny,mbinz; int mbinxlo,mbinylo,mbinzlo; int binsizeflag; // user-chosen bin size double binsize_user; double binsizex,binsizey,binsizez; // actual bin sizes and inverse sizes double bininvx,bininvy,bininvz; int sx,sy,sz,smax; // bin stencil extents int dimension; // 2/3 for 2d/3d int triclinic; // 0 if domain is orthog, 1 if triclinic int newton_pair; // 0 if newton off, 1 if on for pairwise double *bboxlo,*bboxhi; // ptrs to full domain bounding box double (*corners)[3]; // ptr to 8 corners of triclinic box double inner[2],middle[2]; // rRESPA cutoffs for extra lists double cut_inner_sq; // outer cutoff for inner neighbor list double cut_middle_sq; // outer cutoff for middle neighbor list double cut_middle_inside_sq; // inner cutoff for middle neighbor list int special_flag[4]; // flags for 1-2, 1-3, 1-4 neighbors int anyghostlist; // 1 if any non-occasional list // stores neighbors of ghosts int exclude; // 0 if no type/group exclusions, 1 if yes int nex_type; // # of entries in type exclusion list int maxex_type; // max # in type list int *ex1_type,*ex2_type; // pairs of types to exclude int **ex_type; // 2d array of excluded type pairs int nex_group; // # of entries in group exclusion list int maxex_group; // max # in group list int *ex1_group,*ex2_group; // pairs of group #'s to exclude int *ex1_bit,*ex2_bit; // pairs of group bits to exclude int nex_mol; // # of entries in molecule exclusion list int maxex_mol; // max # in molecule list int *ex_mol_group; // molecule group #'s to exclude int *ex_mol_bit; // molecule group bits to exclude int nblist,nglist,nslist; // # of pairwise neigh lists of various kinds int *blist; // lists to build every reneighboring int *glist; // lists to grow atom arrays every reneigh int *slist; // lists to grow stencil arrays every reneigh void bin_atoms(); // bin all atoms double bin_distance(int, int, int); // distance between binx int coord2bin(double *); // mapping atom coord to a bin int coord2bin(double *, int &, int &, int&); // ditto int exclusion(int, int, int, int, int *, int *); // test for pair exclusion void choose_build(int, class NeighRequest *); void choose_stencil(int, class NeighRequest *); - // find_special: determine if atom j is in special list of atom i - // if it is not, return 0 - // if it is and special flag is 0 (both coeffs are 0.0), return -1 - // if it is and special flag is 1 (both coeffs are 1.0), return 0 - // if it is and special flag is 2 (otherwise), return 1,2,3 - // for which neighbor it is (and which coeff it maps to) - - inline int find_special(const int *list, const int *nspecial, - const int tag) const { - const int n1 = nspecial[0]; - const int n2 = nspecial[1]; - const int n3 = nspecial[2]; - - for (int i = 0; i < n3; i++) { - if (list[i] == tag) { - if (i < n1) { - if (special_flag[1] == 0) return -1; - else if (special_flag[1] == 1) return 0; - else return 1; - } else if (i < n2) { - if (special_flag[2] == 0) return -1; - else if (special_flag[2] == 1) return 0; - else return 2; - } else { - if (special_flag[3] == 0) return -1; - else if (special_flag[3] == 1) return 0; - else return 3; - } - } - } - return 0; - }; - // pairwise build functions typedef void (Neighbor::*PairPtr)(class NeighList *); PairPtr *pair_build; void half_nsq_no_newton(class NeighList *); void half_nsq_newton(class NeighList *); void half_bin_no_newton(class NeighList *); void half_bin_newton(class NeighList *); void half_bin_newton_tri(class NeighList *); void half_multi_no_newton(class NeighList *); void half_multi_newton(class NeighList *); void half_multi_newton_tri(class NeighList *); void full_nsq(class NeighList *); void full_nsq_ghost(class NeighList *); void full_bin(class NeighList *); void full_bin_ghost(class NeighList *); void full_multi(class NeighList *); void half_from_full_no_newton(class NeighList *); void half_from_full_newton(class NeighList *); void skip_from(class NeighList *); void skip_from_granular(class NeighList *); void skip_from_respa(class NeighList *); void copy_from(class NeighList *); void granular_nsq_no_newton(class NeighList *); void granular_nsq_newton(class NeighList *); void granular_bin_no_newton(class NeighList *); void granular_bin_newton(class NeighList *); void granular_bin_newton_tri(class NeighList *); void respa_nsq_no_newton(class NeighList *); void respa_nsq_newton(class NeighList *); void respa_bin_no_newton(class NeighList *); void respa_bin_newton(class NeighList *); void respa_bin_newton_tri(class NeighList *); // pairwise stencil creation functions typedef void (Neighbor::*StencilPtr)(class NeighList *, int, int, int); StencilPtr *stencil_create; void stencil_half_bin_2d_no_newton(class NeighList *, int, int, int); void stencil_half_bin_3d_no_newton(class NeighList *, int, int, int); void stencil_half_bin_2d_newton(class NeighList *, int, int, int); void stencil_half_bin_3d_newton(class NeighList *, int, int, int); void stencil_half_bin_2d_newton_tri(class NeighList *, int, int, int); void stencil_half_bin_3d_newton_tri(class NeighList *, int, int, int); void stencil_half_multi_2d_no_newton(class NeighList *, int, int, int); void stencil_half_multi_3d_no_newton(class NeighList *, int, int, int); void stencil_half_multi_2d_newton(class NeighList *, int, int, int); void stencil_half_multi_3d_newton(class NeighList *, int, int, int); void stencil_half_multi_2d_newton_tri(class NeighList *, int, int, int); void stencil_half_multi_3d_newton_tri(class NeighList *, int, int, int); void stencil_full_bin_2d(class NeighList *, int, int, int); void stencil_full_ghost_bin_2d(class NeighList *, int, int, int); void stencil_full_bin_3d(class NeighList *, int, int, int); void stencil_full_ghost_bin_3d(class NeighList *, int, int, int); void stencil_full_multi_2d(class NeighList *, int, int, int); void stencil_full_multi_3d(class NeighList *, int, int, int); // topology build functions typedef void (Neighbor::*BondPtr)(); // ptrs to topology build functions BondPtr bond_build; // ptr to bond list functions void bond_all(); // bond list with all bonds void bond_partial(); // exclude certain bonds BondPtr angle_build; // ptr to angle list functions void angle_all(); // angle list with all angles void angle_partial(); // exclude certain angles BondPtr dihedral_build; // ptr to dihedral list functions void dihedral_all(); // dihedral list with all dihedrals void dihedral_partial(); // exclude certain dihedrals BondPtr improper_build; // ptr to improper list functions void improper_all(); // improper list with all impropers void improper_partial(); // exclude certain impropers + + // find_special: determine if atom j is in special list of atom i + // if it is not, return 0 + // if it is and special flag is 0 (both coeffs are 0.0), return -1 + // if it is and special flag is 1 (both coeffs are 1.0), return 0 + // if it is and special flag is 2 (otherwise), return 1,2,3 + // for which neighbor it is (and which coeff it maps to) + + inline int find_special(const int *list, const int *nspecial, + const int tag) const { + const int n1 = nspecial[0]; + const int n2 = nspecial[1]; + const int n3 = nspecial[2]; + + for (int i = 0; i < n3; i++) { + if (list[i] == tag) { + if (i < n1) { + if (special_flag[1] == 0) return -1; + else if (special_flag[1] == 1) return 0; + else return 1; + } else if (i < n2) { + if (special_flag[2] == 0) return -1; + else if (special_flag[2] == 1) return 0; + else return 2; + } else { + if (special_flag[3] == 0) return -1; + else if (special_flag[3] == 1) return 0; + else return 3; + } + } + } + return 0; + }; }; } #endif diff --git a/src/pair.h b/src/pair.h index 871c0688e..1ce8fea1a 100644 --- a/src/pair.h +++ b/src/pair.h @@ -1,154 +1,158 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #ifndef LMP_PAIR_H #define LMP_PAIR_H #include "pointers.h" namespace LAMMPS_NS { class Pair : protected Pointers { friend class BondQuartic; friend class DihedralCharmm; friend class FixGPU; public: double eng_vdwl,eng_coul; // accumulated energies double virial[6]; // accumulated virial double *eatom,**vatom; // accumulated per-atom energy/virial double cutforce; // max cutoff for all atom pairs double **cutsq; // cutoff sq for each atom pair int **setflag; // 0/1 = whether each i,j has been set int comm_forward; // size of forward communication (0 if none) int comm_reverse; // size of reverse communication (0 if none) int single_enable; // 1 if single() routine exists int respa_enable; // 1 if inner/middle/outer rRESPA routines int one_coeff; // 1 if allows only one coeff * * call int no_virial_compute; // 1 if does not invoke virial_compute() int ghostneigh; // 1 if pair style needs neighbors of ghosts double **cutghost; // cutoff for each ghost pair int tail_flag; // pair_modify flag for LJ tail correction double etail,ptail; // energy/pressure tail corrections double etail_ij,ptail_ij; int nextra; // # of extra quantities pair style calculates double *pvector; // vector of extra pair quantities class NeighList *list; // standard neighbor list used by most pairs class NeighList *listhalf; // half list used by some pairs class NeighList *listfull; // full list used by some pairs class NeighList *listgranhistory; // granular history list used by some pairs class NeighList *listinner; // rRESPA lists used by some pairs class NeighList *listmiddle; class NeighList *listouter; Pair(class LAMMPS *); virtual ~Pair(); // top-level Pair methods void init(); void reinit(); double mix_energy(double, double, double, double); double mix_distance(double, double); void write_file(int, char **); void init_bitmap(double, double, int, int &, int &, int &, int &); virtual void modify_params(int, char **); // general child-class methods virtual void compute(int, int) = 0; virtual void compute_inner() {} virtual void compute_middle() {} virtual void compute_outer(int, int) {} virtual double single(int, int, int, int, double, double, double, double &) {return 0.0;} virtual void settings(int, char **) = 0; virtual void coeff(int, char **) = 0; virtual void init_style(); virtual void init_list(int, class NeighList *); virtual double init_one(int, int) {return 0.0;} virtual void write_restart(FILE *) {} virtual void read_restart(FILE *) {} virtual void write_restart_settings(FILE *) {} virtual void read_restart_settings(FILE *) {} virtual int pack_comm(int, int *, double *, int, int *) {return 0;} virtual void unpack_comm(int, int, double *) {} virtual int pack_reverse_comm(int, int, double *) {return 0;} virtual void unpack_reverse_comm(int, int *, double *) {} virtual double memory_usage(); // specific child-class methods for certain Pair styles virtual void *extract(char *, int &) {return NULL;} virtual void swap_eam(double *, double **) {} virtual void reset_dt() {} virtual void min_xf_pointers(int, double **, double **) {} virtual void min_xf_get(int) {} virtual void min_x_set(int) {} protected: int allocated; // 0/1 = whether arrays are allocated // pair_modify settings int offset_flag,mix_flag; // flags for offset and mixing int ncoultablebits; // size of Coulomb table double tabinner; // inner cutoff for Coulomb table // custom data type for accessing Coulomb tables typedef union {int i; float f;} union_int_float_t; double THIRD; int evflag; // energy,virial settings int eflag_either,eflag_global,eflag_atom; int vflag_either,vflag_global,vflag_atom; int vflag_fdotr; int maxeatom,maxvatom; void ev_setup(int, int); void ev_tally(int, int, int, int, double, double, double, double, double, double); void ev_tally_full(int, double, double, double, double, double, double); void ev_tally_xyz(int, int, int, int, double, double, double, double, double, double, double, double); void ev_tally_xyz_full(int, double, double, double, double, double, double, double, double); void ev_tally3(int, int, int, double, double, double *, double *, double *, double *); void ev_tally4(int, int, int, int, double, double *, double *, double *, double *, double *, double *); void ev_tally_list(int, int *, double, double *); void v_tally2(int, int, double, double *); void v_tally3(int, int, int, double *, double *, double *, double *); void v_tally4(int, int, int, int, double *, double *, double *, double *, double *, double *); void v_tally_tensor(int, int, int, int, double, double, double, double, double, double); void virial_compute(); + + inline int sbmask(int j) { + return j >> SBBITS & 3; + } }; } #endif diff --git a/src/pair_born.cpp b/src/pair_born.cpp index ba9953d8b..99100d5c2 100644 --- a/src/pair_born.cpp +++ b/src/pair_born.cpp @@ -1,416 +1,411 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing Author: Sai Jayaraman (Sandia) ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "pair_born.h" #include "atom.h" #include "comm.h" #include "force.h" #include "neigh_list.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) /* ---------------------------------------------------------------------- */ PairBorn::PairBorn(LAMMPS *lmp) : Pair(lmp) {} /* ---------------------------------------------------------------------- */ PairBorn::~PairBorn() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut); memory->destroy(a); memory->destroy(rho); memory->destroy(sigma); memory->destroy(c); memory->destroy(d); memory->destroy(rhoinv); memory->destroy(born1); memory->destroy(born2); memory->destroy(born3); memory->destroy(offset); } } /* ---------------------------------------------------------------------- */ void PairBorn::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair; double rsq,r2inv,r6inv,forceborn,factor_lj; double r,rexp; int *ilist,*jlist,*numneigh,**firstneigh; evdwl = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; double **x = atom->x; double **f = atom->f; int *type = atom->type; int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; 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]; - - if (j < nall) factor_lj = 1.0; - else { - factor_lj = special_lj[j/nall]; - j %= nall; - } + 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_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("Illegal pair_style command"); cut_global = atof(arg[0]); // reset cutoffs that have been explicitly set if (allocated) { int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i+1; j <= atom->ntypes; j++) if (setflag[i][j]) cut[i][j] = cut_global; } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairBorn::coeff(int narg, char **arg) { if (narg < 7 || narg > 8) error->all("Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); double a_one = force->numeric(arg[2]); double rho_one = force->numeric(arg[3]); double sigma_one = force->numeric(arg[4]); if (rho_one <= 0) error->all("Incorrect args for pair coefficients"); double c_one = force->numeric(arg[5]); double d_one = force->numeric(arg[6]); double cut_one = cut_global; if (narg == 8) cut_one = force->numeric(arg[7]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { a[i][j] = a_one; rho[i][j] = rho_one; sigma[i][j] = sigma_one; c[i][j] = c_one; d[i][j] = d_one; cut[i][j] = cut_one; setflag[i][j] = 1; count++; } } if (count == 0) error->all("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("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 PI = 4.0*atan(1.0); 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*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*PI*all[0]*all[1] * (-a[i][j]*exp((sigma[i][j]-rc)/rho1) * (rc3 + 3.0*rho1*rc2 + 6.0*rho2*rc + 6.0*rho3) + 2.0*c[i][j]/rc3 - 8.0*d[i][j]/(5.0*rc5)); } return cut[i][j]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairBorn::write_restart(FILE *fp) { write_restart_settings(fp); int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { fwrite(&setflag[i][j],sizeof(int),1,fp); if (setflag[i][j]) { fwrite(&a[i][j],sizeof(double),1,fp); fwrite(&rho[i][j],sizeof(double),1,fp); fwrite(&sigma[i][j],sizeof(double),1,fp); fwrite(&c[i][j],sizeof(double),1,fp); fwrite(&d[i][j],sizeof(double),1,fp); fwrite(&cut[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairBorn::read_restart(FILE *fp) { read_restart_settings(fp); allocate(); int i,j; int me = comm->me; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp); MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world); if (setflag[i][j]) { if (me == 0) { fread(&a[i][j],sizeof(double),1,fp); fread(&rho[i][j],sizeof(double),1,fp); fread(&sigma[i][j],sizeof(double),1,fp); fread(&c[i][j],sizeof(double),1,fp); fread(&d[i][j],sizeof(double),1,fp); fread(&cut[i][j],sizeof(double),1,fp); } MPI_Bcast(&a[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&rho[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&c[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&d[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairBorn::write_restart_settings(FILE *fp) { fwrite(&cut_global,sizeof(double),1,fp); fwrite(&offset_flag,sizeof(int),1,fp); fwrite(&mix_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairBorn::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&cut_global,sizeof(double),1,fp); fread(&offset_flag,sizeof(int),1,fp); fread(&mix_flag,sizeof(int),1,fp); } MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world); MPI_Bcast(&offset_flag,1,MPI_INT,0,world); MPI_Bcast(&mix_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- */ double PairBorn::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r2inv,r6inv,r,rexp,forceborn,phiborn; r2inv = 1.0/rsq; r6inv = r2inv*r2inv*r2inv; r = sqrt(rsq); rexp = exp((sigma[itype][jtype]-r)*rhoinv[itype][jtype]); forceborn = born1[itype][jtype]*r*rexp - born2[itype][jtype]*r6inv + born3[itype][jtype]*r2inv*r6inv; fforce = factor_lj*forceborn*r2inv; phiborn = a[itype][jtype]*rexp - c[itype][jtype]*r6inv + d[itype][jtype]*r2inv*r6inv - offset[itype][jtype]; return factor_lj*phiborn; } /* ---------------------------------------------------------------------- */ void *PairBorn::extract(char *str, int &dim) { 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_buck.cpp b/src/pair_buck.cpp index 6b91e2305..cc2a37611 100644 --- a/src/pair_buck.cpp +++ b/src/pair_buck.cpp @@ -1,385 +1,380 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "pair_buck.h" #include "atom.h" #include "comm.h" #include "force.h" #include "neigh_list.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) /* ---------------------------------------------------------------------- */ PairBuck::PairBuck(LAMMPS *lmp) : Pair(lmp) {} /* ---------------------------------------------------------------------- */ PairBuck::~PairBuck() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut); memory->destroy(a); memory->destroy(rho); memory->destroy(c); memory->destroy(rhoinv); memory->destroy(buck1); memory->destroy(buck2); memory->destroy(offset); } } /* ---------------------------------------------------------------------- */ void PairBuck::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair; double rsq,r2inv,r6inv,forcebuck,factor_lj; double r,rexp; int *ilist,*jlist,*numneigh,**firstneigh; evdwl = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; double **x = atom->x; double **f = atom->f; int *type = atom->type; int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; 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]; - - if (j < nall) factor_lj = 1.0; - else { - factor_lj = special_lj[j/nall]; - j %= nall; - } + 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_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("Illegal pair_style command"); cut_global = force->numeric(arg[0]); // reset cutoffs that have been explicitly set if (allocated) { int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i+1; j <= atom->ntypes; j++) if (setflag[i][j]) cut[i][j] = cut_global; } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairBuck::coeff(int narg, char **arg) { if (narg < 5 || narg > 6) error->all("Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); double a_one = force->numeric(arg[2]); double rho_one = force->numeric(arg[3]); if (rho_one <= 0) error->all("Incorrect args for pair coefficients"); double c_one = force->numeric(arg[4]); double cut_one = cut_global; if (narg == 6) cut_one = force->numeric(arg[5]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { a[i][j] = a_one; rho[i][j] = rho_one; c[i][j] = c_one; cut[i][j] = cut_one; setflag[i][j] = 1; count++; } } if (count == 0) error->all("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("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 PI = 4.0*atan(1.0); 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*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*PI*all[0]*all[1]* (-a[i][j]*exp(-rc/rho1)* (rc3 + 3.0*rho1*rc2 + 6.0*rho2*rc + 6.0*rho3) + 2.0*c[i][j]/rc3); } return cut[i][j]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairBuck::write_restart(FILE *fp) { write_restart_settings(fp); int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { fwrite(&setflag[i][j],sizeof(int),1,fp); if (setflag[i][j]) { fwrite(&a[i][j],sizeof(double),1,fp); fwrite(&rho[i][j],sizeof(double),1,fp); fwrite(&c[i][j],sizeof(double),1,fp); fwrite(&cut[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairBuck::read_restart(FILE *fp) { read_restart_settings(fp); allocate(); int i,j; int me = comm->me; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp); MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world); if (setflag[i][j]) { if (me == 0) { fread(&a[i][j],sizeof(double),1,fp); fread(&rho[i][j],sizeof(double),1,fp); fread(&c[i][j],sizeof(double),1,fp); fread(&cut[i][j],sizeof(double),1,fp); } MPI_Bcast(&a[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&rho[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&c[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairBuck::write_restart_settings(FILE *fp) { fwrite(&cut_global,sizeof(double),1,fp); fwrite(&offset_flag,sizeof(int),1,fp); fwrite(&mix_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairBuck::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&cut_global,sizeof(double),1,fp); fread(&offset_flag,sizeof(int),1,fp); fread(&mix_flag,sizeof(int),1,fp); } MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world); MPI_Bcast(&offset_flag,1,MPI_INT,0,world); MPI_Bcast(&mix_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- */ double PairBuck::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r2inv,r6inv,r,rexp,forcebuck,phibuck; r2inv = 1.0/rsq; r6inv = r2inv*r2inv*r2inv; r = sqrt(rsq); rexp = exp(-r*rhoinv[itype][jtype]); forcebuck = buck1[itype][jtype]*r*rexp - buck2[itype][jtype]*r6inv; fforce = factor_lj*forcebuck*r2inv; phibuck = a[itype][jtype]*rexp - c[itype][jtype]*r6inv - offset[itype][jtype]; return factor_lj*phibuck; } /* ---------------------------------------------------------------------- */ void *PairBuck::extract(char *str, int &dim) { 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 9fa00e13b..f34956afd 100644 --- a/src/pair_buck_coul_cut.cpp +++ b/src/pair_buck_coul_cut.cpp @@ -1,450 +1,445 @@ /* ---------------------------------------------------------------------- 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 "math.h" #include "stdio.h" #include "stdlib.h" #include "pair_buck_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; #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) /* ---------------------------------------------------------------------- */ PairBuckCoulCut::PairBuckCoulCut(LAMMPS *lmp) : Pair(lmp) {} /* ---------------------------------------------------------------------- */ PairBuckCoulCut::~PairBuckCoulCut() { 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(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; - int nall = nlocal + atom->nghost; 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]; - - if (j < nall) factor_coul = factor_lj = 1.0; - else { - factor_coul = special_coul[j/nall]; - factor_lj = special_lj[j/nall]; - j %= nall; - } + 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; r = sqrt(rsq); 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]*sqrt(r2inv); 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_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("Illegal pair_style command"); cut_lj_global = force->numeric(arg[0]); if (narg == 1) cut_coul_global = cut_lj_global; else cut_coul_global = force->numeric(arg[1]); // reset cutoffs that have been explicitly set if (allocated) { int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i+1; j <= atom->ntypes; j++) if (setflag[i][j]) { cut_lj[i][j] = cut_lj_global; 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("Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); double a_one = force->numeric(arg[2]); double rho_one = force->numeric(arg[3]); if (rho_one <= 0) error->all("Incorrect args for pair coefficients"); double c_one = force->numeric(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(arg[5]); if (narg == 7) cut_coul_one = force->numeric(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("Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairBuckCoulCut::init_style() { if (!atom->q_flag) error->all("Pair style buck/coul/cut requires atom attribute q"); int irequest = neighbor->request(this); } /* ---------------------------------------------------------------------- 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("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 PI = 4.0*atan(1.0); 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*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*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); } /* ---------------------------------------------------------------------- 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); } 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); } /* ---------------------------------------------------------------------- */ 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 cc92998f0..130b9efd2 100644 --- a/src/pair_coul_cut.cpp +++ b/src/pair_coul_cut.cpp @@ -1,316 +1,311 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "pair_coul_cut.h" #include "atom.h" #include "comm.h" #include "force.h" #include "neighbor.h" #include "neigh_list.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) /* ---------------------------------------------------------------------- */ 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; - int nall = nlocal + atom->nghost; 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]; - - if (j < nall) factor_coul = 1.0; - else { - factor_coul = special_coul[j/nall]; - j %= nall; - } + 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_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("Illegal pair_style command"); cut_global = force->numeric(arg[0]); // reset cutoffs that have been explicitly set if (allocated) { int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i+1; j <= atom->ntypes; j++) if (setflag[i][j]) cut[i][j] = cut_global; } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairCoulCut::coeff(int narg, char **arg) { if (narg < 2 || narg > 3) error->all("Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); double cut_one = cut_global; if (narg == 3) cut_one = force->numeric(arg[2]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { cut[i][j] = cut_one; scale[i][j] = 1.0; setflag[i][j] = 1; count++; } } if (count == 0) error->all("Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairCoulCut::init_style() { if (!atom->q_flag) error->all("Pair style coul/cut requires atom attribute q"); int irequest = neighbor->request(this); } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairCoulCut::init_one(int i, int j) { if (setflag[i][j] == 0) cut[i][j] = mix_distance(cut[i][i],cut[j][j]); scale[j][i] = scale[i][j]; return cut[i][j]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairCoulCut::write_restart(FILE *fp) { write_restart_settings(fp); int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { fwrite(&setflag[i][j],sizeof(int),1,fp); if (setflag[i][j]) fwrite(&cut[i][j],sizeof(double),1,fp); } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairCoulCut::read_restart(FILE *fp) { read_restart_settings(fp); allocate(); int i,j; int me = comm->me; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp); MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world); if (setflag[i][j]) { if (me == 0) fread(&cut[i][j],sizeof(double),1,fp); MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairCoulCut::write_restart_settings(FILE *fp) { fwrite(&cut_global,sizeof(double),1,fp); fwrite(&offset_flag,sizeof(int),1,fp); fwrite(&mix_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairCoulCut::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&cut_global,sizeof(double),1,fp); fread(&offset_flag,sizeof(int),1,fp); fread(&mix_flag,sizeof(int),1,fp); } MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world); MPI_Bcast(&offset_flag,1,MPI_INT,0,world); MPI_Bcast(&mix_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- */ double PairCoulCut::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r2inv,rinv,forcecoul,phicoul; r2inv = 1.0/rsq; rinv = sqrt(r2inv); forcecoul = force->qqrd2e * atom->q[i]*atom->q[j]*rinv; fforce = factor_coul*forcecoul * r2inv; phicoul = force->qqrd2e * atom->q[i]*atom->q[j]*rinv; return factor_coul*phicoul; } /* ---------------------------------------------------------------------- */ void *PairCoulCut::extract(char *str, int &dim) { dim = 2; if (strcmp(str,"scale") == 0) return (void *) scale; return NULL; } diff --git a/src/pair_coul_debye.cpp b/src/pair_coul_debye.cpp index 7e3b60ee1..ca3d3b09a 100644 --- a/src/pair_coul_debye.cpp +++ b/src/pair_coul_debye.cpp @@ -1,188 +1,183 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "pair_coul_debye.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 MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) /* ---------------------------------------------------------------------- */ PairCoulDebye::PairCoulDebye(LAMMPS *lmp) : PairCoulCut(lmp) {} /* ---------------------------------------------------------------------- */ void PairCoulDebye::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,r,rinv,forcecoul,factor_coul,screening; 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; - int nall = nlocal + atom->nghost; 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]; - - if (j < nall) factor_coul = 1.0; - else { - factor_coul = special_coul[j/nall]; - j %= nall; - } + 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); rinv = 1.0/r; screening = exp(-kappa*r); forcecoul = qqrd2e * qtmp*q[j] * screening * (kappa + 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 * qtmp*q[j] * rinv * screening; if (evflag) ev_tally(i,j,nlocal,newton_pair, 0.0,ecoul,fpair,delx,dely,delz); } } } if (vflag_fdotr) virial_compute(); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairCoulDebye::settings(int narg, char **arg) { if (narg != 2) error->all("Illegal pair_style command"); kappa = force->numeric(arg[0]); cut_global = force->numeric(arg[1]); // reset cutoffs that have been explicitly set if (allocated) { int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i+1; j <= atom->ntypes; j++) if (setflag[i][j]) cut[i][j] = cut_global; } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairCoulDebye::write_restart_settings(FILE *fp) { fwrite(&cut_global,sizeof(double),1,fp); fwrite(&kappa,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 PairCoulDebye::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&cut_global,sizeof(double),1,fp); fread(&kappa,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(&kappa,1,MPI_DOUBLE,0,world); MPI_Bcast(&offset_flag,1,MPI_INT,0,world); MPI_Bcast(&mix_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- */ double PairCoulDebye::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r2inv,r,rinv,forcecoul,phicoul,screening; r2inv = 1.0/rsq; r = sqrt(rsq); rinv = 1.0/r; screening = exp(-kappa*r); forcecoul = force->qqrd2e * atom->q[i]*atom->q[j] * screening * (kappa + rinv); fforce = factor_coul*forcecoul * r2inv; phicoul = force->qqrd2e * atom->q[i]*atom->q[j] * rinv * screening; return factor_coul*phicoul; } diff --git a/src/pair_dpd.cpp b/src/pair_dpd.cpp index 6a42deced..f3db674f8 100644 --- a/src/pair_dpd.cpp +++ b/src/pair_dpd.cpp @@ -1,391 +1,386 @@ /* ---------------------------------------------------------------------- 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 "math.h" #include "stdio.h" #include "stdlib.h" #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 MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define EPSILON 1.0e-10 /* ---------------------------------------------------------------------- */ PairDPD::PairDPD(LAMMPS *lmp) : Pair(lmp) { 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; - int nall = nlocal + atom->nghost; 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]; - - if (j < nall) factor_dpd = 1.0; - else { - factor_dpd = special_lj[j/nall]; - j %= nall; - } + 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_compute(); } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairDPD::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(gamma,n+1,n+1,"pair:gamma"); memory->create(sigma,n+1,n+1,"pair:sigma"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairDPD::settings(int narg, char **arg) { if (narg != 3) error->all("Illegal pair_style command"); temperature = force->numeric(arg[0]); cut_global = force->numeric(arg[1]); seed = force->inumeric(arg[2]); // initialize Marsaglia RNG with processor-unique seed if (seed <= 0) error->all("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("Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); double a0_one = force->numeric(arg[2]); double gamma_one = force->numeric(arg[3]); double cut_one = cut_global; if (narg == 5) cut_one = force->numeric(arg[4]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { 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("Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairDPD::init_style() { if (comm->ghost_velocity == 0) error->all("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( "Pair dpd needs newton pair on for momentum conservation"); int irequest = neighbor->request(this); } /* ---------------------------------------------------------------------- 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("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); } /* ---------------------------------------------------------------------- */ 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 = -a0[itype][jtype] * r * (1.0 - 0.5*r/cut[itype][jtype]); return factor_dpd*phi; } diff --git a/src/pair_dpd_tstat.cpp b/src/pair_dpd_tstat.cpp index 3a22e08ea..b64ff6b0f 100644 --- a/src/pair_dpd_tstat.cpp +++ b/src/pair_dpd_tstat.cpp @@ -1,245 +1,240 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "math.h" #include "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 MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define EPSILON 1.0e-10 /* ---------------------------------------------------------------------- */ PairDPDTstat::PairDPDTstat(LAMMPS *lmp) : PairDPD(lmp) { single_enable = 0; } /* ---------------------------------------------------------------------- */ 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; 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+1; 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; - int nall = nlocal + atom->nghost; 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]; - - if (j < nall) factor_dpd = 1.0; - else { - factor_dpd = special_lj[j/nall]; - j %= nall; - } + 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_compute(); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairDPDTstat::settings(int narg, char **arg) { if (narg != 4) error->all("Illegal pair_style command"); t_start = force->numeric(arg[0]); t_stop = force->numeric(arg[1]); cut_global = force->numeric(arg[2]); seed = force->inumeric(arg[3]); temperature = t_start; // initialize Marsaglia RNG with processor-unique seed if (seed <= 0) error->all("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("Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); double a0_one = 0.0; double gamma_one = force->numeric(arg[2]); double cut_one = cut_global; if (narg == 4) cut_one = force->numeric(arg[3]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { 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("Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- 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); // 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); } diff --git a/src/pair_gauss.cpp b/src/pair_gauss.cpp index ad3d15f4a..cd76d6cf8 100644 --- a/src/pair_gauss.cpp +++ b/src/pair_gauss.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. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author: Sai Jayaraman (Sandia) ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "pair_gauss.h" #include "atom.h" #include "comm.h" #include "force.h" #include "neighbor.h" #include "neigh_list.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define EPSILON 1.0e-10 /* ---------------------------------------------------------------------- */ PairGauss::PairGauss(LAMMPS *lmp) :Pair(lmp) { nextra = 1; pvector = new double[1]; } /* ---------------------------------------------------------------------- */ PairGauss::~PairGauss() { delete [] pvector; if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut); memory->destroy(a); memory->destroy(b); memory->destroy(offset); } } /* ---------------------------------------------------------------------- */ void PairGauss::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair; double r,rsq,r2inv,r6inv,forcelj,rexp; 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 nall = nlocal + atom->nghost; int newton_pair = force->newton_pair; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // loop over neighbors of my atoms for (ii = 0; ii < inum; ii++) { i = ilist[ii]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; + j &= NEIGHMASK; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; jtype = type[j]; // define a Gaussian well to be occupied if // the site it interacts with is within the force maximum if (eflag_global && rsq < 0.5/b[itype][jtype]) occ++; if (rsq < cutsq[itype][jtype]) { r2inv = 1.0/rsq; r = sqrt(rsq); forcelj = - 2.0*a[itype][jtype]*b[itype][jtype] * rsq * exp(-b[itype][jtype]*rsq); fpair = forcelj*r2inv; f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; if (newton_pair || j < nlocal) { f[j][0] -= delx*fpair; f[j][1] -= dely*fpair; f[j][2] -= delz*fpair; } if (eflag) evdwl = -(a[itype][jtype]*exp(-b[itype][jtype]*rsq) - offset[itype][jtype]); if (evflag) ev_tally(i,j,nlocal,newton_pair, evdwl,0.0,fpair,delx,dely,delz); } } } if (eflag_global) pvector[0] = occ; if (vflag_fdotr) virial_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("Illegal pair_style command"); cut_global = atof(arg[0]); // reset cutoffs that have been explicity set if (allocated) { int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i+1; j <= atom->ntypes; j++) if (setflag[i][j]) cut[i][j] = cut_global; } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairGauss::coeff(int narg, char **arg) { if (narg < 4 || narg > 5) error->all("Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo, ihi, jlo, jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); double a_one = atof(arg[2]); double b_one = atof(arg[3]); double cut_one = cut_global; if (narg == 5) cut_one = atof(arg[4]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j<=jhi; j++) { a[i][j] = a_one; b[i][j] = b_one; cut[i][j] = cut_one; setflag[i][j] = 1; count++ ; } } if (count == 0) error->all("Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairGauss::init_one(int i, int j) { if (setflag[i][j] == 0) error->all("All pair coeffs are not set"); if (offset_flag) offset[i][j] = a[i][j]*exp(-b[i][j]*cut[i][j]*cut[i][j]); else offset[i][j] = 0.0; a[j][i] = a[i][j]; b[j][i] = b[i][j]; offset[j][i] = offset[i][j]; return cut[i][j]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairGauss::write_restart(FILE *fp) { write_restart_settings(fp); int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { fwrite(&setflag[i][j],sizeof(int),1,fp); if (setflag[i][j]) { fwrite(&a[i][j],sizeof(double),1,fp); fwrite(&b[i][j],sizeof(double),1,fp); fwrite(&cut[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairGauss::read_restart(FILE *fp) { read_restart_settings(fp); allocate(); int i,j; int me = comm->me; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp); MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world); if (setflag[i][j]) { if (me == 0) { fread(&a[i][j],sizeof(double),1,fp); fread(&b[i][j],sizeof(double),1,fp); fread(&cut[i][j],sizeof(double),1,fp); } MPI_Bcast(&a[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&b[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairGauss::write_restart_settings(FILE *fp) { fwrite(&cut_global,sizeof(double),1,fp); fwrite(&offset_flag,sizeof(int),1,fp); fwrite(&mix_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairGauss::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&cut_global,sizeof(double),1,fp); fread(&offset_flag,sizeof(int),1,fp); fread(&mix_flag,sizeof(int),1,fp); } MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world); MPI_Bcast(&offset_flag,1,MPI_INT,0,world); MPI_Bcast(&mix_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- */ double PairGauss::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r2inv,r6inv,forcelj,philj,r; r = sqrt(rsq); r2inv = 1.0/rsq; philj = -(a[itype][jtype]*exp(-b[itype][jtype]*rsq) - offset[itype][jtype]); forcelj = -2.0*a[itype][jtype]*b[itype][jtype]*rsq*exp(-b[itype][jtype]*rsq); fforce = forcelj*r2inv; return philj; } /* ---------------------------------------------------------------------- */ void *PairGauss::extract(char *str, int &dim) { dim = 2; if (strcmp(str,"a") == 0) return (void *) a; return NULL; } diff --git a/src/pair_lj96_cut.cpp b/src/pair_lj96_cut.cpp index 03b9a4455..4e20798ec 100644 --- a/src/pair_lj96_cut.cpp +++ b/src/pair_lj96_cut.cpp @@ -1,724 +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: Chuanfu Luo (luochuanfu@gmail.com) ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #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 "memory.h" #include "error.h" using namespace LAMMPS_NS; #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) /* ---------------------------------------------------------------------- */ PairLJ96Cut::PairLJ96Cut(LAMMPS *lmp) : Pair(lmp) { respa_enable = 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; - int nall = nlocal + atom->nghost; 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]; - - if (j < nall) factor_lj = 1.0; - else { - factor_lj = special_lj[j/nall]; - j %= nall; - } + 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_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; - int nall = nlocal + atom->nghost; 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]; - - if (j < nall) factor_lj = 1.0; - else { - factor_lj = special_lj[j/nall]; - j %= nall; - } + 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; - int nall = nlocal + atom->nghost; 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]; - - if (j < nall) factor_lj = 1.0; - else { - factor_lj = special_lj[j/nall]; - j %= nall; - } + 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; - int nall = nlocal + atom->nghost; 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]; - - if (j < nall) factor_lj = 1.0; - else { - factor_lj = special_lj[j/nall]; - j %= nall; - } + 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("Illegal pair_style command"); cut_global = force->numeric(arg[0]); // reset cutoffs that have been explicitly set if (allocated) { int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i+1; j <= atom->ntypes; j++) if (setflag[i][j]) cut[i][j] = cut_global; } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairLJ96Cut::coeff(int narg, char **arg) { if (narg < 4 || narg > 5) error->all("Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); double epsilon_one = atof(arg[2]); double sigma_one = atof(arg[3]); double cut_one = cut_global; if (narg == 5) cut_one = atof(arg[4]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { 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("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 && strcmp(update->integrate_style,"respa") == 0) { int respa = 0; if (((Respa *) update->integrate)->level_inner >= 0) respa = 1; if (((Respa *) update->integrate)->level_middle >= 0) respa = 2; if (respa == 0) irequest = neighbor->request(this); else if (respa == 1) { irequest = neighbor->request(this); neighbor->requests[irequest]->id = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respainner = 1; irequest = neighbor->request(this); neighbor->requests[irequest]->id = 3; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respaouter = 1; } else { irequest = neighbor->request(this); neighbor->requests[irequest]->id = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respainner = 1; irequest = neighbor->request(this); neighbor->requests[irequest]->id = 2; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respamiddle = 1; irequest = neighbor->request(this); neighbor->requests[irequest]->id = 3; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respaouter = 1; } } else irequest = neighbor->request(this); // set rRESPA cutoffs if (strcmp(update->integrate_style,"respa") == 0 && ((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("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 PI = 4.0*atan(1.0); 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*PI*all[0]*all[1]*epsilon[i][j] * sig6 * (sig3 - 2.0*rc3) / (6.0*rc6); ptail_ij = 8.0*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); } /* ---------------------------------------------------------------------- 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); } 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 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_cut.cpp b/src/pair_lj_cut.cpp index 2c36c5401..24ba2dad2 100644 --- a/src/pair_lj_cut.cpp +++ b/src/pair_lj_cut.cpp @@ -1,725 +1,705 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author: Paul Crozier (SNL) ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "pair_lj_cut.h" #include "atom.h" #include "comm.h" #include "force.h" #include "neighbor.h" #include "neigh_list.h" #include "neigh_request.h" #include "update.h" #include "integrate.h" #include "respa.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) /* ---------------------------------------------------------------------- */ PairLJCut::PairLJCut(LAMMPS *lmp) : Pair(lmp) { respa_enable = 1; } /* ---------------------------------------------------------------------- */ PairLJCut::~PairLJCut() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cut); memory->destroy(epsilon); memory->destroy(sigma); memory->destroy(lj1); memory->destroy(lj2); memory->destroy(lj3); memory->destroy(lj4); memory->destroy(offset); } } /* ---------------------------------------------------------------------- */ void PairLJCut::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair; double rsq,r2inv,r6inv,forcelj,factor_lj; int *ilist,*jlist,*numneigh,**firstneigh; evdwl = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; double **x = atom->x; double **f = atom->f; int *type = atom->type; int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; 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]; - - if (j < nall) factor_lj = 1.0; - else { - factor_lj = special_lj[j/nall]; - j %= nall; - } + 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_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; - int nall = nlocal + atom->nghost; 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]; - - if (j < nall) factor_lj = 1.0; - else { - factor_lj = special_lj[j/nall]; - j %= nall; - } + 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; - int nall = nlocal + atom->nghost; 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]; - - if (j < nall) factor_lj = 1.0; - else { - factor_lj = special_lj[j/nall]; - j %= nall; - } + 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; - int nall = nlocal + atom->nghost; 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]; - - if (j < nall) factor_lj = 1.0; - else { - factor_lj = special_lj[j/nall]; - j %= nall; - } + 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("Illegal pair_style command"); cut_global = force->numeric(arg[0]); // reset cutoffs that have been explicitly set if (allocated) { int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i+1; j <= atom->ntypes; j++) if (setflag[i][j]) cut[i][j] = cut_global; } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairLJCut::coeff(int narg, char **arg) { if (narg < 4 || narg > 5) error->all("Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(arg[2]); double sigma_one = force->numeric(arg[3]); double cut_one = cut_global; if (narg == 5) cut_one = force->numeric(arg[4]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { epsilon[i][j] = epsilon_one; sigma[i][j] = sigma_one; cut[i][j] = cut_one; setflag[i][j] = 1; count++; } } if (count == 0) error->all("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 && strcmp(update->integrate_style,"respa") == 0) { int respa = 0; if (((Respa *) update->integrate)->level_inner >= 0) respa = 1; if (((Respa *) update->integrate)->level_middle >= 0) respa = 2; if (respa == 0) irequest = neighbor->request(this); else if (respa == 1) { irequest = neighbor->request(this); neighbor->requests[irequest]->id = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respainner = 1; irequest = neighbor->request(this); neighbor->requests[irequest]->id = 3; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respaouter = 1; } else { irequest = neighbor->request(this); neighbor->requests[irequest]->id = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respainner = 1; irequest = neighbor->request(this); neighbor->requests[irequest]->id = 2; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respamiddle = 1; irequest = neighbor->request(this); neighbor->requests[irequest]->id = 3; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->respaouter = 1; } } else irequest = neighbor->request(this); // set rRESPA cutoffs if (strcmp(update->integrate_style,"respa") == 0 && ((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("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 PI = 4.0*atan(1.0); 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*PI*all[0]*all[1]*epsilon[i][j] * sig6 * (sig6 - 3.0*rc6) / (9.0*rc9); ptail_ij = 16.0*PI*all[0]*all[1]*epsilon[i][j] * sig6 * (2.0*sig6 - 3.0*rc6) / (9.0*rc9); } return cut[i][j]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJCut::write_restart(FILE *fp) { write_restart_settings(fp); int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { fwrite(&setflag[i][j],sizeof(int),1,fp); if (setflag[i][j]) { fwrite(&epsilon[i][j],sizeof(double),1,fp); fwrite(&sigma[i][j],sizeof(double),1,fp); fwrite(&cut[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJCut::read_restart(FILE *fp) { read_restart_settings(fp); allocate(); int i,j; int me = comm->me; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp); MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world); if (setflag[i][j]) { if (me == 0) { fread(&epsilon[i][j],sizeof(double),1,fp); fread(&sigma[i][j],sizeof(double),1,fp); fread(&cut[i][j],sizeof(double),1,fp); } MPI_Bcast(&epsilon[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJCut::write_restart_settings(FILE *fp) { fwrite(&cut_global,sizeof(double),1,fp); fwrite(&offset_flag,sizeof(int),1,fp); fwrite(&mix_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairLJCut::read_restart_settings(FILE *fp) { int me = comm->me; if (me == 0) { fread(&cut_global,sizeof(double),1,fp); fread(&offset_flag,sizeof(int),1,fp); fread(&mix_flag,sizeof(int),1,fp); } MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world); MPI_Bcast(&offset_flag,1,MPI_INT,0,world); MPI_Bcast(&mix_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- */ double PairLJCut::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r2inv,r6inv,forcelj,philj; r2inv = 1.0/rsq; r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); fforce = factor_lj*forcelj*r2inv; philj = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]) - offset[itype][jtype]; return factor_lj*philj; } /* ---------------------------------------------------------------------- */ void *PairLJCut::extract(char *str, int &dim) { dim = 2; if (strcmp(str,"epsilon") == 0) return (void *) epsilon; return NULL; } diff --git a/src/pair_lj_cut_coul_cut.cpp b/src/pair_lj_cut_coul_cut.cpp index c55c50ea6..1ebf1e2e2 100644 --- a/src/pair_lj_cut_coul_cut.cpp +++ b/src/pair_lj_cut_coul_cut.cpp @@ -1,438 +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. ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "pair_lj_cut_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; #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) /* ---------------------------------------------------------------------- */ PairLJCutCoulCut::PairLJCutCoulCut(LAMMPS *lmp) : Pair(lmp) {} /* ---------------------------------------------------------------------- */ 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; - int nall = nlocal + atom->nghost; 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]; - - if (j < nall) factor_coul = factor_lj = 1.0; - else { - factor_coul = special_coul[j/nall]; - factor_lj = special_lj[j/nall]; - j %= nall; - } + 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_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("Illegal pair_style command"); cut_lj_global = force->numeric(arg[0]); if (narg == 1) cut_coul_global = cut_lj_global; else cut_coul_global = force->numeric(arg[1]); // reset cutoffs that have been explicitly set if (allocated) { int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i+1; j <= atom->ntypes; j++) if (setflag[i][j]) { cut_lj[i][j] = cut_lj_global; 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("Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(arg[2]); double sigma_one = force->numeric(arg[3]); double cut_lj_one = cut_lj_global; double cut_coul_one = cut_coul_global; if (narg >= 5) cut_coul_one = cut_lj_one = force->numeric(arg[4]); if (narg == 6) cut_coul_one = force->numeric(arg[5]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { epsilon[i][j] = epsilon_one; sigma[i][j] = sigma_one; cut_lj[i][j] = cut_lj_one; cut_coul[i][j] = cut_coul_one; setflag[i][j] = 1; count++; } } if (count == 0) error->all("Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairLJCutCoulCut::init_style() { if (!atom->q_flag) error->all("Pair style lj/cut/coul/cut requires atom attribute q"); int irequest = neighbor->request(this); } /* ---------------------------------------------------------------------- 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 PI = 4.0*atan(1.0); 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*PI*all[0]*all[1]*epsilon[i][j] * sig6 * (sig6 - 3.0*rc6) / (9.0*rc9); ptail_ij = 16.0*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); } /* ---------------------------------------------------------------------- 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); } 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); } /* ---------------------------------------------------------------------- */ 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; } diff --git a/src/pair_lj_cut_coul_debye.cpp b/src/pair_lj_cut_coul_debye.cpp index e4fb8ce63..f54332a42 100644 --- a/src/pair_lj_cut_coul_debye.cpp +++ b/src/pair_lj_cut_coul_debye.cpp @@ -1,227 +1,222 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "math.h" #include "stdlib.h" #include "pair_lj_cut_coul_debye.h" #include "atom.h" #include "neigh_list.h" #include "force.h" #include "comm.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ PairLJCutCoulDebye::PairLJCutCoulDebye(LAMMPS *lmp) : PairLJCutCoulCut(lmp) {} /* ---------------------------------------------------------------------- */ void PairLJCutCoulDebye::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,rinv,screening; 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; - int nall = nlocal + atom->nghost; 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]; - - if (j < nall) factor_coul = factor_lj = 1.0; - else { - factor_coul = special_coul[j/nall]; - factor_lj = special_lj[j/nall]; - j %= nall; - } + 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]) { r = sqrt(rsq); rinv = 1.0/r; screening = exp(-kappa*r); forcecoul = qqrd2e * qtmp*q[j] * screening * (kappa + rinv); } 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] * rinv * screening; 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_compute(); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairLJCutCoulDebye::settings(int narg, char **arg) { if (narg < 2 || narg > 3) error->all("Illegal pair_style command"); kappa = force->numeric(arg[0]); cut_lj_global = force->numeric(arg[1]); if (narg == 2) cut_coul_global = cut_lj_global; else cut_coul_global = force->numeric(arg[2]); // reset cutoffs that were previously set from data file if (allocated) { int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i+1; j <= atom->ntypes; j++) if (setflag[i][j] == 1) { cut_lj[i][j] = cut_lj_global; cut_coul[i][j] = cut_coul_global; } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairLJCutCoulDebye::write_restart_settings(FILE *fp) { fwrite(&cut_lj_global,sizeof(double),1,fp); fwrite(&cut_coul_global,sizeof(double),1,fp); fwrite(&kappa,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 PairLJCutCoulDebye::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(&kappa,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(&kappa,1,MPI_DOUBLE,0,world); MPI_Bcast(&offset_flag,1,MPI_INT,0,world); MPI_Bcast(&mix_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- */ double PairLJCutCoulDebye::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r2inv,r6inv,r,rinv,screening,forcecoul,forcelj,phicoul,philj; r2inv = 1.0/rsq; if (rsq < cut_coulsq[itype][jtype]) { r = sqrt(rsq); rinv = 1.0/r; screening = exp(-kappa*r); forcecoul = force->qqrd2e * atom->q[i]*atom->q[j] * screening * (kappa + rinv); } 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] * rinv * screening; 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; } diff --git a/src/pair_lj_expand.cpp b/src/pair_lj_expand.cpp index 7f255258d..3b80e5771 100644 --- a/src/pair_lj_expand.cpp +++ b/src/pair_lj_expand.cpp @@ -1,396 +1,391 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "pair_lj_expand.h" #include "atom.h" #include "comm.h" #include "force.h" #include "neigh_list.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) /* ---------------------------------------------------------------------- */ PairLJExpand::PairLJExpand(LAMMPS *lmp) : Pair(lmp) {} /* ---------------------------------------------------------------------- */ PairLJExpand::~PairLJExpand() { 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; - int nall = nlocal + atom->nghost; 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]; - - if (j < nall) factor_lj = 1.0; - else { - factor_lj = special_lj[j/nall]; - j %= nall; - } + 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_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("Illegal pair_style command"); cut_global = force->numeric(arg[0]); // reset cutoffs that have been explicitly set if (allocated) { int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i+1; j <= atom->ntypes; j++) if (setflag[i][j]) cut[i][j] = cut_global; } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairLJExpand::coeff(int narg, char **arg) { if (narg < 5 || narg > 6) error->all("Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(arg[2]); double sigma_one = force->numeric(arg[3]); double shift_one = force->numeric(arg[4]); double cut_one = cut_global; if (narg == 6) cut_one = force->numeric(arg[5]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { 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("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 PI = 4.0*atan(1.0); double sig2 = sigma[i][j]*sigma[i][j]; double sig6 = sig2*sig2*sig2; double shiftcut = shift[i][j] - cut[i][j]; double rc3 = shiftcut*shiftcut*shiftcut; double rc4 = rc3*shiftcut; double rc5 = rc4*shiftcut; double rc6 = rc5*shiftcut; double rc9 = rc6*rc3; double rc10 = rc9*shiftcut; double rc11 = rc10*shiftcut; double rc12 = rc11*shiftcut; double shift2 = shift[i][j]*shift[i][j]; double shift3 = shift2*shift[i][j]; etail_ij = 8.0*PI*all[0]*all[1]*epsilon[i][j] * sig6*((-1.0/(9.0*rc9) + shift[i][j]/(5.0*rc10) - shift2/(11.0*rc11))*sig6 + 1.0/(3.0*rc3) - shift[i][j]/(2.0*rc4) + shift2/(5.0*rc5)); ptail_ij = 8.0*PI*all[0]*all[1]*epsilon[i][j] * sig6* ((-4.0/(3.0*rc9) + 18.0*shift[i][j]/(5.0*rc10) - 36.0*shift2/(11.0*rc11) + shift3/rc12)*sig6 + 2.0/rc3 - 9.0*shift[i][j]/(2.0*rc4) + 18.0*shift2/(5.0*rc5) - shift3/rc6)/3.0; } 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); } /* ---------------------------------------------------------------------- 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); } 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 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; } diff --git a/src/pair_lj_gromacs.cpp b/src/pair_lj_gromacs.cpp index b2c567d94..5f0584b51 100644 --- a/src/pair_lj_gromacs.cpp +++ b/src/pair_lj_gromacs.cpp @@ -1,425 +1,420 @@ /* ---------------------------------------------------------------------- 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 "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #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; #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) /* ---------------------------------------------------------------------- */ PairLJGromacs::PairLJGromacs(LAMMPS *lmp) : Pair(lmp) {} /* ---------------------------------------------------------------------- */ PairLJGromacs::~PairLJGromacs() { 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; - int nall = nlocal + atom->nghost; 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]; - - if (j < nall) factor_lj = 1.0; - else { - factor_lj = special_lj[j/nall]; - j %= nall; - } + 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]); if (rsq > cut_inner_sq[itype][jtype]) { eswitch = t*t*t*(ljsw3[itype][jtype] + ljsw4[itype][jtype]*t) + ljsw5[itype][jtype]; 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_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("Illegal pair_style command"); cut_inner_global = force->numeric(arg[0]); cut_global = force->numeric(arg[1]); if (cut_inner_global <= 0.0 || cut_inner_global > cut_global) error->all("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("Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(arg[2]); double sigma_one = force->numeric(arg[3]); double cut_inner_one = cut_inner_global; double cut_one = cut_global; if (narg == 6) { cut_inner_one = force->numeric(arg[4]); cut_one = force->numeric(arg[5]); } if (cut_inner_one <= 0.0 || cut_inner_one > cut_one) error->all("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("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); } /* ---------------------------------------------------------------------- */ 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]); if (rsq > cut_inner_sq[itype][jtype]) { phiswitch = t*t*t*(ljsw3[itype][jtype] + ljsw4[itype][jtype]*t) + ljsw5[itype][jtype]; 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 83332d9dc..23abf053e 100644 --- a/src/pair_lj_gromacs_coul_gromacs.cpp +++ b/src/pair_lj_gromacs_coul_gromacs.cpp @@ -1,492 +1,487 @@ /* ---------------------------------------------------------------------- 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 "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #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; #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) /* ---------------------------------------------------------------------- */ PairLJGromacsCoulGromacs::PairLJGromacsCoulGromacs(LAMMPS *lmp) : Pair(lmp) {} /* ---------------------------------------------------------------------- */ PairLJGromacsCoulGromacs::~PairLJGromacsCoulGromacs() { 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; - int nall = nlocal + atom->nghost; 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]; - - if (j < nall) factor_coul = factor_lj = 1.0; - else { - factor_coul = special_coul[j/nall]; - factor_lj = special_lj[j/nall]; - j %= nall; - } + 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]); if (rsq > cut_lj_innersq) { eswitch = tlj*tlj*tlj * (ljsw3[itype][jtype] + ljsw4[itype][jtype]*tlj) + ljsw5[itype][jtype]; 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_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("Illegal pair_style command"); cut_lj_inner = force->numeric(arg[0]); cut_lj = force->numeric(arg[1]); if (narg == 2) { cut_coul_inner = cut_lj_inner; cut_coul = cut_lj; } else { cut_coul_inner = force->numeric(arg[2]); cut_coul = force->numeric(arg[3]); } if (cut_lj_inner <= 0.0 || cut_coul_inner < 0.0) error->all("Illegal pair_style command"); if (cut_lj_inner > cut_lj || cut_coul_inner > cut_coul) error->all("Illegal pair_style command"); } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairLJGromacsCoulGromacs::coeff(int narg, char **arg) { if (narg != 4) error->all("Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(arg[2]); double sigma_one = force->numeric(arg[3]); 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("Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairLJGromacsCoulGromacs::init_style() { if (!atom->q_flag) error->all("Pair style lj/gromacs/coul/gromacs requires atom attribute q"); int irequest = neighbor->request(this); 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); } /* ---------------------------------------------------------------------- */ 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]); if (rsq > cut_lj_innersq) { phiswitch = tlj*tlj*tlj * (ljsw3[itype][jtype] + ljsw4[itype][jtype]*tlj) + ljsw5[itype][jtype]; philj += phiswitch; } eng += factor_lj*philj; } return eng; } diff --git a/src/pair_lj_smooth.cpp b/src/pair_lj_smooth.cpp index d49a23bbf..a880735fe 100644 --- a/src/pair_lj_smooth.cpp +++ b/src/pair_lj_smooth.cpp @@ -1,439 +1,434 @@ /* ---------------------------------------------------------------------- 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 "math.h" #include "stdio.h" #include "stdlib.h" #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; #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) /* ---------------------------------------------------------------------- */ PairLJSmooth::PairLJSmooth(LAMMPS *lmp) : Pair(lmp) {} /* ---------------------------------------------------------------------- */ 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; - int nall = nlocal + atom->nghost; 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; - if (j < nall) factor_lj = 1.0; - else { - factor_lj = special_lj[j/nall]; - j %= nall; - } - 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_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("Illegal pair_style command"); cut_inner_global = force->numeric(arg[0]); cut_global = force->numeric(arg[1]); if (cut_inner_global <= 0.0 || cut_inner_global > cut_global) error->all("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("Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); double epsilon_one = force->numeric(arg[2]); double sigma_one = force->numeric(arg[3]); double cut_inner_one = cut_inner_global; double cut_one = cut_global; if (narg == 6) { cut_inner_one = force->numeric(arg[4]); cut_one = force->numeric(arg[5]); } if (cut_inner_one <= 0.0 || cut_inner_one > cut_one) error->all("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("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); } /* ---------------------------------------------------------------------- */ 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_morse.cpp b/src/pair_morse.cpp index d01e227fa..efe169fa9 100644 --- a/src/pair_morse.cpp +++ b/src/pair_morse.cpp @@ -1,331 +1,326 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "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; #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) /* ---------------------------------------------------------------------- */ PairMorse::PairMorse(LAMMPS *lmp) : Pair(lmp) {} /* ---------------------------------------------------------------------- */ 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; - int nall = nlocal + atom->nghost; 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]; - - if (j < nall) factor_lj = 1.0; - else { - factor_lj = special_lj[j/nall]; - j %= nall; - } + 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_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("Illegal pair_style command"); cut_global = force->numeric(arg[0]); // reset cutoffs that have been explicitly set if (allocated) { int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i+1; j <= atom->ntypes; j++) if (setflag[i][j]) cut[i][j] = cut_global; } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairMorse::coeff(int narg, char **arg) { if (narg < 5 || narg > 6) error->all("Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); double d0_one = force->numeric(arg[2]); double alpha_one = force->numeric(arg[3]); double r0_one = force->numeric(arg[4]); double cut_one = cut_global; if (narg == 6) cut_one = force->numeric(arg[5]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { 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("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("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); } /* ---------------------------------------------------------------------- */ 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; } diff --git a/src/pair_soft.cpp b/src/pair_soft.cpp index c58290e35..1d4fa8060 100644 --- a/src/pair_soft.cpp +++ b/src/pair_soft.cpp @@ -1,316 +1,311 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "pair_soft.h" #include "atom.h" #include "comm.h" #include "force.h" #include "update.h" #include "neigh_list.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) /* ---------------------------------------------------------------------- */ PairSoft::PairSoft(LAMMPS *lmp) : Pair(lmp) { PI = 4.0*atan(1.0); } /* ---------------------------------------------------------------------- */ 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; - int nall = nlocal + atom->nghost; 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]; - - if (j < nall) factor_lj = 1.0; - else { - factor_lj = special_lj[j/nall]; - j %= nall; - } + 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 = PI*r/cut[itype][jtype]; if (r > 0.0) fpair = factor_lj * prefactor[itype][jtype] * sin(arg) * 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_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("Illegal pair_style command"); cut_global = force->numeric(arg[0]); // reset cutoffs that have been explicitly set if (allocated) { int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i+1; j <= atom->ntypes; j++) if (setflag[i][j]) cut[i][j] = cut_global; } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairSoft::coeff(int narg, char **arg) { if (narg < 3 || narg > 4) error->all("Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); double prefactor_one = force->numeric(arg[2]); double cut_one = cut_global; if (narg == 4) cut_one = force->numeric(arg[3]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { prefactor[i][j] = prefactor_one; cut[i][j] = cut_one; setflag[i][j] = 1; count++; } } if (count == 0) error->all("Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairSoft::init_one(int i, int j) { // always mix prefactors geometrically if (setflag[i][j] == 0) { prefactor[i][j] = sqrt(prefactor[i][i]*prefactor[j][j]); cut[i][j] = mix_distance(cut[i][i],cut[j][j]); } prefactor[j][i] = prefactor[i][j]; cut[j][i] = cut[i][j]; return cut[i][j]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairSoft::write_restart(FILE *fp) { write_restart_settings(fp); int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { fwrite(&setflag[i][j],sizeof(int),1,fp); if (setflag[i][j]) { fwrite(&prefactor[i][j],sizeof(double),1,fp); fwrite(&cut[i][j],sizeof(double),1,fp); } } } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairSoft::read_restart(FILE *fp) { read_restart_settings(fp); allocate(); int i,j; int me = comm->me; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp); MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world); if (setflag[i][j]) { if (me == 0) { fread(&prefactor[i][j],sizeof(double),1,fp); fread(&cut[i][j],sizeof(double),1,fp); } MPI_Bcast(&prefactor[i][j],1,MPI_DOUBLE,0,world); MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); } } } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairSoft::write_restart_settings(FILE *fp) { fwrite(&cut_global,sizeof(double),1,fp); fwrite(&mix_flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairSoft::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&cut_global,sizeof(double),1,fp); fread(&mix_flag,sizeof(int),1,fp); } MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world); MPI_Bcast(&mix_flag,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- */ double PairSoft::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double r,arg,philj; r = sqrt(rsq); arg = PI*r/cut[itype][jtype]; fforce = factor_lj * prefactor[itype][jtype] * sin(arg) * PI/cut[itype][jtype]/r; philj = prefactor[itype][jtype] * (1.0+cos(arg)); return factor_lj*philj; } /* ---------------------------------------------------------------------- */ void *PairSoft::extract(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 a77dd6b5a..30f1c8eb2 100644 --- a/src/pair_table.cpp +++ b/src/pair_table.cpp @@ -1,968 +1,963 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author: Paul Crozier (SNL) ------------------------------------------------------------------------- */ #include "mpi.h" #include "math.h" #include "stdlib.h" #include "string.h" #include "pair_table.h" #include "atom.h" #include "force.h" #include "comm.h" #include "neigh_list.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define LOOKUP 0 #define LINEAR 1 #define SPLINE 2 #define BITMAP 3 #define R 1 #define RSQ 2 #define BMP 3 #define MAXLINE 1024 /* ---------------------------------------------------------------------- */ PairTable::PairTable(LAMMPS *lmp) : Pair(lmp) { ntables = 0; tables = NULL; } /* ---------------------------------------------------------------------- */ PairTable::~PairTable() { for (int m = 0; m < ntables; m++) free_table(&tables[m]); memory->sfree(tables); if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(tabindex); } } /* ---------------------------------------------------------------------- */ void PairTable::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype,itable; double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair; double rsq,factor_lj,fraction,value,a,b; int *ilist,*jlist,*numneigh,**firstneigh; Table *tb; union_int_float_t rsq_lookup; int tlm1 = tablength - 1; evdwl = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; double **x = atom->x; double **f = atom->f; int *type = atom->type; int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; 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; - if (j < nall) factor_lj = 1.0; - else { - factor_lj = special_lj[j/nall]; - j %= nall; - } - delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; jtype = type[j]; if (rsq < cutsq[itype][jtype]) { tb = &tables[tabindex[itype][jtype]]; if (rsq < tb->innersq) error->one("Pair distance < table inner cutoff"); if (tabstyle == LOOKUP) { itable = static_cast ((rsq - tb->innersq) * tb->invdelta); if (itable >= tlm1) error->one("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("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("Pair distance > table outer cutoff"); b = (rsq - tb->rsq[itable]) * tb->invdelta; a = 1.0 - b; value = a * tb->f[itable] + b * tb->f[itable+1] + ((a*a*a-a)*tb->f2[itable] + (b*b*b-b)*tb->f2[itable+1]) * tb->deltasq6; fpair = factor_lj * value; } else { rsq_lookup.f = rsq; itable = rsq_lookup.i & tb->nmask; itable >>= tb->nshiftbits; fraction = (rsq_lookup.f - tb->rsq[itable]) * tb->drsq[itable]; value = tb->f[itable] + fraction*tb->df[itable]; fpair = factor_lj * value; } f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; if (newton_pair || j < nlocal) { f[j][0] -= delx*fpair; f[j][1] -= dely*fpair; f[j][2] -= delz*fpair; } if (eflag) { if (tabstyle == LOOKUP) evdwl = tb->e[itable]; else if (tabstyle == LINEAR || tabstyle == BITMAP) evdwl = tb->e[itable] + fraction*tb->de[itable]; else evdwl = a * tb->e[itable] + b * tb->e[itable+1] + ((a*a*a-a)*tb->e2[itable] + (b*b*b-b)*tb->e2[itable+1]) * tb->deltasq6; evdwl *= factor_lj; } if (evflag) ev_tally(i,j,nlocal,newton_pair, evdwl,0.0,fpair,delx,dely,delz); } } } if (vflag_fdotr) virial_compute(); } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairTable::allocate() { allocated = 1; int nt = atom->ntypes; memory->create(setflag,nt+1,nt+1,"pair:setflag"); for (int i = 1; i <= nt; i++) for (int j = i; j <= nt; j++) setflag[i][j] = 0; memory->create(cutsq,nt+1,nt+1,"pair:cutsq"); memory->create(tabindex,nt+1,nt+1,"pair:tabindex"); } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairTable::settings(int narg, char **arg) { if (narg != 2) error->all("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("Unknown table style in pair_style command"); tablength = force->inumeric(arg[1]); if (tablength < 2) error->all("Illegal number of pair table entries"); // delete old tables, since cannot just change settings for (int m = 0; m < ntables; m++) free_table(&tables[m]); memory->sfree(tables); if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(tabindex); } allocated = 0; ntables = 0; tables = NULL; } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairTable::coeff(int narg, char **arg) { if (narg != 4 && narg != 5) error->all("Illegal pair_coeff command"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); int me; MPI_Comm_rank(world,&me); tables = (Table *) memory->srealloc(tables,(ntables+1)*sizeof(Table),"pair:tables"); Table *tb = &tables[ntables]; null_table(tb); if (me == 0) read_table(tb,arg[2],arg[3]); bcast_table(tb); // set table cutoff if (narg == 5) tb->cut = force->numeric(arg[4]); else if (tb->rflag) tb->cut = tb->rhi; else tb->cut = tb->rfile[tb->ninput-1]; // error check on table parameters // insure cutoff is within table // for BITMAP tables, file values can be in non-ascending order if (tb->ninput <= 1) error->one("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("Invalid pair table cutoff"); if (rlo <= 0.0) error->all("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("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("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("All pair coeffs are not set"); tabindex[j][i] = tabindex[i][j]; return tables[tabindex[i][j]].cut; } /* ---------------------------------------------------------------------- read a table section from a tabulated potential file only called by proc 0 this function sets these values in Table: ninput,rfile,efile,ffile,rflag,rlo,rhi,fpflag,fplo,fphi,ntablebits ------------------------------------------------------------------------- */ void PairTable::read_table(Table *tb, char *file, char *keyword) { char line[MAXLINE]; // open file FILE *fp = fopen(file,"r"); if (fp == NULL) { char str[128]; sprintf(str,"Cannot open file %s",file); error->one(str); } // loop until section found with matching keyword while (1) { if (fgets(line,MAXLINE,fp) == NULL) error->one("Did not find keyword in table file"); if (strspn(line," \t\n\r") == strlen(line)) continue; // blank line if (line[0] == '#') continue; // comment if (strstr(line,keyword) == line) break; // matching keyword fgets(line,MAXLINE,fp); // no match, skip section param_extract(tb,line); fgets(line,MAXLINE,fp); for (int i = 0; i < tb->ninput; i++) fgets(line,MAXLINE,fp); } // read args on 2nd line of section // allocate table arrays for file values fgets(line,MAXLINE,fp); param_extract(tb,line); memory->create(tb->rfile,tb->ninput,"pair:rfile"); memory->create(tb->efile,tb->ninput,"pair:efile"); memory->create(tb->ffile,tb->ninput,"pair:ffile"); // setup bitmap parameters for table to read in tb->ntablebits = 0; int masklo,maskhi,nmask,nshiftbits; if (tb->rflag == BMP) { while (1 << tb->ntablebits < tb->ninput) tb->ntablebits++; if (1 << tb->ntablebits != tb->ninput) error->one("Bitmapped table is incorrect length in table file"); init_bitmap(tb->rlo,tb->rhi,tb->ntablebits,masklo,maskhi,nmask,nshiftbits); } // read r,e,f table values from file // if rflag set, compute r // if rflag not set, use r from file int itmp; double rtmp; union_int_float_t rsq_lookup; fgets(line,MAXLINE,fp); for (int i = 0; i < tb->ninput; i++) { fgets(line,MAXLINE,fp); sscanf(line,"%d %lg %lg %lg",&itmp,&rtmp,&tb->efile[i],&tb->ffile[i]); if (tb->rflag == R) rtmp = tb->rlo + (tb->rhi - tb->rlo)*i/(tb->ninput-1); else if (tb->rflag == RSQ) { rtmp = tb->rlo*tb->rlo + (tb->rhi*tb->rhi - tb->rlo*tb->rlo)*i/(tb->ninput-1); rtmp = sqrt(rtmp); } else if (tb->rflag == BMP) { rsq_lookup.i = i << nshiftbits; rsq_lookup.i |= masklo; if (rsq_lookup.f < tb->rlo*tb->rlo) { rsq_lookup.i = i << nshiftbits; rsq_lookup.i |= maskhi; } rtmp = sqrtf(rsq_lookup.f); } tb->rfile[i] = rtmp; } // close file fclose(fp); } /* ---------------------------------------------------------------------- broadcast read-in table info from proc 0 to other procs this function communicates these values in Table: ninput,rfile,efile,ffile,rflag,rlo,rhi,fpflag,fplo,fphi ------------------------------------------------------------------------- */ void PairTable::bcast_table(Table *tb) { MPI_Bcast(&tb->ninput,1,MPI_INT,0,world); int me; MPI_Comm_rank(world,&me); if (me > 0) { memory->create(tb->rfile,tb->ninput,"pair:rfile"); memory->create(tb->efile,tb->ninput,"pair:efile"); memory->create(tb->ffile,tb->ninput,"pair:ffile"); } MPI_Bcast(tb->rfile,tb->ninput,MPI_DOUBLE,0,world); MPI_Bcast(tb->efile,tb->ninput,MPI_DOUBLE,0,world); MPI_Bcast(tb->ffile,tb->ninput,MPI_DOUBLE,0,world); MPI_Bcast(&tb->rflag,1,MPI_INT,0,world); if (tb->rflag) { MPI_Bcast(&tb->rlo,1,MPI_DOUBLE,0,world); MPI_Bcast(&tb->rhi,1,MPI_DOUBLE,0,world); } MPI_Bcast(&tb->fpflag,1,MPI_INT,0,world); if (tb->fpflag) { MPI_Bcast(&tb->fplo,1,MPI_DOUBLE,0,world); MPI_Bcast(&tb->fphi,1,MPI_DOUBLE,0,world); } } /* ---------------------------------------------------------------------- build spline representation of e,f over entire range of read-in table this function sets these values in Table: e2file,f2file ------------------------------------------------------------------------- */ void PairTable::spline_table(Table *tb) { memory->create(tb->e2file,tb->ninput,"pair:e2file"); memory->create(tb->f2file,tb->ninput,"pair:f2file"); double ep0 = - tb->ffile[0]; double epn = - tb->ffile[tb->ninput-1]; spline(tb->rfile,tb->efile,tb->ninput,ep0,epn,tb->e2file); if (tb->fpflag == 0) { tb->fplo = (tb->ffile[1] - tb->ffile[0]) / (tb->rfile[1] - tb->rfile[0]); tb->fphi = (tb->ffile[tb->ninput-1] - tb->ffile[tb->ninput-2]) / (tb->rfile[tb->ninput-1] - tb->rfile[tb->ninput-2]); } double fp0 = tb->fplo; double fpn = tb->fphi; spline(tb->rfile,tb->ffile,tb->ninput,fp0,fpn,tb->f2file); } /* ---------------------------------------------------------------------- extract attributes from parameter line in table section format of line: N value R/RSQ/BITMAP lo hi FP fplo fphi N is required, other params are optional ------------------------------------------------------------------------- */ void PairTable::param_extract(Table *tb, char *line) { tb->ninput = 0; tb->rflag = 0; tb->fpflag = 0; char *word = strtok(line," \t\n\r\f"); while (word) { if (strcmp(word,"N") == 0) { word = strtok(NULL," \t\n\r\f"); tb->ninput = atoi(word); } else if (strcmp(word,"R") == 0 || strcmp(word,"RSQ") == 0 || strcmp(word,"BITMAP") == 0) { if (strcmp(word,"R") == 0) tb->rflag = R; else if (strcmp(word,"RSQ") == 0) tb->rflag = RSQ; else if (strcmp(word,"BITMAP") == 0) tb->rflag = BMP; word = strtok(NULL," \t\n\r\f"); tb->rlo = atof(word); word = strtok(NULL," \t\n\r\f"); tb->rhi = atof(word); } else if (strcmp(word,"FP") == 0) { tb->fpflag = 1; word = strtok(NULL," \t\n\r\f"); tb->fplo = atof(word); word = strtok(NULL," \t\n\r\f"); tb->fphi = atof(word); } else { printf("WORD: %s\n",word); error->one("Invalid keyword in pair table parameters"); } word = strtok(NULL," \t\n\r\f"); } if (tb->ninput == 0) error->one("Pair table parameters did not set N"); } /* ---------------------------------------------------------------------- compute r,e,f vectors from splined values ------------------------------------------------------------------------- */ void PairTable::compute_table(Table *tb) { int tlm1 = tablength-1; // inner = inner table bound // cut = outer table bound // delta = table spacing in rsq for N-1 bins double inner; if (tb->rflag) inner = tb->rlo; else inner = tb->rfile[0]; tb->innersq = inner*inner; tb->delta = (tb->cut*tb->cut - tb->innersq) / tlm1; tb->invdelta = 1.0/tb->delta; // direct lookup tables // N-1 evenly spaced bins in rsq from inner to cut // e,f = value at midpt of bin // e,f are N-1 in length since store 1 value at bin midpt // f is converted to f/r when stored in f[i] // e,f are never a match to read-in values, always computed via spline interp if (tabstyle == LOOKUP) { memory->create(tb->e,tlm1,"pair:e"); memory->create(tb->f,tlm1,"pair:f"); double r,rsq; for (int i = 0; i < tlm1; i++) { rsq = tb->innersq + (i+0.5)*tb->delta; r = sqrt(rsq); tb->e[i] = splint(tb->rfile,tb->efile,tb->e2file,tb->ninput,r); tb->f[i] = splint(tb->rfile,tb->ffile,tb->f2file,tb->ninput,r)/r; } } // linear tables // N-1 evenly spaced bins in rsq from inner to cut // rsq,e,f = value at lower edge of bin // de,df values = delta from lower edge to upper edge of bin // rsq,e,f are N in length so de,df arrays can compute difference // f is converted to f/r when stored in f[i] // e,f can match read-in values, else compute via spline interp if (tabstyle == LINEAR) { memory->create(tb->rsq,tablength,"pair:rsq"); memory->create(tb->e,tablength,"pair:e"); memory->create(tb->f,tablength,"pair:f"); memory->create(tb->de,tlm1,"pair:de"); memory->create(tb->df,tlm1,"pair:df"); double r,rsq; for (int i = 0; i < tablength; i++) { rsq = tb->innersq + i*tb->delta; r = sqrt(rsq); tb->rsq[i] = rsq; if (tb->match) { tb->e[i] = tb->efile[i]; tb->f[i] = tb->ffile[i]/r; } else { tb->e[i] = splint(tb->rfile,tb->efile,tb->e2file,tb->ninput,r); tb->f[i] = splint(tb->rfile,tb->ffile,tb->f2file,tb->ninput,r)/r; } } for (int i = 0; i < tlm1; i++) { tb->de[i] = tb->e[i+1] - tb->e[i]; tb->df[i] = tb->f[i+1] - tb->f[i]; } } // cubic spline tables // N-1 evenly spaced bins in rsq from inner to cut // rsq,e,f = value at lower edge of bin // e2,f2 = spline coefficient for each bin // rsq,e,f,e2,f2 are N in length so have N-1 spline bins // f is converted to f/r after e is splined // e,f can match read-in values, else compute via spline interp if (tabstyle == SPLINE) { memory->create(tb->rsq,tablength,"pair:rsq"); memory->create(tb->e,tablength,"pair:e"); memory->create(tb->f,tablength,"pair:f"); memory->create(tb->e2,tablength,"pair:e2"); memory->create(tb->f2,tablength,"pair:f2"); tb->deltasq6 = tb->delta*tb->delta / 6.0; double r,rsq; for (int i = 0; i < tablength; i++) { rsq = tb->innersq + i*tb->delta; r = sqrt(rsq); tb->rsq[i] = rsq; if (tb->match) { tb->e[i] = tb->efile[i]; tb->f[i] = tb->ffile[i]/r; } else { tb->e[i] = splint(tb->rfile,tb->efile,tb->e2file,tb->ninput,r); tb->f[i] = splint(tb->rfile,tb->ffile,tb->f2file,tb->ninput,r); } } // ep0,epn = dE/dr at inner and at cut double ep0 = - tb->f[0]; double epn = - tb->f[tlm1]; spline(tb->rsq,tb->e,tablength,ep0,epn,tb->e2); // fp0,fpn = dh/dg at inner and at cut // h(r) = f(r)/r and g(r) = r^2 // dh/dg = (1/r df/dr - f/r^2) / 2r // dh/dg in secant approx = (f(r2)/r2 - f(r1)/r1) / (g(r2) - g(r1)) double fp0,fpn; double secant_factor = 0.1; if (tb->fpflag) fp0 = (tb->fplo/sqrt(tb->innersq) - tb->f[0]/tb->innersq) / (2.0 * sqrt(tb->innersq)); else { double rsq1 = tb->innersq; double rsq2 = rsq1 + secant_factor*tb->delta; fp0 = (splint(tb->rfile,tb->ffile,tb->f2file,tb->ninput,sqrt(rsq2)) / sqrt(rsq2) - tb->f[0] / sqrt(rsq1)) / (secant_factor*tb->delta); } if (tb->fpflag && tb->cut == tb->rfile[tb->ninput-1]) fpn = (tb->fphi/tb->cut - tb->f[tlm1]/(tb->cut*tb->cut)) / (2.0 * tb->cut); else { double rsq2 = tb->cut * tb->cut; double rsq1 = rsq2 - secant_factor*tb->delta; fpn = (tb->f[tlm1] / sqrt(rsq2) - splint(tb->rfile,tb->ffile,tb->f2file,tb->ninput,sqrt(rsq1)) / sqrt(rsq1)) / (secant_factor*tb->delta); } for (int i = 0; i < tablength; i++) tb->f[i] /= sqrt(tb->rsq[i]); spline(tb->rsq,tb->f,tablength,fp0,fpn,tb->f2); } // bitmapped linear tables // 2^N bins from inner to cut, spaced in bitmapped manner // f is converted to f/r when stored in f[i] // e,f can match read-in values, else compute via spline interp if (tabstyle == BITMAP) { double r; union_int_float_t rsq_lookup; int masklo,maskhi; // linear lookup tables of length ntable = 2^n // stored value = value at lower edge of bin init_bitmap(inner,tb->cut,tablength,masklo,maskhi,tb->nmask,tb->nshiftbits); int ntable = 1 << tablength; int ntablem1 = ntable - 1; memory->create(tb->rsq,ntable,"pair:rsq"); memory->create(tb->e,ntable,"pair:e"); memory->create(tb->f,ntable,"pair:f"); memory->create(tb->de,ntable,"pair:de"); memory->create(tb->df,ntable,"pair:df"); memory->create(tb->drsq,ntable,"pair:drsq"); union_int_float_t minrsq_lookup; minrsq_lookup.i = 0 << tb->nshiftbits; minrsq_lookup.i |= maskhi; for (int i = 0; i < ntable; i++) { rsq_lookup.i = i << tb->nshiftbits; rsq_lookup.i |= masklo; if (rsq_lookup.f < tb->innersq) { rsq_lookup.i = i << tb->nshiftbits; rsq_lookup.i |= maskhi; } r = sqrtf(rsq_lookup.f); tb->rsq[i] = rsq_lookup.f; if (tb->match) { tb->e[i] = tb->efile[i]; tb->f[i] = tb->ffile[i]/r; } else { tb->e[i] = splint(tb->rfile,tb->efile,tb->e2file,tb->ninput,r); tb->f[i] = splint(tb->rfile,tb->ffile,tb->f2file,tb->ninput,r)/r; } minrsq_lookup.f = MIN(minrsq_lookup.f,rsq_lookup.f); } tb->innersq = minrsq_lookup.f; for (int i = 0; i < ntablem1; i++) { tb->de[i] = tb->e[i+1] - tb->e[i]; tb->df[i] = tb->f[i+1] - tb->f[i]; tb->drsq[i] = 1.0/(tb->rsq[i+1] - tb->rsq[i]); } // get the delta values for the last table entries // tables are connected periodically between 0 and ntablem1 tb->de[ntablem1] = tb->e[0] - tb->e[ntablem1]; tb->df[ntablem1] = tb->f[0] - tb->f[ntablem1]; tb->drsq[ntablem1] = 1.0/(tb->rsq[0] - tb->rsq[ntablem1]); // get the correct delta values at itablemax // smallest r is in bin itablemin // largest r is in bin itablemax, which is itablemin-1, // or ntablem1 if itablemin=0 // deltas at itablemax only needed if corresponding rsq < cut*cut // if so, compute deltas between rsq and cut*cut // if tb->match, data at cut*cut is unavailable, so we'll take // deltas at itablemax-1 as a good approximation double e_tmp,f_tmp; int itablemin = minrsq_lookup.i & tb->nmask; itablemin >>= tb->nshiftbits; int itablemax = itablemin - 1; if (itablemin == 0) itablemax = ntablem1; int itablemaxm1 = itablemax - 1; if (itablemax == 0) itablemaxm1 = ntablem1; rsq_lookup.i = itablemax << tb->nshiftbits; rsq_lookup.i |= maskhi; if (rsq_lookup.f < tb->cut*tb->cut) { if (tb->match) { tb->de[itablemax] = tb->de[itablemaxm1]; tb->df[itablemax] = tb->df[itablemaxm1]; tb->drsq[itablemax] = tb->drsq[itablemaxm1]; } else { rsq_lookup.f = tb->cut*tb->cut; r = sqrtf(rsq_lookup.f); e_tmp = splint(tb->rfile,tb->efile,tb->e2file,tb->ninput,r); f_tmp = splint(tb->rfile,tb->ffile,tb->f2file,tb->ninput,r)/r; tb->de[itablemax] = e_tmp - tb->e[itablemax]; tb->df[itablemax] = f_tmp - tb->f[itablemax]; tb->drsq[itablemax] = 1.0/(rsq_lookup.f - tb->rsq[itablemax]); } } } } /* ---------------------------------------------------------------------- set all ptrs in a table to NULL, so can be freed safely ------------------------------------------------------------------------- */ void PairTable::null_table(Table *tb) { tb->rfile = tb->efile = tb->ffile = NULL; tb->e2file = tb->f2file = NULL; tb->rsq = tb->drsq = tb->e = tb->de = NULL; tb->f = tb->df = tb->e2 = tb->f2 = NULL; } /* ---------------------------------------------------------------------- free all arrays in a table ------------------------------------------------------------------------- */ void PairTable::free_table(Table *tb) { memory->destroy(tb->rfile); memory->destroy(tb->efile); memory->destroy(tb->ffile); memory->destroy(tb->e2file); memory->destroy(tb->f2file); memory->destroy(tb->rsq); memory->destroy(tb->drsq); memory->destroy(tb->e); memory->destroy(tb->de); memory->destroy(tb->f); memory->destroy(tb->df); memory->destroy(tb->e2); memory->destroy(tb->f2); } /* ---------------------------------------------------------------------- spline and splint routines modified from Numerical Recipes ------------------------------------------------------------------------- */ void PairTable::spline(double *x, double *y, int n, double yp1, double ypn, double *y2) { int i,k; double p,qn,sig,un; double *u = new double[n]; if (yp1 > 0.99e30) y2[0] = u[0] = 0.0; else { y2[0] = -0.5; u[0] = (3.0/(x[1]-x[0])) * ((y[1]-y[0]) / (x[1]-x[0]) - yp1); } for (i = 1; i < n-1; i++) { sig = (x[i]-x[i-1]) / (x[i+1]-x[i-1]); p = sig*y2[i-1] + 2.0; y2[i] = (sig-1.0) / p; u[i] = (y[i+1]-y[i]) / (x[i+1]-x[i]) - (y[i]-y[i-1]) / (x[i]-x[i-1]); u[i] = (6.0*u[i] / (x[i+1]-x[i-1]) - sig*u[i-1]) / p; } if (ypn > 0.99e30) qn = un = 0.0; else { qn = 0.5; un = (3.0/(x[n-1]-x[n-2])) * (ypn - (y[n-1]-y[n-2]) / (x[n-1]-x[n-2])); } y2[n-1] = (un-qn*u[n-2]) / (qn*y2[n-2] + 1.0); for (k = n-2; k >= 0; k--) y2[k] = y2[k]*y2[k+1] + u[k]; delete [] u; } /* ---------------------------------------------------------------------- */ double PairTable::splint(double *xa, double *ya, double *y2a, int n, double x) { int klo,khi,k; double h,b,a,y; klo = 0; khi = n-1; while (khi-klo > 1) { k = (khi+klo) >> 1; if (xa[k] > x) khi = k; else klo = k; } h = xa[khi]-xa[klo]; a = (xa[khi]-x) / h; b = (x-xa[klo]) / h; y = a*ya[klo] + b*ya[khi] + ((a*a*a-a)*y2a[klo] + (b*b*b-b)*y2a[khi]) * (h*h)/6.0; return y; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairTable::write_restart(FILE *fp) { write_restart_settings(fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairTable::read_restart(FILE *fp) { read_restart_settings(fp); allocate(); } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void PairTable::write_restart_settings(FILE *fp) { fwrite(&tabstyle,sizeof(int),1,fp); fwrite(&tablength,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void PairTable::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&tabstyle,sizeof(int),1,fp); fread(&tablength,sizeof(int),1,fp); } MPI_Bcast(&tabstyle,1,MPI_DOUBLE,0,world); MPI_Bcast(&tablength,1,MPI_INT,0,world); } /* ---------------------------------------------------------------------- */ double PairTable::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { int itable; double fraction,value,a,b,phi; int tlm1 = tablength - 1; Table *tb = &tables[tabindex[itype][jtype]]; if (rsq < tb->innersq) error->one("Pair distance < table inner cutoff"); if (tabstyle == LOOKUP) { itable = static_cast ((rsq-tb->innersq) * tb->invdelta); if (itable >= tlm1) error->one("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("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("Pair distance > table outer cutoff"); b = (rsq - tb->rsq[itable]) * tb->invdelta; a = 1.0 - b; value = a * tb->f[itable] + b * tb->f[itable+1] + ((a*a*a-a)*tb->f2[itable] + (b*b*b-b)*tb->f2[itable+1]) * tb->deltasq6; fforce = factor_lj * value; } else { union_int_float_t rsq_lookup; rsq_lookup.f = rsq; itable = rsq_lookup.i & tb->nmask; itable >>= tb->nshiftbits; fraction = (rsq_lookup.f - tb->rsq[itable]) * tb->drsq[itable]; value = tb->f[itable] + fraction*tb->df[itable]; fforce = factor_lj * value; } if (tabstyle == LOOKUP) phi = tb->e[itable]; else if (tabstyle == LINEAR || tabstyle == BITMAP) phi = tb->e[itable] + fraction*tb->de[itable]; else phi = a * tb->e[itable] + b * tb->e[itable+1] + ((a*a*a-a)*tb->e2[itable] + (b*b*b-b)*tb->e2[itable+1]) * tb->deltasq6; return factor_lj*phi; } /* ---------------------------------------------------------------------- return the Coulomb cutoff for tabled potentials called by KSpace solvers which require that all pairwise cutoffs be the same loop over all tables not just those indexed by tabindex[i][j] since no way to know which tables are active since pair::init() not yet called ------------------------------------------------------------------------- */ void *PairTable::extract(char *str, int &dim) { if (strcmp(str,"cut_coul") != 0) return NULL; if (ntables == 0) error->all("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("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 b755aefb6..430a9604b 100644 --- a/src/pair_yukawa.cpp +++ b/src/pair_yukawa.cpp @@ -1,319 +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. ------------------------------------------------------------------------- */ #include "math.h" #include "stdlib.h" #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; #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) /* ---------------------------------------------------------------------- */ PairYukawa::PairYukawa(LAMMPS *lmp) : Pair(lmp) {} /* ---------------------------------------------------------------------- */ PairYukawa::~PairYukawa() { if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); 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,ecoul,fpair; double rsq,r2inv,r,rinv,screening,forceyukawa,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; int *type = atom->type; int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; double *special_coul = force->special_coul; 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]; - - if (j < nall) factor_coul = 1.0; - else { - factor_coul = special_coul[j/nall]; - j %= nall; - } + 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); rinv = 1.0/r; screening = exp(-kappa*r); forceyukawa = a[itype][jtype] * screening * (kappa + rinv); fpair = factor_coul*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) { ecoul = a[itype][jtype] * screening * rinv - 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_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(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("Illegal pair_style command"); kappa = force->numeric(arg[0]); cut_global = force->numeric(arg[1]); // reset cutoffs that have been explicitly set if (allocated) { int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i+1; j <= atom->ntypes; j++) if (setflag[i][j]) cut[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("Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo,ihi,jlo,jhi; force->bounds(arg[0],atom->ntypes,ilo,ihi); force->bounds(arg[1],atom->ntypes,jlo,jhi); double a_one = force->numeric(arg[2]); double cut_one = cut_global; if (narg == 4) cut_one = force->numeric(arg[3]); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { a[i][j] = a_one; cut[i][j] = cut_one; setflag[i][j] = 1; count++; } } if (count == 0) error->all("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); } /* ---------------------------------------------------------------------- */ 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_coul*forceyukawa * r2inv; phi = a[itype][jtype] * screening * rinv - offset[itype][jtype]; return factor_coul*phi; }