diff --git a/src/MANYBODY/pair_airebo.cpp b/src/MANYBODY/pair_airebo.cpp index fa01ac15a..f6555063d 100644 --- a/src/MANYBODY/pair_airebo.cpp +++ b/src/MANYBODY/pair_airebo.cpp @@ -1,4205 +1,4200 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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) Bugfixes and optimizations: Marcel Fallet & Steve Stuart (Clemson), Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ #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 "my_page.h" #include "math_const.h" #include "math_special.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace MathConst; using namespace MathSpecial; #define 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; + ipage = NULL; + pgsize = oneatom = 0; + nC = nH = NULL; manybody_flag = 1; } /* ---------------------------------------------------------------------- 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); + delete [] ipage; 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_fdotr_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(FLERR,"Illegal pair_style command"); cutlj = force->numeric(FLERR,arg[0]); ljflag = torflag = 1; if (narg == 3) { ljflag = force->inumeric(FLERR,arg[1]); torflag = force->inumeric(FLERR,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(FLERR,"Incorrect args for pair coefficients"); // insure I,J args are * * if (strcmp(arg[0],"*") != 0 || strcmp(arg[1],"*") != 0) error->all(FLERR,"Incorrect args for pair coefficients"); // read 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(FLERR,"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(FLERR,"Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairAIREBO::init_style() { if (atom->tag_enable == 0) error->all(FLERR,"Pair style AIREBO requires atom IDs"); if (force->newton_pair == 0) error->all(FLERR,"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 + // local REBO neighbor list + // create pages if first time or if neighbor pgsize/oneatom has changed + + int create = 0; + if (ipage == NULL) create = 1; + if (pgsize != neighbor->pgsize) create = 1; + if (oneatom != neighbor->oneatom) create = 1; - pgsize = neighbor->pgsize; - oneatom = neighbor->oneatom; - if (maxpage == 0) add_pages(); + if (create) { + delete [] ipage; + pgsize = neighbor->pgsize; + oneatom = neighbor->oneatom; + + int nmypage= comm->nthreads; + ipage = new MyPage[nmypage]; + for (int i = 0; i < nmypage; i++) + ipage[i].init(oneatom,pgsize,PGDELTA); + } } /* ---------------------------------------------------------------------- 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(FLERR,"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,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 (atom->nmax > 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 - int npage = 0; - int npnt = 0; + ipage->reset(); for (ii = 0; ii < allnum; ii++) { i = ilist[ii]; - if (pgsize - npnt < oneatom) { - npnt = 0; - npage++; - if (npage == maxpage) add_pages(); - } - neighptr = &pages[npage][npnt]; n = 0; + neighptr = ipage->vget(); 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(FLERR, - "Neighbor list overflow, boost neigh_modify one or page"); + ipage->vgot(n); + if (ipage->status()) + error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } } /* ---------------------------------------------------------------------- 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 = tee*tee; 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*(powint(cw2,5)))-(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*powint(cw2,4) * 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); } } } } } } /* ---------------------------------------------------------------------- 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*cube(pij); // 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*cube(pji); 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]/square(rijmag))-(rjl[0]/(rjlmag*rjlmag)))); dcosijldrj[1] = ((-rij[1]+rjl[1])/(rijmag*rjlmag)) + (cosijl*((rij[1]/square(rijmag))-(rjl[1]/(rjlmag*rjlmag)))); dcosijldrj[2] = ((-rij[2]+rjl[2])/(rijmag*rjlmag)) + (cosijl*((rij[2]/square(rijmag))-(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-square(om1234))*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-square(om1234)) * (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)); 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; Stb = 0.0; dStb = 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 += (wik*g*exp(lamdajik)); 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*cube(pij); 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 += (wjl*g*exp(lamdaijl)); 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*cube(pji); 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) > sqrt(TOL)) { 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) > sqrt(TOL)) { 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-square(omkijl))*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]/square(rijmag))-(rjl[0]/(rjlmag*rjlmag)))); dcosijldrj[1] = ((-rij[1]+rjl[1])/(rijmag*rjlmag)) + (cosijl*((rij[1]/square(rijmag))-(rjl[1]/(rjlmag*rjlmag)))); dcosijldrj[2] = ((-rij[2]+rjl[2])/(rijmag*rjlmag)) + (cosijl*((rij[2]/square(rijmag))-(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-square(om1234))*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-square(om1234)) * (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[1][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; } -/* ---------------------------------------------------------------------- - add pages to REBO neighbor list -------------------------------------------------------------------------- */ - -void PairAIREBO::add_pages(int howmany) -{ - int toppage = maxpage; - maxpage += howmany*PGDELTA; - - pages = (int **) - memory->srealloc(pages,maxpage*sizeof(int *),"AIREBO:pages"); - for (int i = toppage; 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 = open_potential(filename); if (fp == NULL) { char str[128]; sprintf(str,"Cannot open AIREBO potential file %s",filename); error->one(FLERR,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, d; const double x2 = x*x; const double x3 = x2*x; f = coeffs[0]; f += coeffs[1]*x; d = coeffs[1]; f += coeffs[2]*x2; d += 2.0*coeffs[2]*x; f += coeffs[3]*x3; d += 3.0*coeffs[3]*x2; f += coeffs[4]*x2*x2; d += 4.0*coeffs[4]*x3; f += coeffs[5]*x2*x3; d += 5.0*coeffs[5]*x2*x2; *df = d; return f; } /* ---------------------------------------------------------------------- bicubic spline evaluation ------------------------------------------------------------------------- */ double PairAIREBO::Spbicubic(double x, double y, double coeffs[16], double df[2]) { double f,xn,yn,xn1,yn1,c; int i,j; f = 0.0; df[0] = 0.0; df[1] = 0.0; xn = 1.0; for (i = 0; i < 4; i++) { yn = 1.0; for (j = 0; j < 4; j++) { c = coeffs[i*4+j]; f += c*xn*yn; if (i > 0) df[0] += c * ((double) i) * xn1 * yn; if (j > 0) df[1] += c * ((double) j) * xn * yn1; yn1 = yn; yn *= y; } xn1 = xn; xn *= x; } 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,xn,yn,zn,xn1,yn1,zn1,c; int i,j,k; f = 0.0; df[0] = 0.0; df[1] = 0.0; df[2] = 0.0; xn = 1.0; for (i = 0; i < 4; i++) { ir = (double) i; yn = 1.0; for (j = 0; j < 4; j++) { jr = (double) j; zn = 1.0; for (k = 0; k < 4; k++) { kr = (double) k; c = coeffs[16*i+4*j+k]; f += c*xn*yn*zn; if (i > 0) df[0] += c * ir * xn1 * yn * zn; if (j > 0) df[1] += c * jr * xn * yn1 * zn; if (k > 0) df[2] += c * kr * xn * yn * zn1; zn1 = zn; zn *= z; } yn1 = yn; yn *= y; } xn1 = xn; xn *= x; } 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); + + for (int i = 0; i < comm->nthreads; i++) + bytes += ipage[i].size(); + + bytes += 2*maxlocal * sizeof(double); return bytes; } diff --git a/src/MANYBODY/pair_airebo.h b/src/MANYBODY/pair_airebo.h index fc8378b98..8536d6ab0 100644 --- a/src/MANYBODY/pair_airebo.h +++ b/src/MANYBODY/pair_airebo.h @@ -1,215 +1,215 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #ifdef PAIR_CLASS PairStyle(airebo,PairAIREBO) #else #ifndef LMP_PAIR_AIREBO_H #define LMP_PAIR_AIREBO_H #include "pair.h" +#include "my_page.h" #include "math.h" #include "math_const.h" namespace LAMMPS_NS { class PairAIREBO : public Pair { public: PairAIREBO(class LAMMPS *); virtual ~PairAIREBO(); virtual void compute(int, int); virtual void settings(int, char **); void coeff(int, char **); void init_style(); double init_one(int, int); double memory_usage(); protected: - int **pages; // neighbor list pages int *map; // 0 (C), 1 (H), or -1 (NULL) for each type int me; int ljflag,torflag; // 0/1 if LJ,torsion terms included - int maxlocal; // size of numneigh, firstneigh arrays - int maxpage; // # of pages currently allocated - int pgsize; // size of neighbor page - int oneatom; // max # of neighbors for one atom double cutlj; // user-specified LJ cutoff double cutljrebosq; // cut for when to compute // REBO neighs of ghost atoms double **cutljsq; // LJ cutoffs for C,H types double **lj1,**lj2,**lj3,**lj4; // pre-computed LJ coeffs for C,H types double cut3rebo; // maximum distance for 3rd REBO neigh + int maxlocal; // size of numneigh, firstneigh arrays + int pgsize; // size of neighbor page + int oneatom; // max # of neighbors for one atom + MyPage *ipage; // neighbor list pages int *REBO_numneigh; // # of pair neighbors for each atom int **REBO_firstneigh; // ptr to 1st neighbor of each atom + double *closestdistsq; // closest owned atom dist to each ghost double *nC,*nH; // sum of weighting fns with REBO neighs double smin,Nmin,Nmax,NCmin,NCmax,thmin,thmax; double rcmin[2][2],rcmax[2][2],rcmaxsq[2][2],rcmaxp[2][2]; double Q[2][2],alpha[2][2],A[2][2],rho[2][2],BIJc[2][2][3],Beta[2][2][3]; double rcLJmin[2][2],rcLJmax[2][2],rcLJmaxsq[2][2],bLJmin[2][2],bLJmax[2][2]; double epsilon[2][2],sigma[2][2],epsilonT[2][2]; // spline coefficients double gCdom[5],gC1[4][6],gC2[4][6],gHdom[4],gH[3][6]; double pCCdom[2][2],pCHdom[2][2],pCC[4][4][16],pCH[4][4][16]; double piCCdom[3][2],piCHdom[3][2],piHHdom[3][2]; double piCC[4][4][9][64],piCH[4][4][9][64],piHH[4][4][9][64]; double Tijdom[3][2],Tijc[4][4][9][64]; // spline knot values double PCCf[5][5],PCCdfdx[5][5],PCCdfdy[5][5],PCHf[5][5]; double PCHdfdx[5][5],PCHdfdy[5][5]; double piCCf[5][5][11],piCCdfdx[5][5][11]; double piCCdfdy[5][5][11],piCCdfdz[5][5][11]; double piCHf[5][5][11],piCHdfdx[5][5][11]; double piCHdfdy[5][5][11],piCHdfdz[5][5][11]; double piHHf[5][5][11],piHHdfdx[5][5][11]; double piHHdfdy[5][5][11],piHHdfdz[5][5][11]; double Tf[5][5][10],Tdfdx[5][5][10],Tdfdy[5][5][10],Tdfdz[5][5][10]; void REBO_neigh(); void FREBO(int, int); void FLJ(int, int); void TORSION(int, int); double bondorder(int, int, double *, double, double, double **, int); double bondorderLJ(int, int, double *, double, double, double *, double, double **, int); double gSpline(double, double, int, double *, double *); double PijSpline(double, double, int, int, double *); double piRCSpline(double, double, double, int, int, double *); double TijSpline(double, double, double, double *); - void add_pages(int howmany = 1); void read_file(char *); double Sp5th(double, double *, double *); double Spbicubic(double, double, double *, double *); double Sptricubic(double, double, double, double *, double *); void spline_init(); void allocate(); // ---------------------------------------------------------------------- // S'(t) and S(t) cutoff functions // added to header for inlining // ---------------------------------------------------------------------- /* ---------------------------------------------------------------------- cutoff function Sprime return cutoff and dX = derivative no side effects ------------------------------------------------------------------------- */ inline double Sp(double Xij, double Xmin, double Xmax, double &dX) const { 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(t*MathConst::MY_PI)); dX = (-0.5*MathConst::MY_PI*sin(t*MathConst::MY_PI)) / (Xmax-Xmin); } return cutoff; }; /* ---------------------------------------------------------------------- LJ cutoff function Sp2 return cutoff and dX = derivative no side effects ------------------------------------------------------------------------- */ inline double Sp2(double Xij, double Xmin, double Xmax, double &dX) const { 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 = (1.0-(t*t*(3.0-2.0*t))); dX = 6.0*(t*t-t) / (Xmax-Xmin); } return cutoff; }; /* kronecker delta function returning a double */ inline double kronecker(const int a, const int b) const { return (a == b) ? 1.0 : 0.0; }; }; } #endif #endif /* ERROR/WARNING messages: E: Illegal ... command Self-explanatory. Check the input script syntax and compare to the documentation for the command. You can use -echo screen as a command-line option when running LAMMPS to see the offending line. E: Incorrect args for pair coefficients Self-explanatory. Check the input script or data file. E: Pair style AIREBO requires atom IDs This is a requirement to use the AIREBO potential. E: Pair style AIREBO requires newton pair on See the newton command. This is a restriction to use the AIREBO potential. E: All pair coeffs are not set All pair coefficients must be set in the data file or by the pair_coeff command before running a simulation. E: Neighbor list overflow, boost neigh_modify one or page There are too many neighbors of a single atom. Use the neigh_modify command to increase the neighbor page size and the max number of neighbors allowed for one atom. E: Cannot open AIREBO potential file %s The specified AIREBO potential file cannot be opened. Check that the path and name are correct. */ diff --git a/src/MANYBODY/pair_comb.cpp b/src/MANYBODY/pair_comb.cpp index d5982caf0..2da2fc93d 100644 --- a/src/MANYBODY/pair_comb.cpp +++ b/src/MANYBODY/pair_comb.cpp @@ -1,2121 +1,2131 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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, present: tnshan@sandia.gov) 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 "group.h" #include "update.h" +#include "my_page.h" #include "math_const.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace MathConst; #define MAXLINE 1024 #define DELTA 4 #define PGDELTA 1 #define MAXNEIGH 24 /* ---------------------------------------------------------------------- */ PairComb::PairComb(LAMMPS *lmp) : Pair(lmp) { single_enable = 0; restartinfo = 0; one_coeff = 1; manybody_flag = 1; nmax = 0; NCo = NULL; bbij = 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; sht_num = NULL; sht_first = NULL; - maxpage = 0; - pages = NULL; + + ipage = NULL; + pgsize = oneatom = 0; // 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); memory->destroy(bbij); memory->destroy(sht_num); memory->destroy(sht_first); + delete [] ipage; + 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; 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; int sht_jnum, *sht_jlist, nj; evdwl = ecoul = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = vflag_atom = 0; // Build short range neighbor list Short_neigh(); 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; 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; nj = 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]; sht_jlist = sht_first[i]; sht_jnum = sht_num[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 < sht_jnum; jj++) { j = sht_jlist[jj]; 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 // half i-j loop for (jj = 0; jj < sht_jnum; jj++) { j = sht_jlist[jj]; 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; nj ++; // 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 < sht_jnum; kk++) { k = sht_jlist[kk]; if (j == k) continue; 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],eflag,i,nj,rsq1,zeta_ij, iq,jq,fpair,prefactor,evdwl); // 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 < sht_jnum; kk++) { k = sht_jlist[kk]; if (j == k) continue; 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_fdotr_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(FLERR,"Illegal pair_style command"); } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairComb::coeff(int narg, char **arg) { int i,j,n; if (!allocated) allocate(); if (narg != 3 + atom->ntypes) error->all(FLERR,"Incorrect args for pair coefficients"); // insure I,J args are * * if (strcmp(arg[0],"*") != 0 || strcmp(arg[1],"*") != 0) error->all(FLERR,"Incorrect args for pair coefficients"); // read 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(FLERR,"Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairComb::init_style() { if (atom->tag_enable == 0) error->all(FLERR,"Pair style COMB requires atom IDs"); if (force->newton_pair == 0) error->all(FLERR,"Pair style COMB requires newton pair on"); if (!atom->q_flag) error->all(FLERR,"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; - pgsize = neighbor->pgsize; - oneatom = neighbor->oneatom; - if (maxpage == 0) add_pages(); + // local Comb neighbor list + // create pages if first time or if neighbor pgsize/oneatom has changed + + int create = 0; + if (ipage == NULL) create = 1; + if (pgsize != neighbor->pgsize) create = 1; + if (oneatom != neighbor->oneatom) create = 1; + + if (create) { + delete [] ipage; + pgsize = neighbor->pgsize; + oneatom = neighbor->oneatom; + + int nmypage = comm->nthreads; + ipage = new MyPage[nmypage]; + for (int i = 0; i < nmypage; i++) + ipage[i].init(oneatom,pgsize); + } } /* ---------------------------------------------------------------------- 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(FLERR,"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]; memory->sfree(params); params = NULL; nparams = 0; maxparam = 0; // open file on proc 0 FILE *fp; if (comm->me == 0) { fp = open_potential(file); if (fp == NULL) { char str[128]; sprintf(str,"Cannot open COMB potential file %s",file); error->one(FLERR,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(FLERR,"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(FLERR,"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(FLERR,"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(FLERR,"Potential file has duplicate entry"); n = m; } } if (n < 0) error->all(FLERR,"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.0)); // (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.0)); // (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; params[m].gamma = 1.0; // for the change in pair_comb.h } // set cutmax to max of all params cutmax = cutmin = 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].cutsq > cutmin) cutmin = params[m].cutsq+0.2; 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*MY_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*MY_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, int eflag, int i, int j, double rsq, double zeta_ij, double iq, double jq, double &fforce, double &prefactor, double &eng) { 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); bbij[i][j] = bij; // force 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(MY_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 -(MY_PI2/comb_D) * sin(MY_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(MY_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 -(MY_PI2/(comb_D-comb_R)) * sin(MY_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(MY_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 -(MY_PI2/(comb_D-comb_R)) * sin(MY_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.0); if (qi > qmax) self_tmp += cmax * pow((qi-qmax),4.0); 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.0))); Bsj = param->bigb2 * exp(param->lam22*Dj)* (param->aB2-fabs(pow(param->bB2*(qj-param->Qo2),10.0))); 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.0))); Bsj = param->bigb2 * exp(param->lam22*Dj)* (param->aB2-fabs(pow(param->bB2*(qj-param->Qo2),10.0))); 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,-1.0*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; } /* ---------------------------------------------------------------------- */ 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 nmax = atom->nmax; 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; // 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"); memory->create(NCo,nmax,"pair:NCo"); memory->create(bbij,nmax,MAXNEIGH,"pair:bbij"); memory->create(sht_num,nmax,"pair:sht_num"); - sht_first = (int **) memory->smalloc(nmax*sizeof(int *), - "pair:sht_first"); + sht_first = (int **) memory->smalloc(nmax*sizeof(int *),"pair:sht_first"); // 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 alf,rcoul,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/MY_PIS* exp(-alf*alf*rcoul*rcoul)/rcoul)*esucon/rcoul; calc3 = (erfc(rcoul*alf)/rcoul)*esucon; calc1 = -(alf/MY_PIS*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; 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,esucon; double r3,erfcd,dfafbn1,smf2,dvdrr,alf,alfdpi; r = sqrt(rsq); r3 = r * rsq; alf = 0.20; alfdpi = 2.0*alf/MY_PIS; 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,ii,jj,jnum,itag,jtag; int itype,jtype,iparam_i,iparam_ij; double xtmp,ytmp,ztmp; double rsq1,delr1[3]; int *ilist,*jlist,*numneigh,**firstneigh; double iq,jq,fqi,fqj,fqij,fqjj; double potal,fac11,fac11e,sr1,sr2,sr3; int mr1,mr2,mr3,inty,nj; double **x = atom->x; double *q = atom->q; int *type = atom->type; int *tag = atom->tag; 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]; itag = tag[i]; nj = 0; 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; 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]]; 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; } // three-body interactions 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]; if (rsq1 > params[iparam_ij].cutsq) continue; nj ++; // charge force in Aij and Bij qfo_short(¶ms[iparam_ij],i,nj,rsq1,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(FLERR,str,0); self_d += 4.0 * cmin * pow((qi-qmin),3.0); } if (qi > qmax) { // char str[128]; // sprintf(str,"Pair COMB charge %.10f with force %.10f hit max barrier", // qi,self_d); // error->warning(FLERR,str,0); self_d += 4.0 * cmax * pow((qi-qmax),3.0); } 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 = 1.0 * (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 = 1.0 * rf5 * (cmj1 + 2.0 * iq * cmj2); fqjj = 1.0 * rf5 * (cmi1 + 2.0 * jq * cmi2); } /* ---------------------------------------------------------------------- */ void PairComb::qfo_short(Param *param, int i, int j, double rsq, 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 = bbij[i][j]; //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.0))); Bsj = param->bigb2 * exp(param->lam22*Dj)* (param->aB2-fabs(pow(param->bB2*(qj-param->Qo2),10.0))); 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); - bytes += MAXNEIGH * nmax * sizeof(int); - return bytes; -} /* ---------------------------------------------------------------------- */ void PairComb::Short_neigh() { int nj,itype,jtype,iparam_ij; int inum,jnum,i,j,ii,jj; int *neighptrj,*ilist,*jlist,*numneigh; int **firstneigh; double xtmp,ytmp,ztmp,rr,rsq,delrj[3]; double **x = atom->x; int *type = atom->type; int nlocal = atom->nlocal; int ntype = atom->ntypes; if (atom->nmax > nmax) { memory->sfree(sht_first); nmax = atom->nmax; sht_first = (int **) memory->smalloc(nmax*sizeof(int *), "pair:sht_first"); memory->grow(sht_num,nmax,"pair:sht_num"); memory->grow(NCo,nmax,"pair:NCo"); memory->grow(bbij,nmax,MAXNEIGH,"pair:bbij"); } inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; - int npntj = 0; - int npage = 0; + + // create Comb neighbor list + + ipage->reset(); for (ii = 0; ii < inum; ii++) { i = ilist[ii]; itype = type[i]; - if (pgsize - npntj < oneatom) { - npntj = 0; - npage++; - if (npage == maxpage) add_pages(); - } - nj = 0; - neighptrj = &pages[npage][npntj]; + neighptrj = ipage->vget(); xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; j &= NEIGHMASK; jtype = type[j]; delrj[0] = xtmp - x[j][0]; delrj[1] = ytmp - x[j][1]; delrj[2] = ztmp - x[j][2]; rsq = vec3_dot(delrj,delrj); if (rsq > cutmin) continue; neighptrj[nj++] = j; } sht_first[i] = neighptrj; sht_num[i] = nj; - npntj += nj; + ipage->vgot(nj); + if (ipage->status()) + error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } } -/* ---------------------------------------------------------------------- */ +/* ---------------------------------------------------------------------- + memory usage of local atom-based arrays +------------------------------------------------------------------------- */ -void PairComb::add_pages(int howmany) +double PairComb::memory_usage() { - int toppage = maxpage; - maxpage += howmany*PGDELTA; + double bytes = maxeatom * sizeof(double); + bytes += maxvatom*6 * sizeof(double); + bytes += nmax * sizeof(int); + bytes += nmax * sizeof(int *); + + for (int i = 0; i < comm->nthreads; i++) + bytes += ipage[i].size(); - pages = (int **) - memory->srealloc(pages,maxpage*sizeof(int *),"pair:pages"); - for (int i = toppage; i < maxpage; i++) - memory->create(pages[i],pgsize,"pair:pages[i]"); + bytes += nmax * sizeof(int); + bytes += MAXNEIGH*nmax * sizeof(double); + return bytes; } diff --git a/src/MANYBODY/pair_comb.h b/src/MANYBODY/pair_comb.h index 3131c95b1..cd3947a3d 100644 --- a/src/MANYBODY/pair_comb.h +++ b/src/MANYBODY/pair_comb.h @@ -1,247 +1,248 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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(comb,PairComb) #else #ifndef LMP_PAIR_COMB_H #define LMP_PAIR_COMB_H #include "pair.h" +#include "my_page.h" namespace LAMMPS_NS { class PairComb : public Pair { public: PairComb(class LAMMPS *); virtual ~PairComb(); virtual void compute(int, int); void settings(int, char **); void coeff(int, char **); void init_style(); double init_one(int, int); double memory_usage(); virtual double yasu_char(double *, int &); protected: struct Param { double lam11,lam12,lam21,lam22; double c,d,h; double gamma,powerm; double powern,beta; double biga1,biga2,bigb1,bigb2; double bigd,bigr; double cut,cutsq; double c1,c2,c3,c4; double plp1,plp3,plp6,a123,aconf; double rlm1,rlm2; double romiga,romigb,romigc,romigd,addrep; double QU1,QL1,DU1,DL1,Qo1,dQ1,aB1,bB1,nD1,bD1; double QU2,QL2,DU2,DL2,Qo2,dQ2,aB2,bB2,nD2,bD2; double chi,dj,dk,dl,dm,esm1,esm2,cmn1,cmn2,cml1,cml2; double coulcut, lcut, lcutsq, hfocor; int ielement,jelement,kelement; int powermint; }; double cutmax; // max cutoff for all elements int nelements; // # of unique elements char **elements; // names of unique elements int ***elem2param; // mapping from element triplets to parameters int *map; // mapping from atom types to elements int nparams; // # of stored parameter sets int maxparam; // max # of parameter sets double precision; Param *params; // parameter set for an I-J-K interaction int nmax; double *qf; double *esm, **fafb, **dfafb, **ddfafb, **phin, **dphin, **erpaw; double *charge; int **intype, *typeno; int *NCo, cor_flag, cuo_flag, cuo_flag1, cuo_flag2; double **bbij; + int pgsize; // size of neighbor page + int oneatom; // max # of neighbors for one atom + int *sht_num,**sht_first; // short-range neighbor list + MyPage *ipage; // neighbor list pages + double cutmin; + void allocate(); virtual void read_file(char *); void setup(); virtual void repulsive(Param *, double, double &, int, double &, double, double); double zeta(Param *, double, double, double *, double *); void force_zeta(Param *, int, int, int, double, double, double, double, double &, double &, double &); void attractive(Param *, double, double, double, double *, double *, double *, double *, double *); double elp(Param *, double, double, double *, double *); void flp(Param *, double, double, double *, double *, double *, double *, double *); double comb_fc(double, Param *); double comb_fc_d(double, Param *); double comb_fc2(double); double comb_fc2_d(double); double comb_fc3(double); double comb_fc3_d(double); virtual double comb_fa(double, Param *, double,double); virtual double comb_fa_d(double, Param *, double,double); double comb_bij(double, Param *); double comb_bij_d(double, Param *); inline double comb_gijk(const double costheta, const Param * const param) const { const double comb_c = param->c * param->c; const double comb_d = param->d * param->d; const double hcth = param->h - costheta; return param->gamma*(1.0 + comb_c/comb_d - comb_c / (comb_d + hcth*hcth)); } inline double comb_gijk_d(const double costheta, const Param * const param) const { const double comb_c = param->c * param->c; const double comb_d = param->d * param->d; const double hcth = param->h - costheta; const double numerator = -2.0 * comb_c * hcth; const double denominator = 1.0/(comb_d + hcth*hcth); return param->gamma*numerator*denominator*denominator; } void comb_zetaterm_d(double, double *, double, double *, double, double *, double *, double *, Param *); void costheta_d(double *, double, double *, double, double *, double *, double *); double self(Param *, double, double); void sm_table(); void potal_calc(double &, double &, double &); void tri_point(double, int &, int &, int &, double &, double &, double &, int &); void direct(int,int,int,int,double,double,double,double,double,double, double,double,double,double &,double &); void field(Param *,double,double,double,double &,double &); double qfo_self(Param *, double, double); void qfo_short(Param *, int, int, double, double, double, double &, double &); void qfo_direct (int, int, int, int, double, double, double, double, double, double &); void qfo_field(Param *, double,double ,double ,double &, double &); void qsolve(double *); void Over_cor(Param *, double, int, double &, double &); int pack_reverse_comm(int, int, double *); void unpack_reverse_comm(int, int *, double *); int pack_comm(int , int *, double *, int, int *); void unpack_comm(int , int , double *); - // short range neighbor list - - void add_pages(int howmany = 1); void Short_neigh(); - int maxpage, pgsize, oneatom, **pages; - int *sht_num, **sht_first; // short-range neighbor list - double cutmin; // vector functions, inline for efficiency inline double vec3_dot(const double x[3], const double y[3]) const { return x[0]*y[0] + x[1]*y[1] + x[2]*y[2]; } inline void vec3_add(const double x[3], const double y[3], double * const z) const { z[0] = x[0]+y[0]; z[1] = x[1]+y[1]; z[2] = x[2]+y[2]; } inline void vec3_scale(const double k, const double x[3], double y[3]) const { y[0] = k*x[0]; y[1] = k*x[1]; y[2] = k*x[2]; } inline void vec3_scaleadd(const double k, const double x[3], const double y[3], double * const z) const { z[0] = k*x[0]+y[0]; z[1] = k*x[1]+y[1]; z[2] = k*x[2]+y[2]; } }; } #endif #endif /* ERROR/WARNING messages: E: Illegal ... command Self-explanatory. Check the input script syntax and compare to the documentation for the command. You can use -echo screen as a command-line option when running LAMMPS to see the offending line. E: Incorrect args for pair coefficients Self-explanatory. Check the input script or data file. E: Pair style COMB requires atom IDs This is a requirement to use the AIREBO potential. E: Pair style COMB requires newton pair on See the newton command. This is a restriction to use the COMB potential. E: Pair style COMB requires atom attribute q Self-explanatory. E: All pair coeffs are not set All pair coefficients must be set in the data file or by the pair_coeff command before running a simulation. E: Cannot open COMB potential file %s The specified COMB potential file cannot be opened. Check that the path and name are correct. E: Incorrect format in COMB potential file Incorrect number of words per line in the potential file. E: Illegal COMB parameter One or more of the coefficients defined in the potential file is invalid. E: Potential file has duplicate entry The potential file for a SW or Tersoff potential has more than one entry for the same 3 ordered elements. E: Potential file is missing an entry The potential file for a SW or Tersoff potential does not have a needed entry. W: Pair COMB charge %.10f with force %.10f hit min barrier Something is possibly wrong with your model. W: Pair COMB charge %.10f with force %.10f hit max barrier Something is possibly wrong with your model. */ diff --git a/src/MANYBODY/pair_lcbop.cpp b/src/MANYBODY/pair_lcbop.cpp index 5e7c6974c..cc511d59a 100644 --- a/src/MANYBODY/pair_lcbop.cpp +++ b/src/MANYBODY/pair_lcbop.cpp @@ -1,1297 +1,1292 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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: Dominik Wójt (Wroclaw University of Technology) based on pair_airebo by Ase Henry (MIT) ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "mpi.h" #include "pair_lcbop.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 "my_page.h" #include "math_const.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace MathConst; #define MAXLINE 1024 #define TOL 1.0e-9 #define PGDELTA 1 /* ---------------------------------------------------------------------- */ PairLCBOP::PairLCBOP(LAMMPS *lmp) : Pair(lmp) { single_enable = 0; one_coeff = 1; manybody_flag = 1; ghostneigh = 1; maxlocal = 0; SR_numneigh = NULL; SR_firstneigh = NULL; - maxpage = 0; - pages = NULL; + ipage = NULL; + pgsize = oneatom = 0; + N = NULL; M = NULL; } /* ---------------------------------------------------------------------- check if allocated, since class can be destructed when incomplete ------------------------------------------------------------------------- */ -PairLCBOP::~PairLCBOP() { +PairLCBOP::~PairLCBOP() +{ memory->destroy(SR_numneigh); memory->sfree(SR_firstneigh); - for (int i = 0; i < maxpage; i++) memory->destroy(pages[i]); - memory->sfree(pages); + delete [] ipage; memory->destroy(N); memory->destroy(M); if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); memory->destroy(cutghost); delete [] map; } } /* ---------------------------------------------------------------------- */ void PairLCBOP::compute(int eflag, int vflag) { if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = vflag_atom = 0; SR_neigh(); FSR(eflag,vflag); FLR(eflag,vflag); if (vflag_fdotr) virial_fdotr_compute(); } /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ void PairLCBOP::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"); map = new int[n+1]; } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairLCBOP::settings(int narg, char **arg) { if( narg != 0 ) error->all(FLERR,"Illegal pair_style command"); } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairLCBOP::coeff(int narg, char **arg) { if (!allocated) allocate(); if (narg != 3 + atom->ntypes) error->all(FLERR,"Incorrect args for pair coefficients"); // insure I,J args are * * if (strcmp(arg[0],"*") != 0 || strcmp(arg[1],"*") != 0) error->all(FLERR,"Incorrect args for pair coefficients"); // read args that map atom types to C and NULL // map[i] = which element (0 for C) 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; } else if (strcmp(arg[i],"C") == 0) { map[i-2] = 0; } else error->all(FLERR,"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(FLERR,"Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairLCBOP::init_style() { if (atom->tag_enable == 0) error->all(FLERR,"Pair style LCBOP requires atom IDs"); if (force->newton_pair == 0) error->all(FLERR,"Pair style LCBOP 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 SR neighbor list memory + // local SR neighbor list + // create pages if first time or if neighbor pgsize/oneatom has changed + + int create = 0; + if (ipage == NULL) create = 1; + if (pgsize != neighbor->pgsize) create = 1; + if (oneatom != neighbor->oneatom) create = 1; - pgsize = neighbor->pgsize; - oneatom = neighbor->oneatom; - if (maxpage == 0) add_pages(); + if (create) { + delete [] ipage; + pgsize = neighbor->pgsize; + oneatom = neighbor->oneatom; + + int nmypage = comm->nthreads; + ipage = new MyPage[nmypage]; + for (int i = 0; i < nmypage; i++) + ipage[i].init(oneatom,pgsize,PGDELTA); + } } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairLCBOP::init_one(int i, int j) { if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set"); // cut3rebo = 3 SR distances cut3rebo = 3.0 * r_2; // cutmax = furthest distance from an owned atom // at which another atom will feel force, i.e. the ghost cutoff // for SR term in potential: // interaction = M-K-I-J-L-N with I = owned and J = ghost // I to N is max distance = 3 SR distances // for V_LR term in potential: // r_2_LR // cutghost = SR cutoff used in SR_neigh() for neighbors of ghosts double cutmax = MAX( cut3rebo,r_2_LR ); cutghost[i][j] = r_2; cutLRsq = r_2_LR*r_2_LR; cutghost[j][i] = cutghost[i][j]; r_2_sq = r_2*r_2; return cutmax; } /* ---------------------------------------------------------------------- create SR neighbor list from main neighbor list SR neighbor list stores neighbors of ghost atoms ------------------------------------------------------------------------- */ void PairLCBOP::SR_neigh() { - int i,j,ii,jj,n, - allnum, // number of atoms(both local and ghost) neighbors are stored for - jnum; + int i,j,ii,jj,n,allnum,jnum; double xtmp,ytmp,ztmp,delx,dely,delz,rsq,dS; int *ilist,*jlist,*numneigh,**firstneigh; int *neighptr; double **x = atom->x; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; if (atom->nmax > maxlocal) { // ensure ther is enough space maxlocal = atom->nmax; // for atoms and ghosts allocated memory->destroy(SR_numneigh); memory->sfree(SR_firstneigh); memory->destroy(N); memory->destroy(M); memory->create(SR_numneigh,maxlocal,"LCBOP:numneigh"); SR_firstneigh = (int **) memory->smalloc(maxlocal*sizeof(int *), "LCBOP:firstneigh"); memory->create(N,maxlocal,"LCBOP:N"); memory->create(M,maxlocal,"LCBOP:M"); } allnum = list->inum + list->gnum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // store all SR neighs of owned and ghost atoms // scan full neighbor list of I - int npage = 0; - int npnt = 0; // position in current page + ipage->reset(); for (ii = 0; ii < allnum; ii++) { i = ilist[ii]; - if (pgsize - npnt < oneatom) { // ensure at least oneatom space free at current page - npnt = 0; - npage++; - if (npage == maxpage) add_pages(); - } - neighptr = &pages[npage][npnt]; n = 0; + neighptr = ipage->vget(); xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; N[i] = 0.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; if (rsq < r_2_sq) { neighptr[n++] = j; N[i] += f_c(sqrt(rsq),r_1,r_2,&dS); } } SR_firstneigh[i] = neighptr; SR_numneigh[i] = n; - npnt += n; - if( npnt >= pgsize ) - error->one(FLERR, - "Neighbor list overflow, boost neigh_modify one or page"); + ipage->vgot(n); + if (ipage->status()) + error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } - // calculate M_i + for (ii = 0; ii < allnum; ii++) { i = ilist[ii]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; M[i] = 0.0; jlist = SR_firstneigh[i]; jnum = SR_numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; if (rsq < r_2_sq) { double f_c_ij = f_c(sqrt(rsq),r_1,r_2,&dS); double Nji = N[j]-f_c_ij; // F(xij) = 1-f_c_LR(Nji, 2,3,&dummy) M[i] += f_c_ij * ( 1-f_c_LR(Nji, 2,3,&dS) ); } } } } /* ---------------------------------------------------------------------- Short range forces and energy ------------------------------------------------------------------------- */ void PairLCBOP::FSR(int eflag, int vflag) { int i,j,jj,ii,inum,itag,jtag; double delx,dely,delz,fpair,xtmp,ytmp,ztmp; double r_sq,rijmag,f_c_ij,df_c_ij; double VR,dVRdi,VA,Bij,dVAdi,dVA; double d_f_c_ij,del[3]; int *ilist,*SR_neighs; double **x = atom->x; double **f = atom->f; int *tag = atom->tag; int nlocal = atom->nlocal; int newton_pair = force->newton_pair; inum = list->inum; ilist = list->ilist; // two-body interactions from SR neighbor list, skip half of them for (ii = 0; ii < inum; ii++) { i = ilist[ii]; itag = tag[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; SR_neighs = SR_firstneigh[i]; for (jj = 0; jj < SR_numneigh[i]; jj++) { j = SR_neighs[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; } delx = x[i][0] - x[j][0]; dely = x[i][1] - x[j][1]; delz = x[i][2] - x[j][2]; r_sq = delx*delx + dely*dely + delz*delz; rijmag = sqrt(r_sq); f_c_ij = f_c( rijmag,r_1,r_2,&df_c_ij ); if( f_c_ij <= TOL ) continue; VR = A*exp(-alpha*rijmag); dVRdi = -alpha*VR; dVRdi = dVRdi*f_c_ij + df_c_ij*VR; // VR -> VR * f_c_ij VR *= f_c_ij; VA = dVA = 0.0; { double term = B_1 * exp(-beta_1*rijmag); VA += term; dVA += -beta_1 * term; term = B_2 * exp(-beta_2*rijmag); VA += term; dVA += -beta_2 * term; } dVA = dVA*f_c_ij + df_c_ij*VA; // VA -> VA * f_c_ij VA *= f_c_ij; del[0] = delx; del[1] = dely; del[2] = delz; Bij = bondorder(i,j,del,rijmag,VA,f,vflag_atom); dVAdi = Bij*dVA; // F = (dVRdi+dVAdi)*(-grad rijmag) // grad_i rijmag = \vec{rij} /rijmag // grad_j rijmag = -\vec{rij} /rijmag fpair = -(dVRdi-dVAdi) / rijmag; 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; double evdwl=0.0; if (eflag) evdwl = VR - Bij*VA; if (evflag) ev_tally(i,j,nlocal,newton_pair, evdwl,0.0,fpair,delx,dely,delz); } } } /* ---------------------------------------------------------------------- compute long range forces and energy ------------------------------------------------------------------------- */ void PairLCBOP::FLR(int eflag, int vflag) { int i,j,jj,m,ii,itag,jtag; double delx,dely,delz,fpair,xtmp,ytmp,ztmp; double r_sq,rijmag,f_c_ij,df_c_ij; double V,dVdi; double **x = atom->x; double **f = atom->f; int *tag = atom->tag; int nlocal = atom->nlocal; int newton_pair = force->newton_pair; int inum = list->inum; int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; // two-body interactions from full neighbor list, skip half of them for (ii = 0; ii < inum; ii++) { i = ilist[ii]; itag = tag[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; int *neighs = firstneigh[i]; for (jj = 0; jj < numneigh[i]; jj++) { j = neighs[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; } delx = x[i][0] - x[j][0]; dely = x[i][1] - x[j][1]; delz = x[i][2] - x[j][2]; r_sq = delx*delx + dely*dely + delz*delz; rijmag = sqrt(r_sq); f_c_ij = 1-f_c( rijmag,r_1,r_2,&df_c_ij ); df_c_ij = -df_c_ij; // derivative may be inherited from previous call, see f_c_LR definition f_c_ij *= f_c_LR( rijmag, r_1_LR, r_2_LR, &df_c_ij ); if( f_c_ij <= TOL ) continue; V = dVdi = 0; if( rijmag V * f_c_ij V *= f_c_ij; // F = (dVdi)*(-grad rijmag) // grad_i rijmag = \vec{rij} /rijmag // grad_j rijmag = -\vec{rij} /rijmag fpair = -dVdi / rijmag; 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; double evdwl=0.0; if (eflag) evdwl = V; if (evflag) ev_tally(i,j,nlocal,newton_pair, evdwl,0.0,fpair,delx,dely,delz); } } } /* ---------------------------------------------------------------------- forces for Nij and Mij ------------------------------------------------------------------------- */ void PairLCBOP::FNij( int i, int j, double factor, double **f, int vflag_atom ) { int atomi = i; int atomj = j; int *SR_neighs = SR_firstneigh[i]; double **x = atom->x; for( int k=0; k r_1*r_1 ) { // && riksq < r_2*r_2, if second condition not fulfilled neighbor would not be in the list double rikmag = sqrt(riksq); double df_c_ik; double f_c_ik = f_c( rikmag, r_1, r_2, &df_c_ik ); // F = factor*df_c_ik*(-grad rikmag) // grad_i rikmag = \vec{rik} /rikmag // grad_k rikmag = -\vec{rik} /rikmag double fpair = -factor*df_c_ik / rikmag; f[atomi][0] += rik[0]*fpair; f[atomi][1] += rik[1]*fpair; f[atomi][2] += rik[2]*fpair; f[atomk][0] -= rik[0]*fpair; f[atomk][1] -= rik[1]*fpair; f[atomk][2] -= rik[2]*fpair; if (vflag_atom) v_tally2(atomi,atomk,fpair,rik); } } } } /* ---------------------------------------------------------------------- */ void PairLCBOP::FMij( int i, int j, double factor, double **f, int vflag_atom ) { int atomi = i; int atomj = j; int *SR_neighs = SR_firstneigh[i]; double **x = atom->x; for( int k=0; k TOL ) { double factor2 = factor*df_c_ik*Fx; // F = factor2*(-grad rikmag) // grad_i rikmag = \vec{rik} /rikmag // grad_k rikmag = -\vec{rik} /rikmag double fpair = -factor2 / rikmag; f[atomi][0] += rik[0]*fpair; f[atomi][1] += rik[1]*fpair; f[atomi][2] += rik[2]*fpair; f[atomk][0] -= rik[0]*fpair; f[atomk][1] -= rik[1]*fpair; f[atomk][2] -= rik[2]*fpair; if (vflag_atom) v_tally2(atomi,atomk,fpair,rik); } if( dF > TOL ) { double factor2 = factor*f_c_ik*dF; FNij( atomk, atomi, factor2, f, vflag_atom ); } } } } /* ---------------------------------------------------------------------- Bij function ------------------------------------------------------------------------- */ double PairLCBOP::bondorder(int i, int j, double rij[3], double rijmag, double VA, double **f, int vflag_atom) { double bij, bji; /* bij & bji */{ double rji[3]; rji[0] = -rij[0]; rji[1] = -rij[1]; rji[2] = -rij[2]; bij = b(i,j,rij,rijmag,VA,f,vflag_atom); bji = b(j,i,rji,rijmag,VA,f,vflag_atom); } double Fij_conj; /* F_conj */{ double dummy; double df_c_ij; double f_c_ij = f_c( rijmag, r_1, r_2, &df_c_ij ); double Nij = MIN( 3, N[i]-(f_c_ij) ); double Nji = MIN( 3, N[j]-(f_c_ij) ); // F(xij) = 1-f_c(Nji, 2,3,&dummy) double Mij = M[i] - f_c_ij*( 1-f_c(Nji, 2,3,&dummy) ); double Mji = M[j] - f_c_ij*( 1-f_c(Nij, 2,3,&dummy) ); Mij = MIN( Mij, 3 ); Mji = MIN( Mji, 3 ); double Nij_el, dNij_el_dNij, dNij_el_dMij; double Nji_el, dNji_el_dNji, dNji_el_dMji; { double num_Nij_el = 4 - Mij; double num_Nji_el = 4 - Mji; double den_Nij_el = Nij + 1 - Mij; double den_Nji_el = Nji + 1 - Mji; Nij_el = num_Nij_el / den_Nij_el; Nji_el = num_Nji_el / den_Nji_el; dNij_el_dNij = -Nij_el/den_Nij_el; dNji_el_dNji = -Nji_el/den_Nji_el; dNij_el_dMij = ( -1 + Nij_el ) /den_Nij_el; dNji_el_dMji = ( -1 + Nji_el ) /den_Nji_el; } double Nconj; double dNconj_dNij; double dNconj_dNji; double dNconj_dNel; { double num_Nconj = ( Nij+1 )*( Nji+1 )*( Nij_el+Nji_el ) - 4*( Nij+Nji+2); double den_Nconj = Nij*( 3-Nij )*( Nji+1 ) + Nji*( 3-Nji )*( Nij+1 ) + eps; Nconj = num_Nconj / den_Nconj; if( Nconj <= 0 ) { Nconj = 0; dNconj_dNij = 0; dNconj_dNji = 0; dNconj_dNel = 0; } else if( Nconj >= 1 ) { Nconj = 1; dNconj_dNij = 0; dNconj_dNji = 0; dNconj_dNel = 0; } else { dNconj_dNij = ( ( (Nji+1)*(Nij_el + Nji_el)-4) - Nconj*( (Nji+1)*(3-2*Nij) + Nji*(3-Nji) ) ) /den_Nconj; dNconj_dNji = ( ( (Nij+1)*(Nji_el + Nij_el)-4) - Nconj*( (Nij+1)*(3-2*Nji) + Nij*(3-Nij) ) ) /den_Nconj; dNconj_dNel = (Nij+1)*(Nji+1) / den_Nconj; } } double dF_dNij, dF_dNji, dF_dNconj; Fij_conj = F_conj( Nij, Nji, Nconj, &dF_dNij, &dF_dNji, &dF_dNconj ); /*forces for Nij*/ if( 3-Nij > TOL ) { double factor = -VA*0.5*( dF_dNij + dF_dNconj*( dNconj_dNij + dNconj_dNel*dNij_el_dNij ) ); FNij( i, j, factor, f, vflag_atom ); } /*forces for Nji*/ if( 3-Nji > TOL ) { double factor = -VA*0.5*( dF_dNji + dF_dNconj*( dNconj_dNji + dNconj_dNel*dNji_el_dNji ) ); FNij( j, i, factor, f, vflag_atom ); } /*forces for Mij*/ if( 3-Mij > TOL ) { double factor = -VA*0.5*( dF_dNconj*dNconj_dNel*dNij_el_dMij ); FMij( i, j, factor, f, vflag_atom ); } if( 3-Mji > TOL ) { double factor = -VA*0.5*( dF_dNconj*dNconj_dNel*dNji_el_dMji ); FMij( j, i, factor, f, vflag_atom ); } } double Bij = 0.5*( bij + bji + Fij_conj ); return Bij; } /* ---------------------------------------------------------------------- bij function ------------------------------------------------------------------------- */ double PairLCBOP::b(int i, int j, double rij[3], double rijmag, double VA, double **f, int vflag_atom) { int *SR_neighs = SR_firstneigh[i]; double **x = atom->x; int atomi = i; int atomj = j; //calculate bij magnitude double bij = 1.0; for (int k = 0; k < SR_numneigh[i]; k++) { int atomk = SR_neighs[k]; if (atomk != atomj) { double rik[3]; rik[0] = x[atomi][0]-x[atomk][0]; rik[1] = x[atomi][1]-x[atomk][1]; rik[2] = x[atomi][2]-x[atomk][2]; double rikmag = sqrt((rik[0]*rik[0])+(rik[1]*rik[1])+(rik[2]*rik[2])); double delta_ijk = rijmag-rikmag; double dummy; double f_c_ik = f_c( rikmag, r_1, r_2, &dummy ); double cos_ijk = ((rij[0]*rik[0])+(rij[1]*rik[1])+(rij[2]*rik[2])) / (rijmag*rikmag); cos_ijk = MIN(cos_ijk,1.0); cos_ijk = MAX(cos_ijk,-1.0); double G = gSpline(cos_ijk, &dummy); double H = hSpline(delta_ijk, &dummy); bij += (f_c_ik*G*H); } } bij = pow( bij, -delta ); // bij forces for (int k = 0; k < SR_numneigh[i]; k++) { int atomk = SR_neighs[k]; if (atomk != atomj) { double rik[3]; rik[0] = x[atomi][0]-x[atomk][0]; rik[1] = x[atomi][1]-x[atomk][1]; rik[2] = x[atomi][2]-x[atomk][2]; double rikmag = sqrt((rik[0]*rik[0])+(rik[1]*rik[1])+(rik[2]*rik[2])); double delta_ijk = rijmag-rikmag; double df_c_ik; double f_c_ik = f_c( rikmag, r_1, r_2, &df_c_ik ); double cos_ijk = ((rij[0]*rik[0])+(rij[1]*rik[1])+(rij[2]*rik[2])) / (rijmag*rikmag); cos_ijk = MIN(cos_ijk,1.0); cos_ijk = MAX(cos_ijk,-1.0); double dcos_ijk_dri[3],dcos_ijk_drj[3],dcos_ijk_drk[3]; dcos_ijk_drj[0] = -rik[0] / (rijmag*rikmag) + cos_ijk * rij[0] / (rijmag*rijmag); dcos_ijk_drj[1] = -rik[1] / (rijmag*rikmag) + cos_ijk * rij[1] / (rijmag*rijmag); dcos_ijk_drj[2] = -rik[2] / (rijmag*rikmag) + cos_ijk * rij[2] / (rijmag*rijmag); dcos_ijk_drk[0] = -rij[0] / (rijmag*rikmag) + cos_ijk * rik[0] / (rikmag*rikmag); dcos_ijk_drk[1] = -rij[1] / (rijmag*rikmag) + cos_ijk * rik[1] / (rikmag*rikmag); dcos_ijk_drk[2] = -rij[2] / (rijmag*rikmag) + cos_ijk * rik[2] / (rikmag*rikmag); dcos_ijk_dri[0] = -dcos_ijk_drk[0] - dcos_ijk_drj[0]; dcos_ijk_dri[1] = -dcos_ijk_drk[1] - dcos_ijk_drj[1]; dcos_ijk_dri[2] = -dcos_ijk_drk[2] - dcos_ijk_drj[2]; double dG, dH; double G = gSpline( cos_ijk, &dG ); double H = hSpline( delta_ijk, &dH ); double tmp = -VA*0.5*(-0.5*bij*bij*bij); double fi[3], fj[3], fk[3]; double tmp2 = -tmp*df_c_ik*G*H/rikmag; // F = tmp*df_c_ik*G*H*(-grad rikmag) // grad_i rikmag = \vec{rik} /rikmag // grad_k rikmag = -\vec{rik} /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]; tmp2 = -tmp*f_c_ik*dG*H; // F = tmp*f_c_ik*dG*H*(-grad cos_ijk) // grad_i cos_ijk = dcos_ijk_dri // grad_j cos_ijk = dcos_ijk_drj // grad_k cos_ijk = dcos_ijk_drk fi[0] += tmp2*dcos_ijk_dri[0]; fi[1] += tmp2*dcos_ijk_dri[1]; fi[2] += tmp2*dcos_ijk_dri[2]; fj[0] = tmp2*dcos_ijk_drj[0]; fj[1] = tmp2*dcos_ijk_drj[1]; fj[2] = tmp2*dcos_ijk_drj[2]; fk[0] += tmp2*dcos_ijk_drk[0]; fk[1] += tmp2*dcos_ijk_drk[1]; fk[2] += tmp2*dcos_ijk_drk[2]; tmp2 = -tmp*f_c_ik*G*dH; // F = tmp*f_c_ik*G*dH*(-grad delta_ijk) // grad_i delta_ijk = \vec{rij} /rijmag - \vec{rik} /rijmag // grad_j delta_ijk = -\vec{rij} /rijmag // grad_k delta_ijk = \vec{rik} /rikmag fi[0] += tmp2*( rij[0]/rijmag - rik[0]/rikmag ); fi[1] += tmp2*( rij[1]/rijmag - rik[1]/rikmag ); fi[2] += tmp2*( rij[2]/rijmag - rik[2]/rikmag ); fj[0] += tmp2*( -rij[0]/rijmag ); fj[1] += tmp2*( -rij[1]/rijmag ); fj[2] += tmp2*( -rij[2]/rijmag ); fk[0] += tmp2*( rik[0]/rikmag ); fk[1] += tmp2*( rik[1]/rikmag ); fk[2] += tmp2*( rik[2]/rikmag ); 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) { double rji[3], rki[3]; 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); } } } return bij; } -/* ---------------------------------------------------------------------- - add pages to SR neighbor list -------------------------------------------------------------------------- */ - -void PairLCBOP::add_pages(int howmany) -{ - int toppage = maxpage; - maxpage += howmany*PGDELTA; - - pages = (int **) - memory->srealloc(pages,maxpage*sizeof(int *),"LCBOP:pages"); - for (int i = toppage; i < maxpage; i++) - memory->create(pages[i],pgsize,"LCBOP:pages[i]"); -} - /* ---------------------------------------------------------------------- spline interpolation for G ------------------------------------------------------------------------- */ void PairLCBOP::g_decompose_x( double x, size_t *field_idx, double *offset ) { size_t i=0; while( i<(6-1) && !( x d ) { *dhdx = R_1; return R_0 + R_1*( x-d ); } double result = 1 + C_1*x; *dhdx = C_1*result; double pow_x = x*x; result += 0.5*C_1*C_1*pow_x; pow_x *= x;// == x^3 *dhdx += 4*C_4*pow_x; pow_x *= x;// == x^4 result += C_4*pow_x; pow_x *= x;// == x^5 *dhdx += 6*C_6*pow_x; pow_x *= x;// == x^5 result += C_6*pow_x; return result; } /* ---------------------------------------------------------------------- */ double PairLCBOP::F_conj( double N_ij, double N_ji, double N_conj_ij, double *dFN_ij, double *dFN_ji, double *dFN_ij_conj ) { size_t N_ij_int = MIN( static_cast( floor( N_ij ) ), 2 ); // 2 is the highest number of field size_t N_ji_int = MIN( static_cast( floor( N_ji ) ), 2 ); // cast to suppress warning double x = N_ij - N_ij_int; double y = N_ji - N_ji_int; const TF_conj_field &f0 = F_conj_field[N_ij_int][N_ji_int][0]; const TF_conj_field &f1 = F_conj_field[N_ij_int][N_ji_int][1]; double F_0 = 0; double F_1 = 0; double dF_0_dx = 0, dF_0_dy = 0; double dF_1_dx = 0, dF_1_dy = 0; double l, r; if( N_conj_ij < 1 ) { l = (1-y)* (1-x); r = ( f0.f_00 + x* x* f0.f_x_10 + y* y* f0.f_y_01 ); F_0 += l*r; dF_0_dx += -(1-y)*r +l*2*x* f0.f_x_10; dF_0_dy += -(1-x)*r +l*2*y* f0.f_y_01; l = (1-y)* x; r = ( f0.f_10 + (1-x)*(1-x)*f0.f_x_00 + y* y* f0.f_y_11 ); F_0 += l*r; dF_0_dx += (1-y)*r -l*2*(1-x)*f0.f_x_00; dF_0_dy += -x* r +l*2*y* f0.f_y_11; l = y* (1-x); r = ( f0.f_01 + x* x* f0.f_x_11 + (1-y)*(1-y)*f0.f_y_00 ); F_0 += l*r; dF_0_dx += -y* r +l*2*x* f0.f_x_11; dF_0_dy += (1-x)*r -l*2*(1-y)*f0.f_y_00; l = y* x; r = ( f0.f_11 + (1-x)*(1-x)*f0.f_x_01 + (1-y)*(1-y)*f0.f_y_10 ); F_0 += l*r; dF_0_dx += y* r -l*2*(1-x)*f0.f_x_01; dF_0_dy += x* r -l*2*(1-y)*f0.f_y_10; } if( N_conj_ij > 0 ) { l = (1-y)* (1-x); r = ( f0.f_00 + x* x* f1.f_x_10 + y* y* f1.f_y_01 ); F_1 += l*r; dF_1_dx += -(1-y)*r +l*2*x* f1.f_x_10; dF_1_dy += -(1-x)*r +l*2*y* f1.f_y_01; l = (1-y)* x; r = ( f1.f_10 + (1-x)*(1-x)*f1.f_x_00 + y* y* f1.f_y_11 ); F_1 += l*r; dF_1_dx += (1-y)*r -l*2*(1-x)*f1.f_x_00; dF_1_dy += -x* r +l*2*y* f1.f_y_11; l = y* (1-x); r = ( f1.f_01 + x* x* f1.f_x_11 + (1-y)*(1-y)*f1.f_y_00 ); F_1 += l*r; dF_1_dx += -y* r +l*2*x* f1.f_x_11; dF_1_dy += (1-x)*r -l*2*(1-y)*f1.f_y_00; l = y* x; r = ( f1.f_11 + (1-x)*(1-x)*f1.f_x_01 + (1-y)*(1-y)*f1.f_y_10 ); F_1 += l*r; dF_1_dx += y* r -l*2*(1-x)*f1.f_x_01; dF_1_dy += x* r -l*2*(1-y)*f1.f_y_10; } double result = (1-N_conj_ij)*F_0 + N_conj_ij*F_1; *dFN_ij = (1-N_conj_ij)*dF_0_dx + N_conj_ij*dF_1_dx; *dFN_ji = (1-N_conj_ij)*dF_0_dy + N_conj_ij*dF_1_dy; *dFN_ij_conj = -F_0 + F_1; return result; } /* ---------------------------------------------------------------------- read LCBOP potential file ------------------------------------------------------------------------- */ void PairLCBOP::read_file(char *filename) { int i,j,k,l,limit; char s[MAXLINE]; MPI_Comm_rank(world,&me); // read file on proc 0 if (me == 0) { FILE *fp = open_potential(filename); if (fp == NULL) { char str[128]; sprintf(str,"Cannot open LCBOP potential file %s",filename); error->one(FLERR,str); } // skip initial comment lines while (1) { fgets(s,MAXLINE,fp); if (s[0] != '#') break; } // read parameters fgets(s,MAXLINE,fp); sscanf(s,"%lg",&r_1); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&r_2); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&gamma_1); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&A); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&B_1); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&B_2); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&alpha); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&beta_1); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&beta_2); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&d); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&C_1); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&C_4); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&C_6); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&L); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&kappa); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&R_0); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&R_1); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&r_0); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&r_1_LR); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&r_2_LR); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&v_1); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&v_2); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&eps_1); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&eps_2); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&lambda_1); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&lambda_2); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&eps); fgets(s,MAXLINE,fp); sscanf(s,"%lg",&delta); while (1) { fgets(s,MAXLINE,fp); if (s[0] != '#') break; } // F_conj spline for (k = 0; k < 2; k++) { // 2 values of N_ij_conj for (l = 0; l < 3; l++) { // 3 types of data: f, dfdx, dfdy for (i = 0; i < 4; i++) { // 4x4 matrix fgets(s,MAXLINE,fp); sscanf(s,"%lg %lg %lg %lg", &F_conj_data[i][0][k][l], &F_conj_data[i][1][k][l], &F_conj_data[i][2][k][l], &F_conj_data[i][3][k][l]); } while (1) { fgets(s,MAXLINE,fp); if (s[0] != '#') break; } } } // G spline // x coordinates of mesh points fgets(s,MAXLINE,fp); sscanf( s,"%lg %lg %lg %lg %lg %lg", &gX[0], &gX[1], &gX[2], &gX[3], &gX[4], &gX[5] ); for (i = 0; i < 6; i++) { // for each power in polynomial fgets(s,MAXLINE,fp); sscanf( s,"%lg %lg %lg %lg %lg", &gC[i][0], &gC[i][1], &gC[i][2], &gC[i][3], &gC[i][4] ); } fclose(fp); } // broadcast read-in and setup values MPI_Bcast(&r_1 ,1,MPI_DOUBLE,0,world); MPI_Bcast(&r_2 ,1,MPI_DOUBLE,0,world); MPI_Bcast(&gamma_1 ,1,MPI_DOUBLE,0,world); MPI_Bcast(&A ,1,MPI_DOUBLE,0,world); MPI_Bcast(&B_1 ,1,MPI_DOUBLE,0,world); MPI_Bcast(&B_2 ,1,MPI_DOUBLE,0,world); MPI_Bcast(&alpha ,1,MPI_DOUBLE,0,world); MPI_Bcast(&beta_1 ,1,MPI_DOUBLE,0,world); MPI_Bcast(&beta_2 ,1,MPI_DOUBLE,0,world); MPI_Bcast(&d ,1,MPI_DOUBLE,0,world); MPI_Bcast(&C_1 ,1,MPI_DOUBLE,0,world); MPI_Bcast(&C_4 ,1,MPI_DOUBLE,0,world); MPI_Bcast(&C_6 ,1,MPI_DOUBLE,0,world); MPI_Bcast(&L ,1,MPI_DOUBLE,0,world); MPI_Bcast(&kappa ,1,MPI_DOUBLE,0,world); MPI_Bcast(&R_0 ,1,MPI_DOUBLE,0,world); MPI_Bcast(&R_1 ,1,MPI_DOUBLE,0,world); MPI_Bcast(&r_0 ,1,MPI_DOUBLE,0,world); MPI_Bcast(&r_1_LR ,1,MPI_DOUBLE,0,world); MPI_Bcast(&r_2_LR ,1,MPI_DOUBLE,0,world); MPI_Bcast(&v_1 ,1,MPI_DOUBLE,0,world); MPI_Bcast(&v_2 ,1,MPI_DOUBLE,0,world); MPI_Bcast(&eps_1 ,1,MPI_DOUBLE,0,world); MPI_Bcast(&eps_2 ,1,MPI_DOUBLE,0,world); MPI_Bcast(&lambda_1 ,1,MPI_DOUBLE,0,world); MPI_Bcast(&lambda_2 ,1,MPI_DOUBLE,0,world); MPI_Bcast(&eps ,1,MPI_DOUBLE,0,world); MPI_Bcast(&delta ,1,MPI_DOUBLE,0,world); MPI_Bcast(&gX[0] ,6,MPI_DOUBLE,0,world); MPI_Bcast(&gC[0][0] ,(6-1)*(5+1),MPI_DOUBLE,0,world); MPI_Bcast(&F_conj_data[0],6*4*4,MPI_DOUBLE,0,world); } /* ---------------------------------------------------------------------- init coefficients for TF_conj ------------------------------------------------------------------------- */ #include #include #include template< class function > void print_function( double x_0, double x_1, size_t n, function f, std::ostream &stream ) { double dx = (x_1-x_0)/n; for( double x=x_0; x<=x_1+0.0001; x+=dx ) { double f_val, df; f_val = f(x, &df); stream << x << " " << f_val << " " << df << std::endl; } stream << std::endl; } void PairLCBOP::spline_init() { for( size_t N_conj_ij=0; N_conj_ij<2; N_conj_ij++ ) // N_conj_ij for( size_t N_ij=0; N_ij<4-1; N_ij++ ) for( size_t N_ji=0; N_ji<4-1; N_ji++ ) { TF_conj_field &field = F_conj_field[N_ij][N_ji][N_conj_ij]; field.f_00 = F_conj_data[N_ij ][N_ji ][N_conj_ij][0]; field.f_01 = F_conj_data[N_ij ][N_ji+1][N_conj_ij][0]; field.f_10 = F_conj_data[N_ij+1][N_ji ][N_conj_ij][0]; field.f_11 = F_conj_data[N_ij+1][N_ji+1][N_conj_ij][0]; field.f_x_00 = F_conj_data[N_ij ][N_ji ][N_conj_ij][1] - field.f_10 + field.f_00; field.f_x_01 = F_conj_data[N_ij ][N_ji+1][N_conj_ij][1] - field.f_11 + field.f_01; field.f_x_10 = -(F_conj_data[N_ij+1][N_ji ][N_conj_ij][1] - field.f_10 + field.f_00); field.f_x_11 = -(F_conj_data[N_ij+1][N_ji+1][N_conj_ij][1] - field.f_11 + field.f_01); field.f_y_00 = F_conj_data[N_ij ][N_ji ][N_conj_ij][2] - field.f_01 + field.f_00; field.f_y_01 = -(F_conj_data[N_ij ][N_ji+1][N_conj_ij][2] - field.f_01 + field.f_00); field.f_y_10 = F_conj_data[N_ij+1][N_ji ][N_conj_ij][2] - field.f_11 + field.f_10; field.f_y_11 = -(F_conj_data[N_ij+1][N_ji+1][N_conj_ij][2] - field.f_11 + field.f_10); } //some testing: // std::ofstream file( "test.txt" ); // file << "gX:\n"; // file << gX[0] << " " // << gX[1] << " " // << gX[2] << " " // << gX[3] << " " // << gX[4] << " " // << gX[5] << std::endl; // file << "gC:\n"; // for( int i=0; i<6; i++ ) // file << gC[i][0] << " " // << gC[i][1] << " " // << gC[i][2] << " " // << gC[i][3] << " " // << gC[i][4] << std::endl; // file << std::endl; // // file << "gamma_1 = " << gamma_1 << std::endl; // file << "r_1 = " << r_1 << std::endl; // file << "r_2 = " << r_2 << std::endl; // file << "A = " << A << std::endl; // file << "B_1 = " << B_1 << std::endl; // file << "B_2 = " << B_2 << std::endl; // file << "alpha = " << alpha << std::endl; // file << "beta_1 = " << beta_1 << std::endl; // file << "beta_2 = " << beta_2 << std::endl; // file << "d = " << d << std::endl; // file << "C_1 = " << C_1 << std::endl; // file << "C_4 = " << C_4 << std::endl; // file << "C_6 = " << C_6 << std::endl; // file << "L = " << L << std::endl; // file << "kappa = " << kappa << std::endl; // file << "R_0 = " << R_0 << std::endl; // file << "R_1 = " << R_1 << std::endl; // file << "r_0 = " << r_0 << std::endl; // file << "r_1_LR = " << r_1_LR << std::endl; // file << "r_2_LR = " << r_2_LR << std::endl; // file << "v_1 = " << v_1 << std::endl; // file << "v_2 = " << v_2 << std::endl; // file << "eps_1 = " << eps_1 << std::endl; // file << "eps_2 = " << eps_2 << std::endl; // file << "lambda_1 = " << lambda_1 << std::endl; // file << "lambda_2 = " << lambda_2 << std::endl; // file << "eps = " << eps << std::endl; // file << "delta = " << delta << std::endl; // file << "r_2_sq = " << r_2_sq << std::endl; // file << std::endl; // // // file << "gSpline:" << std::endl; // double x_1 = 1, x_0 = -1; // int n=1000; // double dx = (x_1-x_0)/n; // for( double x=x_0; x<=x_1+0.0001; x+=dx ) { // double g, dg; // g = gSpline(x, &dg); // file << x << " " << g << " " << dg << std::endl; // } // file << std::endl; // // file << "hSpline:" << std::endl; // double x_1 = 1, x_0 = -1; // int n=1000; // double dx = (x_1-x_0)/n; // for( double x=x_0; x<=x_1+0.0001; x+=dx ) { // double h, dh; // h = hSpline(x, &dh); // file << x << " " << h << " " << dh << std::endl; // } // file << std::endl; // // // file << "f_c:" << std::endl; // double x_1 = 4, x_0 = 0; // int n=1000; // double dx = (x_1-x_0)/n; // for( double x=x_0; x<=x_1+0.0001; x+=dx ) { // double f, df; // f = f_c(x, r_1, r_2, &df); // file << x << " " << f << " " << df << std::endl; // } // file << std::endl; // file << "F_conj_data\n"; // for (int k = 0; k < 2; k++) { // 2 values of N_ij_conj // for (int l = 0; l < 3; l++) { // 3 types of data: f, dfdx, dfdy // for (int i = 0; i < 4; i++) { // 4x4 matrix // file // << F_conj_data[i][0][k][l] << " " // << F_conj_data[i][1][k][l] << " " // << F_conj_data[i][2][k][l] << " " // << F_conj_data[i][3][k][l] << std::endl; // } // file << std::endl; // } // } // // // file << "F_conj_0 "; // double dummy; // for( double y=0; y<=3.0+0.0001; y+=0.1 ) // file << y << " "; // file << std::endl; // for( double x=0; x<=3.0+0.0001; x+=0.1 ){ // file << x << " "; // for( double y=0; y<=3.0+0.0001; y+=0.1 ) // file << F_conj( x, y, 0, &dummy, &dummy, &dummy ) << " "; // file << std::endl; // } // // file << "dF0_dx "; // for( double y=0; y<=3.0+0.0001; y+=0.1 ) // file << y << " "; // file << std::endl; // for( double x=0; x<=3.0+0.0001; x+=0.1 ){ // file << x << " "; // for( double y=0; y<=3.0+0.0001; y+=0.1 ) { // double dF_dx; // F_conj( x, y, 0, &dF_dx, &dummy, &dummy ); // file << dF_dx << " "; // } // file << std::endl; // } // // // // file << "F_conj_1 "; // for( double y=0; y<=3.0+0.0001; y+=0.1 ) // file << y << " "; // file << std::endl; // for( double x=0; x<=3.0+0.0001; x+=0.1 ){ // file << x << " "; // for( double y=0; y<=3.0+0.0001; y+=0.1 ) // file << F_conj( x, y, 0, &dummy, &dummy, &dummy ) << " "; // file << std::endl; // } } /* ---------------------------------------------------------------------- memory usage of local atom-based arrays ------------------------------------------------------------------------- */ -double PairLCBOP::memory_usage() { +double PairLCBOP::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); + + for (int i = 0; i < comm->nthreads; i++) + bytes += ipage[i].size(); + + bytes += 3*maxlocal * sizeof(double); return bytes; } diff --git a/src/MANYBODY/pair_lcbop.h b/src/MANYBODY/pair_lcbop.h index 71567cec9..dc0ad61c7 100644 --- a/src/MANYBODY/pair_lcbop.h +++ b/src/MANYBODY/pair_lcbop.h @@ -1,204 +1,207 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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(lcbop,PairLCBOP) #else #ifndef LMP_PAIR_LCBOP_H #define LMP_PAIR_LCBOP_H #include "pair.h" +#include "my_page.h" #include "math.h" #include "math_const.h" namespace LAMMPS_NS { class PairLCBOP : public Pair { public: PairLCBOP(class LAMMPS *); virtual ~PairLCBOP(); virtual void compute(int, int); virtual void settings(int, char **); void coeff(int, char **); void init_style(); double init_one(int, int); double memory_usage(); protected: int **pages; // neighbor list pages int *map; // 0 (C) or -1 (NULL) for each type int me; - int maxlocal; // size of numneigh, firstneigh arrays - int maxpage; // # of pages currently allocated - int pgsize; // size of neighbor page - int oneatom; // max # of neighbors for one atom double cutLR; // LR cutoff double cutLRsq; // LR cutoff squared double cut3rebo; // maximum distance for 3rd SR neigh + int maxlocal; // size of numneigh, firstneigh arrays + int maxpage; // # of pages currently allocated + int pgsize; // size of neighbor page + int oneatom; // max # of neighbors for one atom + MyPage *ipage; // neighbor list pages int *SR_numneigh; // # of pair neighbors for each atom int **SR_firstneigh; // ptr to 1st neighbor of each atom + double *N; // sum of cutoff fns ( f_C ) with SR neighs double *M; // sum_j f_C_ij*F(N_j - f_C_ij) double r_1, r_2, gamma_1, A, B_1, B_2, alpha, beta_1, beta_2, d, C_1, C_4, C_6, L, kappa, R_0, R_1, r_0, r_1_LR, r_2_LR, v_1, v_2, eps_1, eps_2, lambda_1, lambda_2, eps, delta; double r_2_sq; // splines coefficients struct TF_conj_field { double f_00, f_01, f_10, f_11, f_x_00, f_x_01, f_x_10, f_x_11, f_y_00, f_y_01, f_y_10, f_y_11; } F_conj_field[3][3][2]; + double F_conj_data[4][4][2][3]; // temporary data from file double gX[6]; // x coordinates for described points[# of points]; double gC[5+1][6-1]; // coefficients for each period between described points [degree of polynomial+1][# of points-1] void SR_neigh(); void FSR(int, int); void FLR(int, int); void FNij( int, int, double, double**, int ); void FMij( int, int, double, double**, int ); double bondorder( int, int, double*, double, double, double**, int ); double b ( int, int, double*, double, double, double**, int ); double gSpline( double, double* ); double hSpline( double, double* ); void g_decompose_x( double, size_t*, double* ); double F_conj( double, double, double, double*, double*, double* ); - void add_pages(int howmany = 1); void read_file( char * ); void spline_init(); void allocate(); // ---------------------------------------------------------------------- // S'(t) and S(t) cutoff functions // added to header for inlining // ---------------------------------------------------------------------- /* ---------------------------------------------------------------------- short range cutoff function return cutoff and dX = derivative no side effects ------------------------------------------------------------------------- */ inline double f_c(double Xij, double Xmin, double Xmax, double *dX) const { 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 { double z = t*t*t-1; cutoff = exp( gamma_1*t*t*t/z ); *dX = cutoff * (-3*gamma_1*t*t)/z/z / (Xmax-Xmin); } return cutoff; }; /* ---------------------------------------------------------------------- long range cutoff function return cutoff and dX = derivative no side effects ------------------------------------------------------------------------- */ inline double f_c_LR(double Xij, double Xmin, double Xmax, double *dX) const { double cutoff; double t = (Xij-Xmin) / (Xmax-Xmin); if (t <= 0.0) { cutoff = 1.0; //dX = 0.0; this way the derivative is inherited from previous cut off function call } else if (t >= 1.0) { cutoff = 0.0; *dX = 0.0; } else { cutoff = ( 1.0+cos(MathConst::MY_PI*t) )/2.0; *dX = -MathConst::MY_PI*sin(MathConst::MY_PI*t)/2/(Xmax-Xmin); } return cutoff; }; }; } #endif #endif /* ERROR/WARNING messages: E: Illegal ... command Self-explanatory. Check the input script syntax and compare to the documentation for the command. You can use -echo screen as a command-line option when running LAMMPS to see the offending line. E: Incorrect args for pair coefficients Self-explanatory. Check the input script or data file. E: Pair style LCBOP requires atom IDs This is a requirement to use the LCBOP potential. E: Pair style LCBOP requires newton pair on See the newton command. This is a restriction to use the LCBOP potential. E: All pair coeffs are not set All pair coefficients must be set in the data file or by the pair_coeff command before running a simulation. E: Neighbor list overflow, boost neigh_modify one or page There are too many neighbors of a single atom. Use the neigh_modify command to increase the neighbor page size and the max number of neighbors allowed for one atom. E: Cannot open LCBOP potential file %s The specified LCBOP potential file cannot be opened. Check that the path and name are correct. */ diff --git a/src/USER-OMP/fix_shear_history_omp.cpp b/src/USER-OMP/fix_shear_history_omp.cpp index d410f6363..1fe89de3e 100644 --- a/src/USER-OMP/fix_shear_history_omp.cpp +++ b/src/USER-OMP/fix_shear_history_omp.cpp @@ -1,152 +1,173 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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_omp.h" #include "atom.h" #include "comm.h" #include "neighbor.h" #include "neigh_list.h" #include "force.h" #include "pair.h" #include "update.h" #include "modify.h" #include "error.h" #if defined(_OPENMP) #include #endif using namespace LAMMPS_NS; using namespace FixConst; -#define MAXTOUCH 15 - /* ---------------------------------------------------------------------- copy shear partner info from neighbor lists to atom arrays so can be exchanged with atoms ------------------------------------------------------------------------- */ void FixShearHistoryOMP::pre_exchange() { const int nlocal = atom->nlocal; const int nghost = atom->nghost; const int nall = nlocal + nghost; const int nthreads = comm->nthreads; - - int flag = 0; + maxtouch = 0; + #if defined(_OPENMP) -#pragma omp parallel default(none) shared(flag) +#pragma omp parallel default(none) #endif { #if defined(_OPENMP) const int tid = omp_get_thread_num(); #else const int tid = 0; #endif // each thread works on a fixed chunk of local and ghost atoms. const int ldelta = 1 + nlocal/nthreads; const int lfrom = tid*ldelta; const int lmax = lfrom +ldelta; const int lto = (lmax > nlocal) ? nlocal : lmax; - const int gdelta = 1 + nghost/nthreads; - const int gfrom = nlocal + tid*gdelta; - const int gmax = gfrom + gdelta; - const int gto = (gmax > nall) ? nall : gmax; - - - int i,j,ii,jj,m,inum,jnum; + int i,j,ii,jj,m,n,inum,jnum; int *ilist,*jlist,*numneigh,**firstneigh; int *touch,**firsttouch; double *shear,*allshear,**firstshear; - // zero npartners for all current atoms + // zero npartners for all current atoms and + // clear page data structures for this thread for (i = lfrom; i < lto; i++) npartner[i] = 0; - // copy shear info from neighbor list atoms to atom arrays + MyPage &ipg = ipage[tid]; + MyPage &dpg = dpage[tid]; + ipg.reset(); + dpg.reset(); + + // 1st loop over neighbor list + // calculate nparter for each owned atom 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]) { + if ((i >= lfrom) && (i < lto)) + npartner[i]++; + j = jlist[jj]; j &= NEIGHMASK; + if ((j >= lfrom) && (j < lto)) + npartner[j]++; + } + } + } + + // get page chunks to store atom IDs and shear history for my atoms + + for (ii = lfrom; ii < lto; ii++) { + i = ilist[ii]; + n = npartner[i]; + partner[i] = ipg.get(n); + shearpartner[i] = dpg.get(n); + if (partner[i] == NULL || shearpartner[i] == NULL) + error->one(FLERR,"Shear history overflow, boost neigh_modify one"); + } + + // 2nd loop over neighbor list + // store atom IDs and shear history for my atoms + // re-zero npartner to use as counter for all my atoms + + for (i = lfrom; i < lto; i++) npartner[i] = 0; + + 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 ((i >= lfrom) && (i < lto)) { - 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]; - } + 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 >= lfrom) && (j < lto)) { - 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]++; - } - - if ((j >= gfrom) && (j < gto)) { + 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 myflag = 0; + // set maxtouch = max # of partners of any owned atom + m = 0; for (i = lfrom; i < lto; i++) - if (npartner[i] >= MAXTOUCH) myflag = 1; + m = MAX(m,npartner[i]); - if (myflag) #if defined(_OPENMP) -#pragma omp atomic +#pragma omp critical #endif - ++flag; + maxtouch = MAX(m,maxtouch); } - - int flag_all; - MPI_Allreduce(&flag,&flag_all,1,MPI_INT,MPI_SUM,world); - if (flag_all) - error->all(FLERR,"Too many touching neighbors - boost MAXTOUCH"); } diff --git a/src/USER-OMP/neigh_derive_omp.cpp b/src/USER-OMP/neigh_derive_omp.cpp index 4356f17b6..8f5fa05e8 100644 --- a/src/USER-OMP/neigh_derive_omp.cpp +++ b/src/USER-OMP/neigh_derive_omp.cpp @@ -1,183 +1,162 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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 "neighbor_omp.h" #include "neigh_list.h" #include "atom.h" #include "comm.h" +#include "my_page.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_omp(NeighList *list) { const int inum_full = list->listfull->inum; NEIGH_OMP_INIT; #if defined(_OPENMP) #pragma omp parallel default(none) shared(list) #endif NEIGH_OMP_SETUP(inum_full); int i,j,ii,jj,n,jnum,joriginal; int *neighptr,*jlist; int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; int *ilist_full = list->listfull->ilist; int *numneigh_full = list->listfull->numneigh; int **firstneigh_full = list->listfull->firstneigh; - // each thread works on its own page - int npage = tid; - int npnt = 0; + // each thread has its own page allocator + MyPage &ipage = list->ipage[tid]; + ipage.reset(); // loop over atoms in full list for (ii = ifrom; ii < ito; ii++) { -#if defined(_OPENMP) -#pragma omp critical -#endif - if (pgsize - npnt < oneatom) { - npnt = 0; - npage += nthreads; - // only one thread at a time may check whether we - // need new neighbor list pages and then add to them. - if (npage >= list->maxpage) list->add_pages(nthreads); - } - - neighptr = &(list->pages[npage][npnt]); n = 0; + neighptr = ipage.vget(); // loop over parent full list i = ilist_full[ii]; jlist = firstneigh_full[i]; jnum = numneigh_full[i]; for (jj = 0; jj < jnum; jj++) { joriginal = jlist[jj]; j = joriginal & NEIGHMASK; if (j > i) neighptr[n++] = joriginal; } ilist[ii] = i; firstneigh[i] = neighptr; numneigh[i] = n; - npnt += n; - if (n > oneatom) + ipage.vgot(n); + if (ipage.status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } NEIGH_OMP_CLOSE; list->inum = inum_full; } /* ---------------------------------------------------------------------- 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_omp(NeighList *list) { const int inum_full = list->listfull->inum; NEIGH_OMP_INIT; #if defined(_OPENMP) #pragma omp parallel default(none) shared(list) #endif NEIGH_OMP_SETUP(inum_full); int i,j,ii,jj,n,jnum,joriginal; int *neighptr,*jlist; double xtmp,ytmp,ztmp; double **x = atom->x; int nlocal = atom->nlocal; int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; int *ilist_full = list->listfull->ilist; int *numneigh_full = list->listfull->numneigh; int **firstneigh_full = list->listfull->firstneigh; - // each thread works on its own page - int npage = tid; - int npnt = 0; + // each thread has its own page allocator + MyPage &ipage = list->ipage[tid]; + ipage.reset(); // loop over parent full list for (ii = ifrom; ii < ito; ii++) { -#if defined(_OPENMP) -#pragma omp critical -#endif - if (pgsize - npnt < oneatom) { - npnt = 0; - npage += nthreads; - // only one thread at a time may check whether we - // need new neighbor list pages and then add to them. - if (npage >= list->maxpage) list->add_pages(nthreads); - } - - neighptr = &(list->pages[npage][npnt]); n = 0; + neighptr = ipage.vget(); 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++) { joriginal = jlist[jj]; j = joriginal & NEIGHMASK; if (j < nlocal) { if (i > j) 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; } } neighptr[n++] = joriginal; } ilist[ii] = i; firstneigh[i] = neighptr; numneigh[i] = n; - npnt += n; - if (n > oneatom) + ipage.vgot(n); + if (ipage.status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } NEIGH_OMP_CLOSE; list->inum = inum_full; } diff --git a/src/USER-OMP/neigh_full_omp.cpp b/src/USER-OMP/neigh_full_omp.cpp index 8ba2ffaf2..e60962789 100644 --- a/src/USER-OMP/neigh_full_omp.cpp +++ b/src/USER-OMP/neigh_full_omp.cpp @@ -1,579 +1,540 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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 "neighbor_omp.h" #include "neigh_list.h" #include "atom.h" #include "comm.h" #include "domain.h" #include "group.h" +#include "my_page.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_omp(NeighList *list) { const int nlocal = (includegroup) ? atom->nfirst : atom->nlocal; const int bitmask = (includegroup) ? group->bitmask[includegroup] : 0; NEIGH_OMP_INIT; #if defined(_OPENMP) #pragma omp parallel default(none) shared(list) #endif NEIGH_OMP_SETUP(nlocal); 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 nall = atom->nlocal + atom->nghost; int molecular = atom->molecular; int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; - int npage = tid; - int npnt = 0; + // each thread has its own page allocator + MyPage &ipage = list->ipage[tid]; + ipage.reset(); // loop over owned atoms, storing neighbors for (i = ifrom; i < ito; i++) { -#if defined(_OPENMP) -#pragma omp critical -#endif - if (pgsize - npnt < oneatom) { - npnt = 0; - npage += nthreads; - if (npage >= list->maxpage) list->add_pages(nthreads); - } - - neighptr = &(list->pages[npage][npnt]); n = 0; + neighptr = ipage.vget(); 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]); if (which == 0) neighptr[n++] = j; else if (domain->minimum_image_check(delx,dely,delz)) neighptr[n++] = j; else if (which > 0) neighptr[n++] = j ^ (which << SBBITS); } else neighptr[n++] = j; } } ilist[i] = i; firstneigh[i] = neighptr; numneigh[i] = n; - npnt += n; - if (n > oneatom) + ipage.vgot(n); + if (ipage.status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } NEIGH_OMP_CLOSE; list->inum = nlocal; list->gnum = 0; } /* ---------------------------------------------------------------------- N^2 search for all neighbors include neighbors of ghost atoms, but no "special neighbors" for ghosts every neighbor pair appears in list of both atoms i and j ------------------------------------------------------------------------- */ void Neighbor::full_nsq_ghost_omp(NeighList *list) { const int nlocal = atom->nlocal; const int nall = nlocal + atom->nghost; NEIGH_OMP_INIT; #if defined(_OPENMP) #pragma omp parallel default(none) shared(list) #endif NEIGH_OMP_SETUP(nall); 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 molecular = atom->molecular; int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; - int npage = tid; - int npnt = 0; + // each thread has its own page allocator + MyPage &ipage = list->ipage[tid]; + ipage.reset(); // loop over owned & ghost atoms, storing neighbors for (i = ifrom; i < ito; i++) { -#if defined(_OPENMP) -#pragma omp critical -#endif - if (pgsize - npnt < oneatom) { - npnt = 0; - npage += nthreads; - if (npage >= list->maxpage) list->add_pages(nthreads); - } - - neighptr = &(list->pages[npage][npnt]); n = 0; + neighptr = ipage.vget(); 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 // no molecular test when i = ghost atom 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]); if (which == 0) neighptr[n++] = j; else if (domain->minimum_image_check(delx,dely,delz)) neighptr[n++] = j; else 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]) neighptr[n++] = j; } } ilist[i] = i; firstneigh[i] = neighptr; numneigh[i] = n; - npnt += n; - if (n > oneatom) + ipage.vgot(n); + if (ipage.status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } NEIGH_OMP_CLOSE; list->inum = nlocal; list->gnum = nall - nlocal; } /* ---------------------------------------------------------------------- binned neighbor list construction for all neighbors every neighbor pair appears in list of both atoms i and j ------------------------------------------------------------------------- */ void Neighbor::full_bin_omp(NeighList *list) { // bin owned & ghost atoms bin_atoms(); const int nlocal = (includegroup) ? atom->nfirst : atom->nlocal; NEIGH_OMP_INIT; #if defined(_OPENMP) #pragma omp parallel default(none) shared(list) #endif NEIGH_OMP_SETUP(nlocal); int i,j,k,n,itype,jtype,ibin,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 molecular = atom->molecular; int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; int nstencil = list->nstencil; int *stencil = list->stencil; - int npage = tid; - int npnt = 0; + // each thread has its own page allocator + MyPage &ipage = list->ipage[tid]; + ipage.reset(); // loop over owned atoms, storing neighbors for (i = ifrom; i < ito; i++) { -#if defined(_OPENMP) -#pragma omp critical -#endif - if (pgsize - npnt < oneatom) { - npnt = 0; - npage += nthreads; - if (npage >= list->maxpage) list->add_pages(nthreads); - } - - neighptr = &(list->pages[npage][npnt]); n = 0; + neighptr = ipage.vget(); 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]); if (which == 0) neighptr[n++] = j; else if (domain->minimum_image_check(delx,dely,delz)) neighptr[n++] = j; else if (which > 0) neighptr[n++] = j ^ (which << SBBITS); } else neighptr[n++] = j; } } } ilist[i] = i; firstneigh[i] = neighptr; numneigh[i] = n; - npnt += n; - if (n > oneatom) + ipage.vgot(n); + if (ipage.status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } NEIGH_OMP_CLOSE; list->inum = nlocal; list->gnum = 0; } /* ---------------------------------------------------------------------- binned neighbor list construction for all neighbors include neighbors of ghost atoms, but no "special neighbors" for ghosts every neighbor pair appears in list of both atoms i and j ------------------------------------------------------------------------- */ void Neighbor::full_bin_ghost_omp(NeighList *list) { // bin owned & ghost atoms bin_atoms(); const int nlocal = atom->nlocal; const int nall = nlocal + atom->nghost; NEIGH_OMP_INIT; #if defined(_OPENMP) #pragma omp parallel default(none) shared(list) #endif NEIGH_OMP_SETUP(nall); 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; 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 molecular = atom->molecular; int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; int nstencil = list->nstencil; int *stencil = list->stencil; int **stencilxyz = list->stencilxyz; - int npage = tid; - int npnt = 0; + // each thread has its own page allocator + MyPage &ipage = list->ipage[tid]; + ipage.reset(); // loop over owned & ghost atoms, storing neighbors for (i = ifrom; i < ito; i++) { -#if defined(_OPENMP) -#pragma omp critical -#endif - if (pgsize - npnt < oneatom) { - npnt = 0; - npage += nthreads; - if (npage >= list->maxpage) list->add_pages(nthreads); - } - - neighptr = &(list->pages[npage][npnt]); n = 0; + neighptr = ipage.vget(); 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 // no molecular test when i = ghost atom 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]); if (which == 0) neighptr[n++] = j; else if (domain->minimum_image_check(delx,dely,delz)) neighptr[n++] = j; else 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]) neighptr[n++] = j; } } } ilist[i] = i; firstneigh[i] = neighptr; numneigh[i] = n; - npnt += n; - if (n > oneatom) + ipage.vgot(n); + if (ipage.status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } NEIGH_OMP_CLOSE; list->inum = nlocal; list->gnum = nall - 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_omp(NeighList *list) { // bin local & ghost atoms bin_atoms(); const int nlocal = (includegroup) ? atom->nfirst : atom->nlocal; NEIGH_OMP_INIT; #if defined(_OPENMP) #pragma omp parallel default(none) shared(list) #endif NEIGH_OMP_SETUP(nlocal); int i,j,k,n,itype,jtype,ibin,which,ns; double xtmp,ytmp,ztmp,delx,dely,delz,rsq; int *neighptr,*s; double *cutsq,*distsq; // 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 molecular = atom->molecular; int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; int *nstencil_multi = list->nstencil_multi; int **stencil_multi = list->stencil_multi; double **distsq_multi = list->distsq_multi; - int npage = tid; - int npnt = 0; + // each thread has its own page allocator + MyPage &ipage = list->ipage[tid]; + ipage.reset(); for (i = ifrom; i < ito; i++) { -#if defined(_OPENMP) -#pragma omp critical -#endif - if (pgsize - npnt < oneatom) { - npnt = 0; - npage += nthreads; - if (npage >= list->maxpage) list->add_pages(nthreads); - } - - neighptr = &(list->pages[npage][npnt]); n = 0; + neighptr = ipage.vget(); 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]); if (which == 0) neighptr[n++] = j; else if (domain->minimum_image_check(delx,dely,delz)) neighptr[n++] = j; else if (which > 0) neighptr[n++] = j ^ (which << SBBITS); } else neighptr[n++] = j; } } } ilist[i] = i; firstneigh[i] = neighptr; numneigh[i] = n; - npnt += n; - if (n > oneatom) + ipage.vgot(n); + if (ipage.status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } NEIGH_OMP_CLOSE; list->inum = nlocal; list->gnum = 0; } diff --git a/src/USER-OMP/neigh_gran_omp.cpp b/src/USER-OMP/neigh_gran_omp.cpp index e8634dcf3..5f0402f36 100644 --- a/src/USER-OMP/neigh_gran_omp.cpp +++ b/src/USER-OMP/neigh_gran_omp.cpp @@ -1,657 +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 "neighbor.h" #include "neighbor_omp.h" #include "neigh_list.h" #include "atom.h" #include "comm.h" #include "group.h" #include "fix_shear_history.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- granular particles N^2 / 2 search for neighbor pairs with partial Newton's 3rd law shear history must be accounted for when a neighbor pair is added 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::granular_nsq_no_newton_omp(NeighList *list) { const int nlocal = (includegroup) ? atom->nfirst : atom->nlocal; const int bitmask = (includegroup) ? group->bitmask[includegroup] : 0; FixShearHistory * const fix_history = list->fix_history; NeighList * listgranhistory = list->listgranhistory; NEIGH_OMP_INIT; - if (fix_history) - if (nthreads > listgranhistory->maxpage) - listgranhistory->add_pages(nthreads - listgranhistory->maxpage); - #if defined(_OPENMP) #pragma omp parallel default(none) shared(list,listgranhistory) #endif NEIGH_OMP_SETUP(nlocal); int i,j,m,n,nn; double xtmp,ytmp,ztmp,delx,dely,delz,rsq; double radi,radsum,cutsq; int *neighptr,*touchptr; double *shearptr; int *npartner,**partner; double (**shearpartner)[3]; int **firsttouch; double **firstshear; + MyPage *ipage_touch; + MyPage *dpage_shear; double **x = atom->x; double *radius = atom->radius; int *tag = atom->tag; int *type = atom->type; int *mask = atom->mask; int *molecule = atom->molecule; int nall = atom->nlocal + atom->nghost; int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; + // each thread has its own page allocator + MyPage &ipage = list->ipage[tid]; + ipage.reset(); + if (fix_history) { npartner = fix_history->npartner; partner = fix_history->partner; shearpartner = fix_history->shearpartner; firsttouch = listgranhistory->firstneigh; firstshear = listgranhistory->firstdouble; + ipage_touch = listgranhistory->ipage+tid; + dpage_shear = listgranhistory->dpage+tid; + ipage_touch->reset(); + dpage_shear->reset(); } - int npage = tid; - int npnt = 0; - for (i = ifrom; i < ito; i++) { -#if defined(_OPENMP) -#pragma omp critical -#endif - { - if (pgsize - npnt < oneatom) { - npnt = 0; - npage += nthreads; - if (npage >= list->maxpage) { - list->add_pages(nthreads); - if (fix_history) - listgranhistory->add_pages(nthreads); - } - } - - n = nn = 0; - neighptr = &(list->pages[npage][npnt]); - if (fix_history) { - touchptr = &(listgranhistory->pages[npage][npnt]); - shearptr = &(listgranhistory->dpages[npage][3*npnt]); - } + n = 0; + neighptr = ipage.vget(); + if (fix_history) { + nn = 0; + touchptr = ipage_touch->vget(); + shearptr = dpage_shear->vget(); } - + xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; radi = radius[i]; // loop over remaining atoms, owned and ghost for (j = i+1; j < nall; j++) { if (includegroup && !(mask[j] & bitmask)) continue; if (exclude && exclusion(i,j,type[i],type[j],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; radsum = radi + radius[j]; cutsq = (radsum+skin) * (radsum+skin); if (rsq <= cutsq) { neighptr[n] = j; if (fix_history) { if (rsq < radsum*radsum) { for (m = 0; m < npartner[i]; m++) if (partner[i][m] == tag[j]) break; if (m < npartner[i]) { touchptr[n] = 1; shearptr[nn++] = shearpartner[i][m][0]; shearptr[nn++] = shearpartner[i][m][1]; shearptr[nn++] = shearpartner[i][m][2]; } else { touchptr[n] = 0; shearptr[nn++] = 0.0; shearptr[nn++] = 0.0; shearptr[nn++] = 0.0; } } else { touchptr[n] = 0; shearptr[nn++] = 0.0; shearptr[nn++] = 0.0; shearptr[nn++] = 0.0; } } n++; } } ilist[i] = i; firstneigh[i] = neighptr; numneigh[i] = n; + ipage.vgot(n); + if (ipage.status()) + error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); + if (fix_history) { firsttouch[i] = touchptr; firstshear[i] = shearptr; + ipage_touch->vgot(n); + dpage_shear->vgot(nn); } - npnt += n; - if (n > oneatom) - error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } NEIGH_OMP_CLOSE; list->inum = nlocal; } /* ---------------------------------------------------------------------- granular particles N^2 / 2 search for neighbor pairs with full Newton's 3rd law no shear history is allowed for this option 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::granular_nsq_newton_omp(NeighList *list) { const int nlocal = (includegroup) ? atom->nfirst : atom->nlocal; const int bitmask = (includegroup) ? group->bitmask[includegroup] : 0; NEIGH_OMP_INIT; #if defined(_OPENMP) #pragma omp parallel default(none) shared(list) #endif NEIGH_OMP_SETUP(nlocal); int i,j,n,itag,jtag; double xtmp,ytmp,ztmp,delx,dely,delz,rsq; double radi,radsum,cutsq; int *neighptr; double **x = atom->x; double *radius = atom->radius; int *tag = atom->tag; int *type = atom->type; int *mask = atom->mask; int *molecule = atom->molecule; int nall = atom->nlocal + atom->nghost; int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; - int npage = tid; - int npnt = 0; + // each thread has its own page allocator + MyPage &ipage = list->ipage[tid]; + ipage.reset(); for (i = ifrom; i < ito; i++) { -#if defined(_OPENMP) -#pragma omp critical -#endif - if (pgsize - npnt < oneatom) { - npnt = 0; - npage += nthreads; - if (npage >= list->maxpage) list->add_pages(nthreads); - } - - neighptr = &(list->pages[npage][npnt]); n = 0; + neighptr = ipage.vget(); itag = tag[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; radi = radius[i]; // 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; } } } if (exclude && exclusion(i,j,type[i],type[j],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; radsum = radi + radius[j]; cutsq = (radsum+skin) * (radsum+skin); if (rsq <= cutsq) neighptr[n++] = j; } ilist[i] = i; firstneigh[i] = neighptr; numneigh[i] = n; - npnt += n; - if (n > oneatom) + ipage.vgot(n); + if (ipage.status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } NEIGH_OMP_CLOSE; list->inum = nlocal; } /* ---------------------------------------------------------------------- granular particles binned neighbor list construction with partial Newton's 3rd law shear history must be accounted for when a neighbor pair is added 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::granular_bin_no_newton_omp(NeighList *list) { // bin local & ghost atoms bin_atoms(); const int nlocal = (includegroup) ? atom->nfirst : atom->nlocal; FixShearHistory * const fix_history = list->fix_history; NeighList * listgranhistory = list->listgranhistory; NEIGH_OMP_INIT; - if (fix_history) - if (nthreads > listgranhistory->maxpage) - listgranhistory->add_pages(nthreads - listgranhistory->maxpage); - #if defined(_OPENMP) #pragma omp parallel default(none) shared(list,listgranhistory) #endif NEIGH_OMP_SETUP(nlocal); int i,j,k,m,n,nn,ibin; double xtmp,ytmp,ztmp,delx,dely,delz,rsq; double radi,radsum,cutsq; int *neighptr,*touchptr; double *shearptr; + MyPage *ipage_touch; + MyPage *dpage_shear; int *npartner,**partner; double (**shearpartner)[3]; int **firsttouch; double **firstshear; // loop over each atom, storing neighbors double **x = atom->x; double *radius = atom->radius; int *tag = atom->tag; int *type = atom->type; int *mask = atom->mask; int *molecule = atom->molecule; int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; int nstencil = list->nstencil; int *stencil = list->stencil; + // each thread has its own page allocator + MyPage &ipage = list->ipage[tid]; + ipage.reset(); + if (fix_history) { npartner = fix_history->npartner; partner = fix_history->partner; shearpartner = fix_history->shearpartner; firsttouch = listgranhistory->firstneigh; firstshear = listgranhistory->firstdouble; + ipage_touch = listgranhistory->ipage+tid; + dpage_shear = listgranhistory->dpage+tid; + ipage_touch->reset(); + dpage_shear->reset(); } - int npage = tid; - int npnt = 0; - for (i = ifrom; i < ito; i++) { -#if defined(_OPENMP) -#pragma omp critical -#endif - { - if (pgsize - npnt < oneatom) { - npnt = 0; - npage += nthreads; - if (npage >= list->maxpage) { - list->add_pages(nthreads); - if (fix_history) - listgranhistory->add_pages(nthreads); - } - } - - n = nn = 0; - neighptr = &(list->pages[npage][npnt]); - if (fix_history) { - touchptr = &(listgranhistory->pages[npage][npnt]); - shearptr = &(listgranhistory->dpages[npage][3*npnt]); - } + n = 0; + neighptr = ipage.vget(); + if (fix_history) { + nn = 0; + touchptr = ipage_touch->vget(); + shearptr = dpage_shear->vget(); } xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; radi = radius[i]; 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; if (exclude && exclusion(i,j,type[i],type[j],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; radsum = radi + radius[j]; cutsq = (radsum+skin) * (radsum+skin); if (rsq <= cutsq) { neighptr[n] = j; if (fix_history) { if (rsq < radsum*radsum) { for (m = 0; m < npartner[i]; m++) if (partner[i][m] == tag[j]) break; if (m < npartner[i]) { touchptr[n] = 1; shearptr[nn++] = shearpartner[i][m][0]; shearptr[nn++] = shearpartner[i][m][1]; shearptr[nn++] = shearpartner[i][m][2]; } else { touchptr[n] = 0; shearptr[nn++] = 0.0; shearptr[nn++] = 0.0; shearptr[nn++] = 0.0; } } else { touchptr[n] = 0; shearptr[nn++] = 0.0; shearptr[nn++] = 0.0; shearptr[nn++] = 0.0; } } n++; } } } ilist[i] = i; firstneigh[i] = neighptr; numneigh[i] = n; + ipage.vgot(n); + if (ipage.status()) + error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); + if (fix_history) { firsttouch[i] = touchptr; firstshear[i] = shearptr; + ipage_touch->vgot(n); + dpage_shear->vgot(nn); } - npnt += n; - if (n > oneatom) - error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } NEIGH_OMP_CLOSE; list->inum = nlocal; } /* ---------------------------------------------------------------------- granular particles binned neighbor list construction with full Newton's 3rd law no shear history is allowed for this option each owned atom i checks its own bin and other bins in Newton stencil every pair stored exactly once by some processor ------------------------------------------------------------------------- */ void Neighbor::granular_bin_newton_omp(NeighList *list) { // bin local & ghost atoms bin_atoms(); const int nlocal = (includegroup) ? atom->nfirst : atom->nlocal; NEIGH_OMP_INIT; #if defined(_OPENMP) #pragma omp parallel default(none) shared(list) #endif NEIGH_OMP_SETUP(nlocal); int i,j,k,n,ibin; double xtmp,ytmp,ztmp,delx,dely,delz,rsq; double radi,radsum,cutsq; int *neighptr; // loop over each atom, storing neighbors double **x = atom->x; double *radius = atom->radius; int *type = atom->type; int *mask = atom->mask; int *molecule = atom->molecule; int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; int nstencil = list->nstencil; int *stencil = list->stencil; - int npage = tid; - int npnt = 0; + // each thread has its own page allocator + MyPage &ipage = list->ipage[tid]; + ipage.reset(); for (i = ifrom; i < ito; i++) { -#if defined(_OPENMP) -#pragma omp critical -#endif - if (pgsize - npnt < oneatom) { - npnt = 0; - npage += nthreads; - if (npage >= list->maxpage) list->add_pages(nthreads); - } - n = 0; - neighptr = &(list->pages[npage][npnt]); + neighptr = ipage.vget(); xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; radi = radius[i]; // 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; } } if (exclude && exclusion(i,j,type[i],type[j],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; radsum = radi + radius[j]; cutsq = (radsum+skin) * (radsum+skin); if (rsq <= cutsq) 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]) { if (exclude && exclusion(i,j,type[i],type[j],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; radsum = radi + radius[j]; cutsq = (radsum+skin) * (radsum+skin); if (rsq <= cutsq) neighptr[n++] = j; } } ilist[i] = i; firstneigh[i] = neighptr; numneigh[i] = n; - npnt += n; - if (n > oneatom) + ipage.vgot(n); + if (ipage.status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } NEIGH_OMP_CLOSE; list->inum = nlocal; } /* ---------------------------------------------------------------------- granular particles binned neighbor list construction with Newton's 3rd law for triclinic no shear history is allowed for this option each owned atom i checks its own bin and other bins in triclinic stencil every pair stored exactly once by some processor ------------------------------------------------------------------------- */ void Neighbor::granular_bin_newton_tri_omp(NeighList *list) { // bin local & ghost atoms bin_atoms(); const int nlocal = (includegroup) ? atom->nfirst : atom->nlocal; NEIGH_OMP_INIT; #if defined(_OPENMP) #pragma omp parallel default(none) shared(list) #endif NEIGH_OMP_SETUP(nlocal); int i,j,k,n,ibin; double xtmp,ytmp,ztmp,delx,dely,delz,rsq; double radi,radsum,cutsq; int *neighptr; // loop over each atom, storing neighbors double **x = atom->x; double *radius = atom->radius; int *type = atom->type; int *mask = atom->mask; int *molecule = atom->molecule; int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; int nstencil = list->nstencil; int *stencil = list->stencil; - int npage = tid; - int npnt = 0; + // each thread has its own page allocator + MyPage &ipage = list->ipage[tid]; + ipage.reset(); for (i = ifrom; i < ito; i++) { -#if defined(_OPENMP) -#pragma omp critical -#endif - if (pgsize - npnt < oneatom) { - npnt = 0; - npage += nthreads; - if (npage >= list->maxpage) list->add_pages(nthreads); - } - n = 0; - neighptr = &(list->pages[npage][npnt]); + neighptr = ipage.vget(); xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; radi = radius[i]; // 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; } } if (exclude && exclusion(i,j,type[i],type[j],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; radsum = radi + radius[j]; cutsq = (radsum+skin) * (radsum+skin); if (rsq <= cutsq) neighptr[n++] = j; } } ilist[i] = i; firstneigh[i] = neighptr; numneigh[i] = n; - npnt += n; - if (n > oneatom) + ipage.vgot(n); + if (ipage.status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } NEIGH_OMP_CLOSE; list->inum = nlocal; } diff --git a/src/USER-OMP/neigh_half_bin_omp.cpp b/src/USER-OMP/neigh_half_bin_omp.cpp index ba0a18041..f501684a1 100644 --- a/src/USER-OMP/neigh_half_bin_omp.cpp +++ b/src/USER-OMP/neigh_half_bin_omp.cpp @@ -1,522 +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 "neighbor.h" #include "neighbor_omp.h" #include "neigh_list.h" #include "atom.h" #include "comm.h" #include "domain.h" +#include "my_page.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_omp(NeighList *list) { // bin local & ghost atoms bin_atoms(); const int nlocal = (includegroup) ? atom->nfirst : atom->nlocal; NEIGH_OMP_INIT; #if defined(_OPENMP) #pragma omp parallel default(none) shared(list) #endif NEIGH_OMP_SETUP(nlocal); int i,j,k,n,itype,jtype,ibin,which; 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 molecular = atom->molecular; int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; int nstencil = list->nstencil; int *stencil = list->stencil; - // each thread works on its own page - int npage = tid; - int npnt = 0; + // each thread has its own page allocator + MyPage &ipage = list->ipage[tid]; + ipage.reset(); for (i = ifrom; i < ito; i++) { -#if defined(_OPENMP) -#pragma omp critical -#endif - if (pgsize - npnt < oneatom) { - npnt = 0; - npage += nthreads; - if (npage >= list->maxpage) list->add_pages(nthreads); - } - - neighptr = &(list->pages[npage][npnt]); n = 0; + neighptr = ipage.vget(); 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]); if (which == 0) neighptr[n++] = j; else if (domain->minimum_image_check(delx,dely,delz)) neighptr[n++] = j; else if (which > 0) neighptr[n++] = j ^ (which << SBBITS); } else neighptr[n++] = j; } } } ilist[i] = i; firstneigh[i] = neighptr; numneigh[i] = n; - npnt += n; - if (n > oneatom) + ipage.vgot(n); + if (ipage.status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } NEIGH_OMP_CLOSE; list->inum = nlocal; } /* ---------------------------------------------------------------------- binned neighbor list construction with partial Newton's 3rd law include neighbors of ghost atoms, but no "special neighbors" for ghosts owned and ghost atoms check own bin and other bins in stencil pair stored once if i,j are both owned and i < j pair stored by me if i owned and j ghost (also stored by proc owning j) pair stored once if i,j are both ghost and i < j ------------------------------------------------------------------------- */ void Neighbor::half_bin_no_newton_ghost_omp(NeighList *list) { const int nlocal = atom->nlocal; const int nall = nlocal + atom->nghost; NEIGH_OMP_INIT; #if defined(_OPENMP) #pragma omp parallel default(none) shared(list) #endif NEIGH_OMP_SETUP(nall); int i,j,k,n,itype,jtype,ibin,which; int xbin,ybin,zbin,xbin2,ybin2,zbin2; 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 molecular = atom->molecular; int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; int nstencil = list->nstencil; int *stencil = list->stencil; int **stencilxyz = list->stencilxyz; - // each thread works on its own page - int npage = tid; - int npnt = 0; + // each thread has its own page allocator + MyPage &ipage = list->ipage[tid]; + ipage.reset(); for (i = ifrom; i < ito; i++) { -#if defined(_OPENMP) -#pragma omp critical -#endif - if (pgsize - npnt < oneatom) { - npnt = 0; - npage += nthreads; - if (npage >= list->maxpage) list->add_pages(nthreads); - } - - neighptr = &(list->pages[npage][npnt]); n = 0; + neighptr = ipage.vget(); 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 // when i is a ghost atom, must check if stencil bin is out of bounds // only store pair if i < j // stores own/own pairs only once // stores own/ghost pairs with owned atom only, on both procs // stores ghost/ghost pairs only once // no molecular test when i = ghost atom 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 (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]); if (which == 0) neighptr[n++] = j; else if (domain->minimum_image_check(delx,dely,delz)) neighptr[n++] = j; else 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 (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 <= cutneighghostsq[itype][jtype]) neighptr[n++] = j; } } } ilist[i] = i; firstneigh[i] = neighptr; numneigh[i] = n; - npnt += n; - if (n > oneatom) + ipage.vgot(n); + if (ipage.status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } NEIGH_OMP_CLOSE; list->inum = nlocal; list->gnum = nall - atom->nlocal; } /* ---------------------------------------------------------------------- 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_omp(NeighList *list) { // bin local & ghost atoms bin_atoms(); const int nlocal = (includegroup) ? atom->nfirst : atom->nlocal; NEIGH_OMP_INIT; #if defined(_OPENMP) #pragma omp parallel default(none) shared(list) #endif NEIGH_OMP_SETUP(nlocal); int i,j,k,n,itype,jtype,ibin,which; 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 molecular = atom->molecular; int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; int nstencil = list->nstencil; int *stencil = list->stencil; - // each thread works on its own page - int npage = tid; - int npnt = 0; + // each thread has its own page allocator + MyPage &ipage = list->ipage[tid]; + ipage.reset(); for (i = ifrom; i < ito; i++) { -#if defined(_OPENMP) -#pragma omp critical -#endif - if (pgsize - npnt < oneatom) { - npnt = 0; - npage += nthreads; - if (npage >= list->maxpage) list->add_pages(nthreads); - } - - neighptr = &(list->pages[npage][npnt]); n = 0; + neighptr = ipage.vget(); 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]); if (which == 0) neighptr[n++] = j; else if (domain->minimum_image_check(delx,dely,delz)) neighptr[n++] = j; else if (which > 0) neighptr[n++] = j ^ (which << SBBITS); // OLD: 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]); if (which == 0) neighptr[n++] = j; else if (domain->minimum_image_check(delx,dely,delz)) neighptr[n++] = j; else if (which > 0) neighptr[n++] = j ^ (which << SBBITS); // OLD: if (which >= 0) neighptr[n++] = j ^ (which << SBBITS); } else neighptr[n++] = j; } } } ilist[i] = i; firstneigh[i] = neighptr; numneigh[i] = n; - npnt += n; - if (n > oneatom) + ipage.vgot(n); + if (ipage.status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } NEIGH_OMP_CLOSE; list->inum = nlocal; } /* ---------------------------------------------------------------------- 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_omp(NeighList *list) { // bin local & ghost atoms bin_atoms(); const int nlocal = (includegroup) ? atom->nfirst : atom->nlocal; NEIGH_OMP_INIT; #if defined(_OPENMP) #pragma omp parallel default(none) shared(list) #endif NEIGH_OMP_SETUP(nlocal); int i,j,k,n,itype,jtype,ibin,which; 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 molecular = atom->molecular; int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; int nstencil = list->nstencil; int *stencil = list->stencil; - // each thread works on its own page - int npage = tid; - int npnt = 0; + // each thread has its own page allocator + MyPage &ipage = list->ipage[tid]; + ipage.reset(); for (i = ifrom; i < ito; i++) { -#if defined(_OPENMP) -#pragma omp critical -#endif - if (pgsize - npnt < oneatom) { - npnt = 0; - npage += nthreads; - if (npage >= list->maxpage) list->add_pages(nthreads); - } - - neighptr = &(list->pages[npage][npnt]); n = 0; + neighptr = ipage.vget(); 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]); if (which == 0) neighptr[n++] = j; else if (domain->minimum_image_check(delx,dely,delz)) neighptr[n++] = j; else if (which > 0) neighptr[n++] = j ^ (which << SBBITS); } else neighptr[n++] = j; } } } ilist[i] = i; firstneigh[i] = neighptr; numneigh[i] = n; - npnt += n; - if (n > oneatom) + ipage.vgot(n); + if (ipage.status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } NEIGH_OMP_CLOSE; list->inum = nlocal; } diff --git a/src/USER-OMP/neigh_half_multi_omp.cpp b/src/USER-OMP/neigh_half_multi_omp.cpp index 5cc6ba140..b46594870 100644 --- a/src/USER-OMP/neigh_half_multi_omp.cpp +++ b/src/USER-OMP/neigh_half_multi_omp.cpp @@ -1,405 +1,379 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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 "neighbor_omp.h" #include "neigh_list.h" #include "atom.h" #include "comm.h" #include "domain.h" +#include "my_page.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_omp(NeighList *list) { // bin local & ghost atoms bin_atoms(); const int nlocal = (includegroup) ? atom->nfirst : atom->nlocal; NEIGH_OMP_INIT; #if defined(_OPENMP) #pragma omp parallel default(none) shared(list) #endif NEIGH_OMP_SETUP(nlocal); int i,j,k,n,itype,jtype,ibin,which,ns; double xtmp,ytmp,ztmp,delx,dely,delz,rsq; int *neighptr,*s; double *cutsq,*distsq; // 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 molecular = atom->molecular; int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; int *nstencil_multi = list->nstencil_multi; int **stencil_multi = list->stencil_multi; double **distsq_multi = list->distsq_multi; - // each thread works on its own page - int npage = tid; - int npnt = 0; + // each thread has its own page allocator + MyPage &ipage = list->ipage[tid]; + ipage.reset(); for (i = ifrom; i < ito; i++) { -#if defined(_OPENMP) -#pragma omp critical -#endif - if (pgsize - npnt < oneatom) { - npnt = 0; - npage += nthreads; - if (npage >= list->maxpage) list->add_pages(nthreads); - } - - neighptr = &(list->pages[npage][npnt]); n = 0; + neighptr = ipage.vget(); 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]); if (which == 0) neighptr[n++] = j; else if (domain->minimum_image_check(delx,dely,delz)) neighptr[n++] = j; else if (which > 0) neighptr[n++] = j ^ (which << SBBITS); } else neighptr[n++] = j; } } } ilist[i] = i; firstneigh[i] = neighptr; numneigh[i] = n; - npnt += n; - if (n > oneatom) + ipage.vgot(n); + if (ipage.status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } NEIGH_OMP_CLOSE; list->inum = nlocal; } /* ---------------------------------------------------------------------- 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_omp(NeighList *list) { // bin local & ghost atoms bin_atoms(); const int nlocal = (includegroup) ? atom->nfirst : atom->nlocal; NEIGH_OMP_INIT; #if defined(_OPENMP) #pragma omp parallel default(none) shared(list) #endif NEIGH_OMP_SETUP(nlocal); int i,j,k,n,itype,jtype,ibin,which,ns; double xtmp,ytmp,ztmp,delx,dely,delz,rsq; int *neighptr,*s; double *cutsq,*distsq; // 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 molecular = atom->molecular; int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; int *nstencil_multi = list->nstencil_multi; int **stencil_multi = list->stencil_multi; double **distsq_multi = list->distsq_multi; - // each thread works on its own page - int npage = tid; - int npnt = 0; + // each thread has its own page allocator + MyPage &ipage = list->ipage[tid]; + ipage.reset(); for (i = ifrom; i < ito; i++) { -#if defined(_OPENMP) -#pragma omp critical -#endif - if (pgsize - npnt < oneatom) { - npnt = 0; - npage += nthreads; - if (npage >= list->maxpage) list->add_pages(nthreads); - } - - neighptr = &(list->pages[npage][npnt]); n = 0; + neighptr = ipage.vget(); 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]); if (which == 0) neighptr[n++] = j; else if (domain->minimum_image_check(delx,dely,delz)) neighptr[n++] = j; else 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]); if (which == 0) neighptr[n++] = j; else if (domain->minimum_image_check(delx,dely,delz)) neighptr[n++] = j; else if (which > 0) neighptr[n++] = j ^ (which << SBBITS); } else neighptr[n++] = j; } } } ilist[i] = i; firstneigh[i] = neighptr; numneigh[i] = n; - npnt += n; - if (n > oneatom) + ipage.vgot(n); + if (ipage.status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } NEIGH_OMP_CLOSE; list->inum = nlocal; } /* ---------------------------------------------------------------------- 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_omp(NeighList *list) { // bin local & ghost atoms bin_atoms(); const int nlocal = (includegroup) ? atom->nfirst : atom->nlocal; NEIGH_OMP_INIT; #if defined(_OPENMP) #pragma omp parallel default(none) shared(list) #endif NEIGH_OMP_SETUP(nlocal); int i,j,k,n,itype,jtype,ibin,which,ns; double xtmp,ytmp,ztmp,delx,dely,delz,rsq; int *neighptr,*s; double *cutsq,*distsq; // 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 molecular = atom->molecular; int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; int *nstencil_multi = list->nstencil_multi; int **stencil_multi = list->stencil_multi; double **distsq_multi = list->distsq_multi; - // each thread works on its own page - int npage = tid; - int npnt = 0; + // each thread has its own page allocator + MyPage &ipage = list->ipage[tid]; + ipage.reset(); for (i = ifrom; i < ito; i++) { -#if defined(_OPENMP) -#pragma omp critical -#endif - if (pgsize - npnt < oneatom) { - npnt = 0; - npage += nthreads; - if (npage >= list->maxpage) list->add_pages(nthreads); - } - - neighptr = &(list->pages[npage][npnt]); n = 0; + neighptr = ipage.vget(); 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]); if (which == 0) neighptr[n++] = j; else if (domain->minimum_image_check(delx,dely,delz)) neighptr[n++] = j; else if (which > 0) neighptr[n++] = j ^ (which << SBBITS); } else neighptr[n++] = j; } } } ilist[i] = i; firstneigh[i] = neighptr; numneigh[i] = n; - npnt += n; - if (n > oneatom) + ipage.vgot(n); + if (ipage.status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } NEIGH_OMP_CLOSE; list->inum = nlocal; } diff --git a/src/USER-OMP/neigh_half_nsq_omp.cpp b/src/USER-OMP/neigh_half_nsq_omp.cpp index 6a8bee491..a98c4721f 100644 --- a/src/USER-OMP/neigh_half_nsq_omp.cpp +++ b/src/USER-OMP/neigh_half_nsq_omp.cpp @@ -1,350 +1,325 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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 "neighbor_omp.h" #include "neigh_list.h" #include "atom.h" #include "comm.h" #include "domain.h" #include "group.h" +#include "my_page.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_omp(NeighList *list) { const int nlocal = (includegroup) ? atom->nfirst : atom->nlocal; const int bitmask = (includegroup) ? group->bitmask[includegroup] : 0; const int nall = atom->nlocal + atom->nghost; NEIGH_OMP_INIT; #if defined(_OPENMP) #pragma omp parallel default(none) shared(list) #endif NEIGH_OMP_SETUP(nlocal); 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 molecular = atom->molecular; int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; - // each thread works on its own page - int npage = tid; - int npnt = 0; + // each thread has its own page allocator + MyPage &ipage = list->ipage[tid]; + ipage.reset(); // loop over owned atoms, storing neighbors for (i = ifrom; i < ito; i++) { -#if defined(_OPENMP) -#pragma omp critical -#endif - if (pgsize - npnt < oneatom) { - npnt = 0; - npage += nthreads; - if (npage >= list->maxpage) list->add_pages(nthreads); - } - - neighptr = &(list->pages[npage][npnt]); n = 0; + neighptr = ipage.vget(); itype = type[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; // loop over remaining atoms, owned and ghost // only store pair if i < j 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]); if (which == 0) neighptr[n++] = j; else if (domain->minimum_image_check(delx,dely,delz)) neighptr[n++] = j; else if (which > 0) neighptr[n++] = j ^ (which << SBBITS); } else neighptr[n++] = j; } } ilist[i] = i; firstneigh[i] = neighptr; numneigh[i] = n; - npnt += n; - if (n > oneatom) + ipage.vgot(n); + if (ipage.status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } NEIGH_OMP_CLOSE; list->inum = nlocal; } /* ---------------------------------------------------------------------- N^2 / 2 search for neighbor pairs with partial Newton's 3rd law include neighbors of ghost atoms, but no "special neighbors" for ghosts pair stored once if i,j are both owned and i < j pair stored by me if i owned and j ghost (also stored by proc owning j) pair stored once if i,j are both ghost and i < j ------------------------------------------------------------------------- */ void Neighbor::half_nsq_no_newton_ghost_omp(NeighList *list) { const int nlocal = (includegroup) ? atom->nfirst : atom->nlocal; const int bitmask = (includegroup) ? group->bitmask[includegroup] : 0; const int nall = nlocal + atom->nghost; NEIGH_OMP_INIT; #if defined(_OPENMP) #pragma omp parallel default(none) shared(list) #endif NEIGH_OMP_SETUP(nall); 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 molecular = atom->molecular; int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; - // each thread works on its own page - int npage = tid; - int npnt = 0; + // each thread has its own page allocator + MyPage &ipage = list->ipage[tid]; + ipage.reset(); // loop over owned & ghost atoms, storing neighbors for (i = ifrom; i < ito; i++) { -#if defined(_OPENMP) -#pragma omp critical -#endif - if (pgsize - npnt < oneatom) { - npnt = 0; - npage += nthreads; - if (npage >= list->maxpage) list->add_pages(nthreads); - } - - neighptr = &(list->pages[npage][npnt]); n = 0; + neighptr = ipage.vget(); itype = type[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; // loop over remaining atoms, owned and ghost // only store pair if i < j // stores own/own pairs only once // stores own/ghost pairs with owned atom only, on both procs // stores ghost/ghost pairs only once // no molecular test when i = ghost atom if (i < nlocal) { 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]); if (which == 0) neighptr[n++] = j; else if (domain->minimum_image_check(delx,dely,delz)) neighptr[n++] = j; else if (which > 0) neighptr[n++] = j ^ (which << SBBITS); } else neighptr[n++] = j; } } } else { 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]) neighptr[n++] = j; } } ilist[i] = i; firstneigh[i] = neighptr; numneigh[i] = n; - npnt += n; - if (n > oneatom) + ipage.vgot(n); + if (ipage.status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } NEIGH_OMP_CLOSE; list->inum = atom->nlocal; list->gnum = nall - atom->nlocal; } /* ---------------------------------------------------------------------- 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_omp(NeighList *list) { const int nlocal = (includegroup) ? atom->nfirst : atom->nlocal; const int bitmask = (includegroup) ? group->bitmask[includegroup] : 0; NEIGH_OMP_INIT; #if defined(_OPENMP) #pragma omp parallel default(none) shared(list) #endif NEIGH_OMP_SETUP(nlocal); int i,j,n,itype,jtype,itag,jtag,which; 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 nall = atom->nlocal + atom->nghost; int molecular = atom->molecular; int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; - int npage = tid; - int npnt = 0; + // each thread has its own page allocator + MyPage &ipage = list->ipage[tid]; + ipage.reset(); for (i = ifrom; i < ito; i++) { -#if defined(_OPENMP) -#pragma omp critical -#endif - if (pgsize - npnt < oneatom) { - npnt = 0; - npage += nthreads; - if (npage >= list->maxpage) list->add_pages(nthreads); - } - - neighptr = &(list->pages[npage][npnt]); n = 0; + neighptr = ipage.vget(); 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]); if (which == 0) neighptr[n++] = j; else if (domain->minimum_image_check(delx,dely,delz)) neighptr[n++] = j; else if (which > 0) neighptr[n++] = j ^ (which << SBBITS); } else neighptr[n++] = j; } } ilist[i] = i; firstneigh[i] = neighptr; numneigh[i] = n; - npnt += n; - if (n > oneatom) + ipage.vgot(n); + if (ipage.status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } NEIGH_OMP_CLOSE; list->inum = nlocal; } diff --git a/src/USER-OMP/neigh_respa_omp.cpp b/src/USER-OMP/neigh_respa_omp.cpp index 28afc81f1..11c7fd9ae 100644 --- a/src/USER-OMP/neigh_respa_omp.cpp +++ b/src/USER-OMP/neigh_respa_omp.cpp @@ -1,1011 +1,882 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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 "neighbor_omp.h" #include "neigh_list.h" #include "atom.h" #include "comm.h" #include "domain.h" #include "group.h" +#include "my_page.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_omp(NeighList *list) { const int nlocal = (includegroup) ? atom->nfirst : atom->nlocal; const int bitmask = (includegroup) ? group->bitmask[includegroup] : 0; NEIGH_OMP_INIT; NeighList *listinner = list->listinner; - if (nthreads > listinner->maxpage) - listinner->add_pages(nthreads - listinner->maxpage); - - NeighList *listmiddle; + NeighList *listmiddle = list->listmiddle; const int respamiddle = list->respamiddle; - if (respamiddle) { - listmiddle = list->listmiddle; - if (nthreads > listmiddle->maxpage) - listmiddle->add_pages(nthreads - listmiddle->maxpage); - } #if defined(_OPENMP) #pragma omp parallel default(none) shared(list,listinner,listmiddle) #endif NEIGH_OMP_SETUP(nlocal); int i,j,n,itype,jtype,n_inner,n_middle; 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 nall = atom->nlocal + atom->nghost; int molecular = atom->molecular; int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; int *ilist_inner = listinner->ilist; int *numneigh_inner = listinner->numneigh; int **firstneigh_inner = listinner->firstneigh; int *ilist_middle,*numneigh_middle,**firstneigh_middle; if (respamiddle) { ilist_middle = listmiddle->ilist; numneigh_middle = listmiddle->numneigh; firstneigh_middle = listmiddle->firstneigh; } - int npage = tid; - int npnt = 0; - int npage_inner = tid; - int npnt_inner = 0; - int npage_middle = tid; - int npnt_middle = 0; + // each thread has its own page allocator + MyPage &ipage = list->ipage[tid]; + MyPage &ipage_inner = listinner->ipage[tid]; + ipage.reset(); + ipage_inner.reset(); + + MyPage *ipage_middle; + if (respamiddle) { + ipage_middle = listmiddle->ipage + tid; + ipage_middle->reset(); + } int which = 0; int minchange = 0; for (i = ifrom; i < ito; i++) { -#if defined(_OPENMP) -#pragma omp critical -#endif - { - if (pgsize - npnt < oneatom) { - npnt = 0; - npage += nthreads; - if (npage >= list->maxpage) list->add_pages(nthreads); - } - neighptr = &(list->pages[npage][npnt]); - n = 0; - - if (pgsize - npnt_inner < oneatom) { - npnt_inner = 0; - npage_inner += nthreads; - if (npage_inner >= listinner->maxpage) listinner->add_pages(nthreads); - } - neighptr_inner = &(listinner->pages[npage_inner][npnt_inner]); - n_inner = 0; - + n = n_inner = 0; + neighptr = ipage.vget(); + neighptr_inner = ipage_inner.vget(); if (respamiddle) { - if (pgsize - npnt_middle < oneatom) { - npnt_middle = 0; - npage_middle += nthreads; - if (npage_middle >= listmiddle->maxpage) listmiddle->add_pages(nthreads); - } - neighptr_middle = &(listmiddle->pages[npage_middle][npnt_middle]); n_middle = 0; + neighptr_middle = ipage_middle->vget(); } - } 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]); if (which == 0) neighptr[n++] = j; else if (minchange = domain->minimum_image_check(delx,dely,delz)) neighptr[n++] = j; else 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 (minchange) neighptr_inner[n_inner++] = 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 (minchange) neighptr_middle[n_middle++] = j; else if (which > 0) neighptr_middle[n_middle++] = j ^ (which << SBBITS); } } } ilist[i] = i; firstneigh[i] = neighptr; numneigh[i] = n; - npnt += n; - if (n > oneatom) + ipage.vgot(n); + if (ipage.status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); ilist_inner[i] = i; firstneigh_inner[i] = neighptr_inner; numneigh_inner[i] = n_inner; - npnt_inner += n_inner; - if (n_inner > oneatom) + ipage.vgot(n_inner); + if (ipage_inner.status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); if (respamiddle) { ilist_middle[i] = i; firstneigh_middle[i] = neighptr_middle; numneigh_middle[i] = n_middle; - npnt_middle += n_middle; - if (n_middle > oneatom) + ipage_middle->vgot(n_middle); + if (ipage_middle->status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } } NEIGH_OMP_CLOSE; list->inum = nlocal; listinner->inum = nlocal; if (respamiddle) listmiddle->inum = nlocal; } /* ---------------------------------------------------------------------- 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_omp(NeighList *list) { const int nlocal = (includegroup) ? atom->nfirst : atom->nlocal; const int bitmask = (includegroup) ? group->bitmask[includegroup] : 0; NEIGH_OMP_INIT; NeighList *listinner = list->listinner; - if (nthreads > listinner->maxpage) - listinner->add_pages(nthreads - listinner->maxpage); - - NeighList *listmiddle; + NeighList *listmiddle = list->listmiddle; const int respamiddle = list->respamiddle; - if (respamiddle) { - listmiddle = list->listmiddle; - if (nthreads > listmiddle->maxpage) - listmiddle->add_pages(nthreads - listmiddle->maxpage); - } #if defined(_OPENMP) #pragma omp parallel default(none) shared(list,listinner,listmiddle) #endif NEIGH_OMP_SETUP(nlocal); int i,j,n,itype,jtype,itag,jtag,n_inner,n_middle; 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 nall = atom->nlocal + atom->nghost; int molecular = atom->molecular; int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; int *ilist_inner = listinner->ilist; int *numneigh_inner = listinner->numneigh; int **firstneigh_inner = listinner->firstneigh; int *ilist_middle,*numneigh_middle,**firstneigh_middle; if (respamiddle) { ilist_middle = listmiddle->ilist; numneigh_middle = listmiddle->numneigh; firstneigh_middle = listmiddle->firstneigh; } - int npage = tid; - int npnt = 0; - int npage_inner = tid; - int npnt_inner = 0; - int npage_middle = tid; - int npnt_middle = 0; + // each thread has its own page allocator + MyPage &ipage = list->ipage[tid]; + MyPage &ipage_inner = listinner->ipage[tid]; + ipage.reset(); + ipage_inner.reset(); + + MyPage *ipage_middle; + if (respamiddle) { + ipage_middle = listmiddle->ipage + tid; + ipage_middle->reset(); + } int which = 0; int minchange = 0; for (i = ifrom; i < ito; i++) { -#if defined(_OPENMP) -#pragma omp critical -#endif - { - if (pgsize - npnt < oneatom) { - npnt = 0; - npage += nthreads; - if (npage >= list->maxpage) list->add_pages(nthreads); - } - neighptr = &(list->pages[npage][npnt]); - n = 0; - - if (pgsize - npnt_inner < oneatom) { - npnt_inner = 0; - npage_inner += nthreads; - if (npage_inner >= listinner->maxpage) listinner->add_pages(nthreads); - } - neighptr_inner = &(listinner->pages[npage_inner][npnt_inner]); - n_inner = 0; - + n = n_inner = 0; + neighptr = ipage.vget(); + neighptr_inner = ipage_inner.vget(); if (respamiddle) { - if (pgsize - npnt_middle < oneatom) { - npnt_middle = 0; - npage_middle += nthreads; - if (npage_middle >= listmiddle->maxpage) listmiddle->add_pages(nthreads); - } - neighptr_middle = &(listmiddle->pages[npage_middle][npnt_middle]); n_middle = 0; + neighptr_middle = ipage_middle->vget(); } - } 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]); if (which == 0) neighptr[n++] = j; else if (minchange = domain->minimum_image_check(delx,dely,delz)) neighptr[n++] = j; else 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 (minchange) neighptr_inner[n_inner++] = 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 (minchange) neighptr_middle[n_middle++] = j; else if (which > 0) neighptr_middle[n_middle++] = j ^ (which << SBBITS); } } } ilist[i] = i; firstneigh[i] = neighptr; numneigh[i] = n; - npnt += n; - if (n > oneatom) + ipage.vgot(n); + if (ipage.status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); ilist_inner[i] = i; firstneigh_inner[i] = neighptr_inner; numneigh_inner[i] = n_inner; - npnt_inner += n_inner; - if (n_inner > oneatom) + ipage.vgot(n_inner); + if (ipage_inner.status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); if (respamiddle) { ilist_middle[i] = i; firstneigh_middle[i] = neighptr_middle; numneigh_middle[i] = n_middle; - npnt_middle += n_middle; - if (n_middle > oneatom) + ipage_middle->vgot(n_middle); + if (ipage_middle->status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } } NEIGH_OMP_CLOSE; list->inum = nlocal; listinner->inum = nlocal; if (respamiddle) listmiddle->inum = nlocal; } /* ---------------------------------------------------------------------- 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_omp(NeighList *list) { // bin local & ghost atoms bin_atoms(); const int nlocal = (includegroup) ? atom->nfirst : atom->nlocal; NEIGH_OMP_INIT; NeighList *listinner = list->listinner; - if (nthreads > listinner->maxpage) - listinner->add_pages(nthreads - listinner->maxpage); - - NeighList *listmiddle; + NeighList *listmiddle = list->listmiddle; const int respamiddle = list->respamiddle; - if (respamiddle) { - listmiddle = list->listmiddle; - if (nthreads > listmiddle->maxpage) - listmiddle->add_pages(nthreads - listmiddle->maxpage); - } #if defined(_OPENMP) #pragma omp parallel default(none) shared(list,listinner,listmiddle) #endif NEIGH_OMP_SETUP(nlocal); int i,j,k,n,itype,jtype,ibin,n_inner,n_middle; 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 molecular = atom->molecular; int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; int nstencil = list->nstencil; int *stencil = list->stencil; int *ilist_inner = listinner->ilist; int *numneigh_inner = listinner->numneigh; int **firstneigh_inner = listinner->firstneigh; int *ilist_middle,*numneigh_middle,**firstneigh_middle; if (respamiddle) { ilist_middle = listmiddle->ilist; numneigh_middle = listmiddle->numneigh; firstneigh_middle = listmiddle->firstneigh; } - int npage = tid; - int npnt = 0; - int npage_inner = tid; - int npnt_inner = 0; - int npage_middle = tid; - int npnt_middle = 0; + // each thread has its own page allocator + MyPage &ipage = list->ipage[tid]; + MyPage &ipage_inner = listinner->ipage[tid]; + ipage.reset(); + ipage_inner.reset(); + + MyPage *ipage_middle; + if (respamiddle) { + ipage_middle = listmiddle->ipage + tid; + ipage_middle->reset(); + } int which = 0; int minchange = 0; for (i = ifrom; i < ito; i++) { -#if defined(_OPENMP) -#pragma omp critical -#endif - { - if (pgsize - npnt < oneatom) { - npnt = 0; - npage += nthreads; - if (npage >= list->maxpage) list->add_pages(nthreads); - } - neighptr = &(list->pages[npage][npnt]); - n = 0; - - if (pgsize - npnt_inner < oneatom) { - npnt_inner = 0; - npage_inner += nthreads; - if (npage_inner >= listinner->maxpage) listinner->add_pages(nthreads); - } - neighptr_inner = &(listinner->pages[npage_inner][npnt_inner]); - n_inner = 0; - + n = n_inner = 0; + neighptr = ipage.vget(); + neighptr_inner = ipage_inner.vget(); if (respamiddle) { - if (pgsize - npnt_middle < oneatom) { - npnt_middle = 0; - npage_middle += nthreads; - if (npage_middle >= listmiddle->maxpage) listmiddle->add_pages(nthreads); - } - neighptr_middle = &(listmiddle->pages[npage_middle][npnt_middle]); n_middle = 0; + neighptr_middle = ipage_middle->vget(); } - } 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]); if (which == 0) neighptr[n++] = j; else if (minchange = domain->minimum_image_check(delx,dely,delz)) neighptr[n++] = j; else 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 (minchange) neighptr_inner[n_inner++] = 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 (minchange) neighptr_middle[n_middle++] = j; else if (which > 0) neighptr_middle[n_middle++] = j ^ (which << SBBITS); } } } } ilist[i] = i; firstneigh[i] = neighptr; numneigh[i] = n; - npnt += n; - if (n > oneatom) + ipage.vgot(n); + if (ipage.status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); ilist_inner[i] = i; firstneigh_inner[i] = neighptr_inner; numneigh_inner[i] = n_inner; - npnt_inner += n_inner; - if (n_inner > oneatom) + ipage.vgot(n_inner); + if (ipage_inner.status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); if (respamiddle) { ilist_middle[i] = i; firstneigh_middle[i] = neighptr_middle; numneigh_middle[i] = n_middle; - npnt_middle += n_middle; - if (n_middle > oneatom) + ipage_middle->vgot(n_middle); + if (ipage_middle->status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } } NEIGH_OMP_CLOSE; list->inum = nlocal; listinner->inum = nlocal; if (respamiddle) listmiddle->inum = nlocal; } /* ---------------------------------------------------------------------- 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_omp(NeighList *list) { // bin local & ghost atoms bin_atoms(); const int nlocal = (includegroup) ? atom->nfirst : atom->nlocal; NEIGH_OMP_INIT; NeighList *listinner = list->listinner; - if (nthreads > listinner->maxpage) - listinner->add_pages(nthreads - listinner->maxpage); - - NeighList *listmiddle; + NeighList *listmiddle = list->listmiddle; const int respamiddle = list->respamiddle; - if (respamiddle) { - listmiddle = list->listmiddle; - if (nthreads > listmiddle->maxpage) - listmiddle->add_pages(nthreads - listmiddle->maxpage); - } #if defined(_OPENMP) #pragma omp parallel default(none) shared(list,listinner,listmiddle) #endif NEIGH_OMP_SETUP(nlocal); int i,j,k,n,itype,jtype,ibin,n_inner,n_middle; 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 molecular = atom->molecular; int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; int nstencil = list->nstencil; int *stencil = list->stencil; int *ilist_inner = listinner->ilist; int *numneigh_inner = listinner->numneigh; int **firstneigh_inner = listinner->firstneigh; int *ilist_middle,*numneigh_middle,**firstneigh_middle; if (respamiddle) { ilist_middle = listmiddle->ilist; numneigh_middle = listmiddle->numneigh; firstneigh_middle = listmiddle->firstneigh; } - int npage = tid; - int npnt = 0; - int npage_inner = tid; - int npnt_inner = 0; - int npage_middle = tid; - int npnt_middle = 0; + // each thread has its own page allocator + MyPage &ipage = list->ipage[tid]; + MyPage &ipage_inner = listinner->ipage[tid]; + ipage.reset(); + ipage_inner.reset(); + + MyPage *ipage_middle; + if (respamiddle) { + ipage_middle = listmiddle->ipage + tid; + ipage_middle->reset(); + } int which = 0; int minchange = 0; for (i = ifrom; i < ito; i++) { -#if defined(_OPENMP) -#pragma omp critical -#endif - { - if (pgsize - npnt < oneatom) { - npnt = 0; - npage += nthreads; - if (npage >= list->maxpage) list->add_pages(nthreads); - } - neighptr = &(list->pages[npage][npnt]); - n = 0; - - if (pgsize - npnt_inner < oneatom) { - npnt_inner = 0; - npage_inner += nthreads; - if (npage_inner >= listinner->maxpage) listinner->add_pages(nthreads); - } - neighptr_inner = &(listinner->pages[npage_inner][npnt_inner]); - n_inner = 0; - + n = n_inner = 0; + neighptr = ipage.vget(); + neighptr_inner = ipage_inner.vget(); if (respamiddle) { - if (pgsize - npnt_middle < oneatom) { - npnt_middle = 0; - npage_middle += nthreads; - if (npage_middle >= listmiddle->maxpage) listmiddle->add_pages(nthreads); - } - neighptr_middle = &(listmiddle->pages[npage_middle][npnt_middle]); n_middle = 0; + neighptr_middle = ipage_middle->vget(); } - } 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]); if (which == 0) neighptr[n++] = j; else if (minchange = domain->minimum_image_check(delx,dely,delz)) neighptr[n++] = j; else 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 (minchange) neighptr_inner[n_inner++] = 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 (minchange) neighptr_middle[n_middle++] = 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]); if (which == 0) neighptr[n++] = j; else if (minchange = domain->minimum_image_check(delx,dely,delz)) neighptr[n++] = j; else 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 (minchange) neighptr_inner[n_inner++] = 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 (minchange) neighptr_middle[n_middle++] = j; else if (which > 0) neighptr_middle[n_middle++] = j ^ (which << SBBITS); } } } } ilist[i] = i; firstneigh[i] = neighptr; numneigh[i] = n; - npnt += n; - if (n > oneatom) + ipage.vgot(n); + if (ipage.status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); ilist_inner[i] = i; firstneigh_inner[i] = neighptr_inner; numneigh_inner[i] = n_inner; - npnt_inner += n_inner; - if (n_inner > oneatom) + ipage.vgot(n_inner); + if (ipage_inner.status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); if (respamiddle) { ilist_middle[i] = i; firstneigh_middle[i] = neighptr_middle; numneigh_middle[i] = n_middle; - npnt_middle += n_middle; - if (n_middle > oneatom) + ipage_middle->vgot(n_middle); + if (ipage_middle->status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } } NEIGH_OMP_CLOSE; list->inum = nlocal; listinner->inum = nlocal; if (respamiddle) listmiddle->inum = nlocal; } /* ---------------------------------------------------------------------- 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_omp(NeighList *list) { // bin local & ghost atoms bin_atoms(); const int nlocal = (includegroup) ? atom->nfirst : atom->nlocal; NEIGH_OMP_INIT; NeighList *listinner = list->listinner; - if (nthreads > listinner->maxpage) - listinner->add_pages(nthreads - listinner->maxpage); - - NeighList *listmiddle; + NeighList *listmiddle = list->listmiddle; const int respamiddle = list->respamiddle; - if (respamiddle) { - listmiddle = list->listmiddle; - if (nthreads > listmiddle->maxpage) - listmiddle->add_pages(nthreads - listmiddle->maxpage); - } #if defined(_OPENMP) #pragma omp parallel default(none) shared(list,listinner,listmiddle) #endif NEIGH_OMP_SETUP(nlocal); int i,j,k,n,itype,jtype,ibin,n_inner,n_middle; 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 molecular = atom->molecular; int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; int nstencil = list->nstencil; int *stencil = list->stencil; int *ilist_inner = listinner->ilist; int *numneigh_inner = listinner->numneigh; int **firstneigh_inner = listinner->firstneigh; int *ilist_middle,*numneigh_middle,**firstneigh_middle; if (respamiddle) { ilist_middle = listmiddle->ilist; numneigh_middle = listmiddle->numneigh; firstneigh_middle = listmiddle->firstneigh; } - int npage = tid; - int npnt = 0; - int npage_inner = tid; - int npnt_inner = 0; - int npage_middle = tid; - int npnt_middle = 0; + // each thread has its own page allocator + MyPage &ipage = list->ipage[tid]; + MyPage &ipage_inner = listinner->ipage[tid]; + ipage.reset(); + ipage_inner.reset(); + + MyPage *ipage_middle; + if (respamiddle) { + ipage_middle = listmiddle->ipage + tid; + ipage_middle->reset(); + } int which = 0; int minchange = 0; for (i = ifrom; i < ito; i++) { -#if defined(_OPENMP) -#pragma omp critical -#endif - { - if (pgsize - npnt < oneatom) { - npnt = 0; - npage += nthreads; - if (npage >= list->maxpage) list->add_pages(nthreads); - } - neighptr = &(list->pages[npage][npnt]); - n = 0; - - if (pgsize - npnt_inner < oneatom) { - npnt_inner = 0; - npage_inner += nthreads; - if (npage_inner >= listinner->maxpage) listinner->add_pages(nthreads); - } - neighptr_inner = &(listinner->pages[npage_inner][npnt_inner]); - n_inner = 0; - + n = n_inner = 0; + neighptr = ipage.vget(); + neighptr_inner = ipage_inner.vget(); if (respamiddle) { - if (pgsize - npnt_middle < oneatom) { - npnt_middle = 0; - npage_middle += nthreads; - if (npage_middle >= listmiddle->maxpage) listmiddle->add_pages(nthreads); - } - neighptr_middle = &(listmiddle->pages[npage_middle][npnt_middle]); n_middle = 0; + neighptr_middle = ipage_middle->vget(); } - } 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]); if (which == 0) neighptr[n++] = j; else if (minchange = domain->minimum_image_check(delx,dely,delz)) neighptr[n++] = j; else 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 (minchange) neighptr_inner[n_inner++] = 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 (minchange) neighptr_middle[n_middle++] = j; else if (which > 0) neighptr_middle[n_middle++] = j ^ (which << SBBITS); } } } } ilist[i] = i; firstneigh[i] = neighptr; numneigh[i] = n; - npnt += n; - if (n > oneatom) + ipage.vgot(n); + if (ipage.status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); ilist_inner[i] = i; firstneigh_inner[i] = neighptr_inner; numneigh_inner[i] = n_inner; - npnt_inner += n_inner; - if (n_inner > oneatom) + ipage.vgot(n_inner); + if (ipage_inner.status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); if (respamiddle) { ilist_middle[i] = i; firstneigh_middle[i] = neighptr_middle; numneigh_middle[i] = n_middle; - npnt_middle += n_middle; - if (n_middle > oneatom) + ipage_middle->vgot(n_middle); + if (ipage_middle->status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } } NEIGH_OMP_CLOSE; list->inum = nlocal; listinner->inum = nlocal; if (respamiddle) listmiddle->inum = nlocal; } diff --git a/src/USER-OMP/neighbor_omp.h b/src/USER-OMP/neighbor_omp.h index 8db58c7e2..2b2ad24fe 100644 --- a/src/USER-OMP/neighbor_omp.h +++ b/src/USER-OMP/neighbor_omp.h @@ -1,59 +1,57 @@ /* -*- c++ -*- ---------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #ifndef LMP_NEIGHBOR_OMP_H #define LMP_NEIGHBOR_OMP_H #if defined(_OPENMP) #include #endif namespace LAMMPS_NS { // these macros hide some ugly and redundant OpenMP related stuff #if defined(_OPENMP) // make sure we have at least one page for each thread #define NEIGH_OMP_INIT \ - const int nthreads = comm->nthreads; \ - if (nthreads > list->maxpage) \ - list->add_pages(nthreads - list->maxpage) + const int nthreads = comm->nthreads; // get thread id and then assign each thread a fixed chunk of atoms #define NEIGH_OMP_SETUP(num) \ { \ const int tid = omp_get_thread_num(); \ const int idelta = 1 + num/nthreads; \ const int ifrom = tid*idelta; \ const int ito = ((ifrom + idelta) > num) \ ? num : (ifrom+idelta); #define NEIGH_OMP_CLOSE } #else /* !defined(_OPENMP) */ #define NEIGH_OMP_INIT \ const int nthreads = comm->nthreads; #define NEIGH_OMP_SETUP(num) \ const int tid = 0; \ const int ifrom = 0; \ const int ito = num #define NEIGH_OMP_CLOSE #endif } #endif diff --git a/src/USER-OMP/pair_airebo_omp.cpp b/src/USER-OMP/pair_airebo_omp.cpp index 8ab26e9bf..ec788fd6c 100644 --- a/src/USER-OMP/pair_airebo_omp.cpp +++ b/src/USER-OMP/pair_airebo_omp.cpp @@ -1,2769 +1,2759 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ #include "math.h" #include "pair_airebo_omp.h" #include "atom.h" #include "comm.h" #include "error.h" #include "force.h" #include "memory.h" +#include "my_page.h" #include "math_special.h" #include "neighbor.h" #include "neigh_list.h" #if defined(_OPENMP) #include #endif #include "suffix.h" using namespace LAMMPS_NS; using namespace MathSpecial; #define TOL 1.0e-9 /* ---------------------------------------------------------------------- */ PairAIREBOOMP::PairAIREBOOMP(LAMMPS *lmp) : PairAIREBO(lmp), ThrOMP(lmp, THR_PAIR) { suffix_flag |= Suffix::OMP; respa_enable = 0; } /* ---------------------------------------------------------------------- */ void PairAIREBOOMP::compute(int eflag, int vflag) { if (eflag || vflag) { ev_setup(eflag,vflag); } else evflag = vflag_fdotr = vflag_atom = 0; REBO_neigh_thr(); const int nall = atom->nlocal + atom->nghost; const int nthreads = comm->nthreads; const int inum = list->inum; #if defined(_OPENMP) #pragma omp parallel default(none) shared(eflag,vflag) #endif { int ifrom, ito, tid; loop_setup_thr(ifrom, ito, tid, inum, nthreads); ThrData *thr = fix->get_thr(tid); ev_setup_thr(eflag, vflag, nall, eatom, vatom, thr); FREBO_thr(ifrom,ito,evflag,eflag,vflag_atom,thr); if (ljflag) FLJ_thr(ifrom,ito,evflag,eflag,vflag_atom,thr); if (torflag) TORSION_thr(ifrom,ito,evflag,eflag,thr); reduce_thr(this, eflag, vflag, thr); } // end of omp parallel region } /* ---------------------------------------------------------------------- Bij function ------------------------------------------------------------------------- */ double PairAIREBOOMP::bondorder_thr(int i, int j, double rij[3], double rijmag, double VA, int vflag_atom, ThrData * const thr) { 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; const double * const * const x = atom->x; double * const * const f = thr->get_f(); 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 = 1.0/sqrt(1.0+Etmp+PijS); tmp = -0.5*pij*pij*pij; const double invrijm = 1.0/rijmag; const double invrijm2 = invrijm*invrijm; // 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); const double invrikm = 1.0/rikmag; const double invrijkm = invrijm*invrikm; const double invrikm2 = invrikm*invrikm; cosjik = (rij[0]*rik[0] + rij[1]*rik[1] + rij[2]*rik[2]) * invrijkm; cosjik = MIN(cosjik,1.0); cosjik = MAX(cosjik,-1.0); dcosjikdri[0] = ((rij[0]+rik[0])*invrijkm) - (cosjik*((rij[0]*invrijm2)+(rik[0]*invrikm2))); dcosjikdri[1] = ((rij[1]+rik[1])*invrijkm) - (cosjik*((rij[1]*invrijm2)+(rik[1]*invrikm2))); dcosjikdri[2] = ((rij[2]+rik[2])*invrijkm) - (cosjik*((rij[2]*invrijm2)+(rik[2]*invrikm2))); dcosjikdrk[0] = (-rij[0]*invrijkm) + (cosjik*(rik[0]*invrikm2)); dcosjikdrk[1] = (-rij[1]*invrijkm) + (cosjik*(rik[1]*invrikm2)); dcosjikdrk[2] = (-rij[2]*invrijkm) + (cosjik*(rik[2]*invrikm2)); dcosjikdrj[0] = (-rik[0]*invrijkm) + (cosjik*(rij[0]*invrijm2)); dcosjikdrj[1] = (-rik[1]*invrijkm) + (cosjik*(rij[1]*invrijm2)); dcosjikdrj[2] = (-rik[2]*invrijkm) + (cosjik*(rij[2]*invrijm2)); 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]*invrijm); fj[1] -= tmp2*(-rij[1]*invrijm); fj[2] -= tmp2*(-rij[2]*invrijm); fi[0] -= tmp2*((-rik[0]*invrikm)+(rij[0]*invrijm)); fi[1] -= tmp2*((-rik[1]*invrikm)+(rij[1]*invrijm)); fi[2] -= tmp2*((-rik[2]*invrikm)+(rij[2]*invrijm)); fk[0] -= tmp2*(rik[0]*invrikm); fk[1] -= tmp2*(rik[1]*invrikm); fk[2] -= tmp2*(rik[2]*invrikm); // coordination forces // dwik forces tmp2 = VA*.5*(tmp*dwik*g*exp(lamdajik))*invrikm; 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)*invrikm; 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)*invrikm; 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_thr(atomi,atomj,atomk,fj,fk,rji,rki,thr); } } } 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 = 1.0/sqrt(1.0+Etmp+PjiS); tmp = -0.5*pji*pji*pji; 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); const double invrjlm = 1.0/rjlmag; const double invrijlm = invrijm*invrjlm; const double invrjlm2 = invrjlm*invrjlm; cosijl = (-1.0*((rij[0]*rjl[0])+(rij[1]*rjl[1])+(rij[2]*rjl[2]))) * invrijlm; cosijl = MIN(cosijl,1.0); cosijl = MAX(cosijl,-1.0); dcosijldri[0] = (-rjl[0]*invrijlm) - (cosijl*rij[0]*invrijm2); dcosijldri[1] = (-rjl[1]*invrijlm) - (cosijl*rij[1]*invrijm2); dcosijldri[2] = (-rjl[2]*invrijlm) - (cosijl*rij[2]*invrijm2); dcosijldrj[0] = ((-rij[0]+rjl[0])*invrijlm) + (cosijl*((rij[0]*invrijm2)-(rjl[0]*invrjlm2))); dcosijldrj[1] = ((-rij[1]+rjl[1])*invrijlm) + (cosijl*((rij[1]*invrijm2)-(rjl[1]*invrjlm2))); dcosijldrj[2] = ((-rij[2]+rjl[2])*invrijlm) + (cosijl*((rij[2]*invrijm2)-(rjl[2]*invrjlm2))); dcosijldrl[0] = (rij[0]*invrijlm)+(cosijl*rjl[0]*invrjlm2); dcosijldrl[1] = (rij[1]*invrijlm)+(cosijl*rjl[1]*invrjlm2); dcosijldrl[2] = (rij[2]*invrijlm)+(cosijl*rjl[2]*invrjlm2); // 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]*invrijm); fi[1] -= tmp2*(rij[1]*invrijm); fi[2] -= tmp2*(rij[2]*invrijm); fj[0] -= tmp2*((-rjl[0]*invrjlm)-(rij[0]*invrijm)); fj[1] -= tmp2*((-rjl[1]*invrjlm)-(rij[1]*invrijm)); fj[2] -= tmp2*((-rjl[2]*invrjlm)-(rij[2]*invrijm)); fl[0] -= tmp2*(rjl[0]*invrjlm); fl[1] -= tmp2*(rjl[1]*invrjlm); fl[2] -= tmp2*(rjl[2]*invrjlm); // coordination forces // dwik forces tmp2 = VA*.5*(tmp*dwjl*g*exp(lamdaijl))*invrjlm; 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)*invrjlm; 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)*invrjlm; 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_thr(atomi,atomj,atoml,fi,fl,rij,rlj,thr); } } } // 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_thr(atomi,atomk,-tmp2,rik,thr); 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_thr(atomi,atomk,-tmp2,rik,thr); 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_thr(atomk,atomn,-tmp2,rkn,thr); } } } } } // 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_thr(atomj,atoml,-tmp2,rjl,thr); 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_thr(atomj,atoml,-tmp2,rjl,thr); 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_thr(atoml,atomn,-tmp2,rln,thr); } } } } } 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-(om1234*om1234))*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-(om1234*om1234)) * (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_thr(atom1,atom2,atom3,atom4,f1,f2,f4,r13,r23,r43,thr); } } } } } } } // 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_thr(atomi,atomk,-tmp2,rik,thr); 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_thr(atomi,atomk,-tmp2,rik,thr); 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_thr(atomk,atomn,-tmp2,rkn,thr); } } } } } // 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_thr(atomj,atoml,-tmp2,rjl,thr); 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_thr(atomj,atoml,-tmp2,rjl,thr); 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_thr(atoml,atomn,-tmp2,rln,thr); } } } } } } bij = (0.5*(pij+pji))+piRC+(Tij*Etmp); return bij; } /* ---------------------------------------------------------------------- Bij* function ------------------------------------------------------------------------- */ double PairAIREBOOMP::bondorderLJ_thr(int i, int j, double rij[3], double rijmag, double VA, double rij0[3], double rij0mag, int vflag_atom, ThrData * const thr) { 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]; const double * const * const x = atom->x; double * const * const f = thr->get_f(); const int * const 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)); 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 += (wik*g*exp(lamdajik)); 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 = 1.0/sqrt(1.0+Etmp+PijS); tmppij = -.5*pij*pij*pij; 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 = 1.0/sqrt(1.0+Etmp+PjiS); tmppji = -.5*pji*pji*pji; 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) > sqrt(TOL)) { 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) > sqrt(TOL)) { 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-(omkijl*omkijl))*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; const double invrijm = 1.0/rijmag; const double invrijm2 = invrijm*invrijm; // 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); const double invrikm = 1.0/rikmag; const double invrijkm = invrijm*invrikm; const double invrikm2 = invrikm*invrikm; cosjik = ((rij[0]*rik[0])+(rij[1]*rik[1])+(rij[2]*rik[2])) * invrijkm; cosjik = MIN(cosjik,1.0); cosjik = MAX(cosjik,-1.0); dcosjikdri[0] = ((rij[0]+rik[0])*invrijkm) - (cosjik*((rij[0]*invrijm2)+(rik[0]*invrikm2))); dcosjikdri[1] = ((rij[1]+rik[1])*invrijkm) - (cosjik*((rij[1]*invrijm2)+(rik[1]*invrikm2))); dcosjikdri[2] = ((rij[2]+rik[2])*invrijkm) - (cosjik*((rij[2]*invrijm2)+(rik[2]*invrikm2))); dcosjikdrk[0] = (-rij[0]*invrijkm) + (cosjik*(rik[0]*invrikm2)); dcosjikdrk[1] = (-rij[1]*invrijkm) + (cosjik*(rik[1]*invrikm2)); dcosjikdrk[2] = (-rij[2]*invrijkm) + (cosjik*(rik[2]*invrikm2)); dcosjikdrj[0] = (-rik[0]*invrijkm) + (cosjik*(rij[0]*invrijm2)); dcosjikdrj[1] = (-rik[1]*invrijkm) + (cosjik*(rij[1]*invrijm2)); dcosjikdrj[2] = (-rik[2]*invrijkm) + (cosjik*(rij[2]*invrijm2)); 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]*invrijm); fj[1] -= tmp2*(-rij[1]*invrijm); fj[2] -= tmp2*(-rij[2]*invrijm); fi[0] -= tmp2*((-rik[0]/rikmag)+(rij[0]*invrijm)); fi[1] -= tmp2*((-rik[1]/rikmag)+(rij[1]*invrijm)); fi[2] -= tmp2*((-rik[2]/rikmag)+(rij[2]*invrijm)); 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_thr(atomi,atomj,atomk,fj,fk,rji,rki,thr); } } } 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); const double invrjlm = 1.0/rjlmag; const double invrijlm = invrijm*invrjlm; const double invrjlm2 = invrjlm*invrjlm; cosijl = (-1.0*((rij[0]*rjl[0])+(rij[1]*rjl[1])+(rij[2]*rjl[2]))) * invrijlm; cosijl = MIN(cosijl,1.0); cosijl = MAX(cosijl,-1.0); dcosijldri[0] = (-rjl[0]*invrijlm) - (cosijl*rij[0]*invrijm2); dcosijldri[1] = (-rjl[1]*invrijlm) - (cosijl*rij[1]*invrijm2); dcosijldri[2] = (-rjl[2]*invrijlm) - (cosijl*rij[2]*invrijm2); dcosijldrj[0] = ((-rij[0]+rjl[0])*invrijlm) + (cosijl*((rij[0]*invrijm2)-(rjl[0]*invrjlm2))); dcosijldrj[1] = ((-rij[1]+rjl[1])*invrijlm) + (cosijl*((rij[1]*invrijm2)-(rjl[1]*invrjlm2))); dcosijldrj[2] = ((-rij[2]+rjl[2])*invrijlm) + (cosijl*((rij[2]*invrijm2)-(rjl[2]*invrjlm2))); dcosijldrl[0] = (rij[0]*invrijlm) + (cosijl*rjl[0]*invrjlm2); dcosijldrl[1] = (rij[1]*invrijlm) + (cosijl*rjl[1]*invrjlm2); dcosijldrl[2] = (rij[2]*invrijlm) + (cosijl*rjl[2]*invrjlm2); // 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]*invrijm); fi[1] -= tmp2*(rij[1]*invrijm); fi[2] -= tmp2*(rij[2]*invrijm); fj[0] -= tmp2*((-rjl[0]*invrjlm)-(rij[0]*invrijm)); fj[1] -= tmp2*((-rjl[1]*invrjlm)-(rij[1]*invrijm)); fj[2] -= tmp2*((-rjl[2]*invrjlm)-(rij[2]*invrijm)); fl[0] -= tmp2*(rjl[0]*invrjlm); fl[1] -= tmp2*(rjl[1]*invrjlm); fl[2] -= tmp2*(rjl[2]*invrjlm); // coordination forces // dwik forces tmp2 = VA*.5*(tmp*dwjl*g*exp(lamdaijl))*invrjlm; 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)*invrjlm; 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)*invrjlm; 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_thr(atomi,atomj,atoml,fi,fl,rij,rlj,thr); } } } // 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_thr(atomi,atomk,-tmp2,rik,thr); 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_thr(atomi,atomk,-tmp2,rik,thr); 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_thr(atomk,atomn,-tmp2,rkn,thr); } } } } } // 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_thr(atomj,atoml,-tmp2,rjl,thr); 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_thr(atomj,atoml,-tmp2,rjl,thr); 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_thr(atoml,atomn,-tmp2,rln,thr); } } } } } 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-(om1234*om1234))*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-(om1234*om1234)) * (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_thr(atom1,atom2,atom3,atom4,f1,f2,f4,r13,r23,r43,thr); } } } } } } } 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_thr(atomi,atomk,-tmp2,rik,thr); 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_thr(atomi,atomk,-tmp2,rik,thr); 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_thr(atomk,atomn,-tmp2,rkn,thr); } } } } } // 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_thr(atomj,atoml,-tmp2,rjl,thr); 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_thr(atomj,atoml,-tmp2,rjl,thr); 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_thr(atoml,atomn,-tmp2,rln,thr); } } } } } } } return Stb; } /* ---------------------------------------------------------------------- REBO forces and energy ------------------------------------------------------------------------- */ void PairAIREBOOMP::FREBO_thr(int ifrom, int ito, int evflag, int eflag, int vflag_atom, ThrData * const thr) { int i,j,k,m,ii,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; const double * const * const x = atom->x; double * const * const f = thr->get_f(); int *type = atom->type; int *tag = atom->tag; int nlocal = atom->nlocal; ilist = list->ilist; // two-body interactions from REBO neighbor list, skip half of them for (ii = ifrom; ii < ito; 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_thr(i,j,del,rij,VA,vflag_atom,thr); 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_thr(this,i,j,nlocal,/* newton_pair */ 1, evdwl,0.0,fpair,delx,dely,delz,thr); } } } /* ---------------------------------------------------------------------- compute LJ forces and energy find 3- and 4-step paths between atoms I,J via REBO neighbor lists ------------------------------------------------------------------------- */ void PairAIREBOOMP::FLJ_thr(int ifrom, int ito, int evflag, int eflag, int vflag_atom, ThrData * const thr) { int i,j,k,m,ii,jj,kk,mm,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; const double * const * const x = atom->x; double * const * const f = thr->get_f(); int *tag = atom->tag; int *type = atom->type; int nlocal = atom->nlocal; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // loop over neighbors of my atoms for (ii = ifrom; ii < ito; 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 = tee*tee; 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_thr(i,j,delscale,rcmin[itype][jtype],VA, delij,rij,vflag_atom,thr); } 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_thr(this,i,j,nlocal,/* newton_pair */ 1, evdwl,0.0,fpair,delij[0],delij[1],delij[2],thr); 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_thr(atomi,atomj,fpair,delij,thr); } 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_thr(atomi,atomj,atomk,fi,fj,delikS,deljkS,thr); } 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_thr(atomi,atomj,atomk,atomm,fi,fj,fk,delimS,deljmS,delkmS,thr); } } } } } } /* ---------------------------------------------------------------------- torsional forces and energy ------------------------------------------------------------------------- */ void PairAIREBOOMP::TORSION_thr(int ifrom, int ito, int evflag, int eflag, ThrData * const thr) { int i,j,k,l,ii,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; const double * const * const x = atom->x; double * const * const f = thr->get_f(); int *type = atom->type; int *tag = atom->tag; ilist = list->ilist; for (ii = ifrom; ii < ito; 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*(powint(cw2,5)))-(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*powint(cw2,4) * 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_thr(this,i,j,k,l,evdwl,fi,fj,fk,delil,del34,delkl,thr); } } } } } } /* ---------------------------------------------------------------------- create REBO neighbor list from main neighbor list REBO neighbor list stores neighbors of ghost atoms ------------------------------------------------------------------------- */ void PairAIREBOOMP::REBO_neigh_thr() { const int nlocal = atom->nlocal; const int nthreads = comm->nthreads; if (atom->nmax > 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"); } - if (nthreads > maxpage) - add_pages(nthreads - maxpage); - #if defined(_OPENMP) #pragma omp parallel default(none) #endif { int i,j,ii,jj,n,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; const int allnum = list->inum + list->gnum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; #if defined(_OPENMP) const int tid = omp_get_thread_num(); #else const int tid = 0; #endif const int iidelta = 1 + allnum/nthreads; const int iifrom = tid*iidelta; const int iito = ((iifrom+iidelta)>allnum) ? allnum : (iifrom+iidelta); // store all REBO neighs of owned and ghost atoms // scan full neighbor list of I - int npage = tid; - int npnt = 0; + // each thread has its own page allocator + MyPage &ipg = ipage[tid]; + ipg.reset(); for (ii = iifrom; ii < iito; ii++) { i = ilist[ii]; -#if defined(_OPENMP) -#pragma omp critical -#endif - if (pgsize - npnt < oneatom) { - npnt = 0; - npage += nthreads; - if (npage >= maxpage) add_pages(nthreads); - } - neighptr = &(pages[npage][npnt]); n = 0; + neighptr = ipg.vget(); 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(FLERR,"REBO list overflow, boost neigh_modify one or page"); + ipg.vgot(n); + if (ipg.status()) + error->one(FLERR,"REBO list overflow, boost neigh_modify one"); } } } /* ---------------------------------------------------------------------- */ double PairAIREBOOMP::memory_usage() { double bytes = memory_usage_thr(); bytes += PairAIREBO::memory_usage(); return bytes; } diff --git a/src/USER-OMP/pair_comb_omp.cpp b/src/USER-OMP/pair_comb_omp.cpp index eea2c6b61..1a8c32f4a 100644 --- a/src/USER-OMP/pair_comb_omp.cpp +++ b/src/USER-OMP/pair_comb_omp.cpp @@ -1,638 +1,630 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ #include "math.h" #include "pair_comb_omp.h" #include "atom.h" #include "comm.h" #include "group.h" #include "force.h" #include "memory.h" +#include "my_page.h" #include "neighbor.h" #include "neigh_list.h" #include "suffix.h" using namespace LAMMPS_NS; #define MAXNEIGH 24 /* ---------------------------------------------------------------------- */ PairCombOMP::PairCombOMP(LAMMPS *lmp) : PairComb(lmp), ThrOMP(lmp, THR_PAIR) { suffix_flag |= Suffix::OMP; respa_enable = 0; } /* ---------------------------------------------------------------------- */ void PairCombOMP::compute(int eflag, int vflag) { if (eflag || vflag) { ev_setup(eflag,vflag); } else evflag = vflag_fdotr = vflag_atom = 0; const int nall = atom->nlocal + atom->nghost; const int nthreads = comm->nthreads; const int inum = list->inum; // Build short range neighbor list Short_neigh_thr(); #if defined(_OPENMP) #pragma omp parallel default(none) shared(eflag,vflag) #endif { int ifrom, ito, tid; loop_setup_thr(ifrom, ito, tid, inum, nthreads); ThrData *thr = fix->get_thr(tid); ev_setup_thr(eflag, vflag, nall, eatom, vatom, thr); if (evflag) { if (eflag) { if (vflag_atom) eval<1,1,1>(ifrom, ito, thr); else eval<1,1,0>(ifrom, ito, thr); } else { if (vflag_atom) eval<1,0,1>(ifrom, ito, thr); else eval<1,0,0>(ifrom, ito, thr); } } else eval<0,0,0>(ifrom, ito, thr); reduce_thr(this, eflag, vflag, thr); } // end of omp parallel region } template void PairCombOMP::eval(int iifrom, int iito, ThrData * const thr) { int i,j,k,ii,jj,kk,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; 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; int sht_jnum, *sht_jlist, nj; evdwl = ecoul = 0.0; const double * const * const x = atom->x; double * const * const f = thr->get_f(); const double * const q = atom->q; const int * const tag = atom->tag; const int * const type = atom->type; const int nlocal = atom->nlocal; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; yaself = vionij = fvionij = Eov = Fov = 0.0; double fxtmp,fytmp,fztmp; double fjxtmp,fjytmp,fjztmp; // self energy correction term: potal potal_calc(potal,fac11,fac11e); // loop over full neighbor list of my atoms for (ii = iifrom; ii < iito; ++ii) { i = ilist[ii]; itag = tag[i]; itype = map[type[i]]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; fxtmp = fytmp = fztmp = 0.0; iq = q[i]; NCo[i] = 0; nj = 0; iparam_i = elem2param[itype][itype][itype]; // self energy, only on i atom yaself = self(¶ms[iparam_i],iq,potal); if (EVFLAG) ev_tally_thr(this,i,i,nlocal,0,yaself, 0.0,0.0,0.0,0.0,0.0,thr); // two-body interactions (long and short repulsive) jlist = firstneigh[i]; jnum = numneigh[i]; sht_jlist = sht_first[i]; sht_jnum = sht_num[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; } // 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 fxtmp += delx*fvionij; fytmp += dely*fvionij; fztmp += delz*fvionij; f[j][0] -= delx*fvionij; f[j][1] -= dely*fvionij; f[j][2] -= delz*fvionij; if (EVFLAG) ev_tally_thr(this,i,j,nlocal,/* newton_pair */ 1, 0.0,vionij,fvionij,delx,dely,delz,thr); // 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 fxtmp += delx*fpair; fytmp += dely*fpair; fztmp += delz*fpair; f[j][0] -= delx*fpair; f[j][1] -= dely*fpair; f[j][2] -= delz*fpair; if (EVFLAG) ev_tally_thr(this,i,j,nlocal,/* newton_pair */ 1, evdwl,0.0,fpair,delx,dely,delz,thr); } // accumulate coordination number information if (cor_flag) { int numcoor = 0; for (jj = 0; jj < sht_jnum; jj++) { j = sht_jlist[jj]; 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; ++numcoor; } } NCo[i] = numcoor; } // three-body interactions // half i-j loop for (jj = 0; jj < sht_jnum; jj++) { j = sht_jlist[jj]; 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; nj ++; // accumulate bondorder zeta for each i-j interaction via loop over k fjxtmp = fjytmp = fjztmp = 0.0; zeta_ij = 0.0; cuo_flag1 = 0; cuo_flag2 = 0; for (kk = 0; kk < sht_jnum; kk++) { k = sht_jlist[kk]; if (j == k) continue; 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],EFLAG,i,nj,rsq1,zeta_ij, iq,jq,fpair,prefactor,evdwl); // 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; fxtmp += delr1[0]*fpair; fytmp += delr1[1]*fpair; fztmp += delr1[2]*fpair; fjxtmp -= delr1[0]*fpair; fjytmp -= delr1[1]*fpair; fjztmp -= delr1[2]*fpair; if (EVFLAG) ev_tally_thr(this,i,j,nlocal,/* newton_pair */ 1,evdwl,0.0, -fpair,-delr1[0],-delr1[1],-delr1[2],thr); // attractive term via loop over k (3-body forces) for (kk = 0; kk < sht_jnum; kk++) { k = sht_jlist[kk]; if (j == k) continue; 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); fxtmp += fi[0] + filp[0]; fytmp += fi[1] + filp[1]; fztmp += fi[2] + filp[2]; fjxtmp += fj[0] + fjlp[0]; fjytmp += fj[1] + fjlp[1]; fjztmp += fj[2] + fjlp[2]; f[k][0] += fk[0] + fklp[0]; f[k][1] += fk[1] + fklp[1]; f[k][2] += fk[2] + fklp[2]; if (EVFLAG) ev_tally_thr(this,i,j,nlocal,/* newton_pair */ 1, elp_ij,0.0,0.0,0.0,0.0,0.0, thr); if (VFLAG_ATOM) v_tally3_thr(i,j,k,fj,fk,delr1,delr2,thr); } f[j][0] += fjxtmp; f[j][1] += fjytmp; f[j][2] += fjztmp; } f[i][0] += fxtmp; f[i][1] += fytmp; f[i][2] += fztmp; if (cuo_flag) params[iparam_i].cutsq *= 0.65; } cuo_flag = 0; } /* ---------------------------------------------------------------------- */ double PairCombOMP::yasu_char(double *qf_fix, int &igroup) { int ii; double potal,fac11,fac11e; const double * const * const x = atom->x; const double * const q = atom->q; const int * const type = atom->type; const int * const tag = atom->tag; const int inum = list->inum; const int * const ilist = list->ilist; const int * const numneigh = list->numneigh; const int * const * const firstneigh = list->firstneigh; const int * const mask = atom->mask; const int groupbit = group->bitmask[igroup]; qf = qf_fix; for (ii = 0; ii < inum; ii++) { const int 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 #if defined(_OPENMP) #pragma omp parallel for private(ii) default(none) shared(potal,fac11e) #endif for (ii = 0; ii < inum; ii ++) { double fqi,fqj,fqij,fqji,fqjj,delr1[3]; double sr1,sr2,sr3; int mr1,mr2,mr3; const int i = ilist[ii]; const int itag = tag[i]; int nj = 0; if (mask[i] & groupbit) { fqi = fqj = fqij = fqji = fqjj = 0.0; // should not be needed. int itype = map[type[i]]; const double xtmp = x[i][0]; const double ytmp = x[i][1]; const double ztmp = x[i][2]; const double iq = q[i]; const int iparam_i = elem2param[itype][itype][itype]; // charge force from self energy fqi = qfo_self(¶ms[iparam_i],iq,potal); // two-body interactions const int * const jlist = firstneigh[i]; const int jnum = numneigh[i]; for (int jj = 0; jj < jnum; jj++) { const int j = jlist[jj] & NEIGHMASK; const int 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] < ytmp) 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; } const int jtype = map[type[j]]; double jq = q[j]; delr1[0] = x[j][0] - xtmp; delr1[1] = x[j][1] - ytmp; delr1[2] = x[j][2] - ztmp; double rsq1 = vec3_dot(delr1,delr1); const int iparam_ij = elem2param[itype][jtype][jtype]; // long range q-dependent if (rsq1 > params[iparam_ij].lcutsq) continue; const int 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); // field correction to self energy and charge force qfo_field(¶ms[iparam_ij],rsq1,iq,jq,fqji,fqjj); fqi += jq * fqij + fqji; #if defined(_OPENMP) #pragma omp atomic #endif qf[j] += (iq * fqij + fqjj); } // three-body interactions for (int jj = 0; jj < jnum; jj++) { const int j = jlist[jj] & NEIGHMASK; const int jtype = map[type[j]]; const double jq = q[j]; delr1[0] = x[j][0] - xtmp; delr1[1] = x[j][1] - ytmp; delr1[2] = x[j][2] - ztmp; double rsq1 = vec3_dot(delr1,delr1); const int iparam_ij = elem2param[itype][jtype][jtype]; if (rsq1 > params[iparam_ij].cutsq) continue; nj ++; // charge force in Aij and Bij qfo_short(¶ms[iparam_ij],i,nj,rsq1,iq,jq,fqij,fqjj); fqi += fqij; #if defined(_OPENMP) #pragma omp atomic #endif qf[j] += fqjj; } #if defined(_OPENMP) #pragma omp atomic #endif 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++) { const int 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 PairCombOMP::memory_usage() { double bytes = memory_usage_thr(); bytes += PairComb::memory_usage(); return bytes; } /* ---------------------------------------------------------------------- */ void PairCombOMP::Short_neigh_thr() { if (atom->nmax > nmax) { nmax = atom->nmax; memory->sfree(sht_first); sht_first = (int **) memory->smalloc(nmax*sizeof(int *), - "pair:sht_first"); + "pair:sht_first"); memory->grow(sht_num,nmax,"pair:sht_num"); memory->grow(NCo,nmax,"pair:NCo"); - memory->grow(bbij,nmax,nmax,"pair:bbij"); + memory->grow(bbij,nmax,MAXNEIGH,"pair:bbij"); } const int nthreads = comm->nthreads; - if (nthreads > maxpage) - add_pages(nthreads - maxpage); #if defined(_OPENMP) #pragma omp parallel default(none) #endif { int nj,npntj,*neighptrj; int iparam_ij,*ilist,*jlist,*numneigh,**firstneigh; int jnum,i,j,ii,jj; double xtmp,ytmp,ztmp,rsq,delrj[3]; double **x = atom->x; int *type = atom->type; const int inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; #if defined(_OPENMP) const int tid = omp_get_thread_num(); #else const int tid = 0; #endif const int iidelta = 1 + inum/nthreads; const int iifrom = tid*iidelta; - int iito = iifrom + iidelta; - if (iito > inum) iito = inum; + const int iito = ((iifrom + iidelta) > inum) ? inum : (iifrom+iidelta); - int npage = tid; - npntj = 0; + // each thread has its own page allocator + MyPage &ipg = ipage[tid]; + ipg.reset(); - if (iifrom < inum) { - for (ii = iifrom; ii < iito; ii++) { - i = ilist[ii]; + // create Comb neighbor list -#if defined(_OPENMP) -#pragma omp critical -#endif - if(pgsize - npntj < oneatom) { - npntj = 0; - npage += nthreads; - if (npage >= maxpage) add_pages(nthreads); - } + for (ii = iifrom; ii < iito; ii++) { + i = ilist[ii]; - neighptrj = &pages[npage][npntj]; - nj = 0; + nj = 0; + neighptrj = ipg.vget(); - xtmp = x[i][0]; - ytmp = x[i][1]; - ztmp = x[i][2]; + xtmp = x[i][0]; + ytmp = x[i][1]; + ztmp = x[i][2]; - jlist = firstneigh[i]; - jnum = numneigh[i]; + jlist = firstneigh[i]; + jnum = numneigh[i]; - for (jj = 0; jj < jnum; jj++) { - j = jlist[jj]; - j &= NEIGHMASK; + for (jj = 0; jj < jnum; jj++) { + j = jlist[jj]; + j &= NEIGHMASK; - delrj[0] = xtmp - x[j][0]; - delrj[1] = ytmp - x[j][1]; - delrj[2] = ztmp - x[j][2]; - rsq = vec3_dot(delrj,delrj); + delrj[0] = xtmp - x[j][0]; + delrj[1] = ytmp - x[j][1]; + delrj[2] = ztmp - x[j][2]; + rsq = vec3_dot(delrj,delrj); - if (rsq > cutmin) continue; - neighptrj[nj++] = j; - } - sht_first[i] = neighptrj; - sht_num[i] = nj; - npntj += nj; + if (rsq > cutmin) continue; + neighptrj[nj++] = j; } + sht_first[i] = neighptrj; + sht_num[i] = nj; + ipg.vgot(nj); + if (ipg.status()) + error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } } } diff --git a/src/fix_shear_history.cpp b/src/fix_shear_history.cpp index da0def908..5da158339 100644 --- a/src/fix_shear_history.cpp +++ b/src/fix_shear_history.cpp @@ -1,417 +1,431 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "mpi.h" #include "string.h" #include "stdio.h" #include "fix_shear_history.h" #include "atom.h" +#include "comm.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; using namespace FixConst; /* ---------------------------------------------------------------------- */ FixShearHistory::FixShearHistory(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg) { restart_peratom = 1; create_attribute = 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); ipage = NULL; dpage = NULL; pgsize = oneatom = 0; // 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; maxtouch = 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->sfree(partner); memory->sfree(shearpartner); - delete ipage; - delete dpage; + delete [] ipage; + delete [] dpage; } /* ---------------------------------------------------------------------- */ int FixShearHistory::setmask() { int mask = 0; mask |= PRE_EXCHANGE; mask |= MIN_PRE_EXCHANGE; return mask; } /* ---------------------------------------------------------------------- */ void FixShearHistory::init() { if (atom->tag_enable == 0) error->all(FLERR, "Pair style granular with history requires atoms have IDs"); int dim; computeflag = (int *) pair->extract("computeflag",dim); // create pages if first time or if neighbor pgsize/oneatom has changed // note that latter could cause shear history info to be discarded int create = 0; if (ipage == NULL) create = 1; if (pgsize != neighbor->pgsize) create = 1; if (oneatom != neighbor->oneatom) create = 1; if (create) { + delete [] ipage; + delete [] dpage; + pgsize = neighbor->pgsize; oneatom = neighbor->oneatom; - ipage = new MyPage(oneatom,pgsize); - dpage = new MyPage(oneatom,pgsize); + int nmypage = comm->nthreads; + ipage = new MyPage[nmypage]; + dpage = new MyPage[nmypage]; + for (int i = 0; i < nmypage; i++) { + ipage[i].init(oneatom,pgsize); + dpage[i].init(oneatom,pgsize); + } } } /* ---------------------------------------------------------------------- called by setup of run or minimize called by write_restart as input script command only invoke pre_exchange() if neigh list stores more current history info than npartner/partner arrays in this fix that will only be case if pair->compute() has been invoked since update of npartner/npartner this logic avoids 2 problems: run 100; write_restart; run 100 setup_pre_exchange is called twice (by write_restart and 2nd run setup) w/out a neighbor list being created in between read_restart; run 100 setup_pre_exchange called by run setup whacks restart shear history info ------------------------------------------------------------------------- */ void FixShearHistory::setup_pre_exchange() { if (*computeflag) pre_exchange(); *computeflag = 0; } /* ---------------------------------------------------------------------- copy shear partner info from neighbor lists to atom arrays so can be migrated or stored with atoms ------------------------------------------------------------------------- */ void FixShearHistory::pre_exchange() { int i,j,ii,jj,m,n,inum,jnum; int *ilist,*jlist,*numneigh,**firstneigh; int *touch,**firsttouch; double *shear,*allshear,**firstshear; // zero npartner for all current atoms // clear 2 page data structures int nlocal = atom->nlocal; for (i = 0; i < nlocal; i++) npartner[i] = 0; ipage->reset(); dpage->reset(); // 1st loop over neighbor list // calculate npartner for each owned atom 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]; jnum = numneigh[i]; touch = firsttouch[i]; for (jj = 0; jj < jnum; jj++) { if (touch[jj]) { npartner[i]++; j = jlist[jj]; j &= NEIGHMASK; if (j < nlocal) npartner[j]++; } } } // get page chunks to store atom IDs and shear history for my atoms for (ii = 0; ii < inum; ii++) { i = ilist[ii]; n = npartner[i]; partner[i] = ipage->get(n); shearpartner[i] = dpage->get(n); if (partner[i] == NULL || shearpartner[i] == NULL) error->one(FLERR,"Shear history overflow, boost neigh_modify one"); } // 2nd loop over neighbor list // store atom IDs and shear history for my atoms // re-zero npartner to use as counter for all my atoms for (i = 0; i < nlocal; i++) npartner[i] = 0; 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; 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) { 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]++; } } } } // set maxtouch = max # of partners of any owned atom maxtouch = 0; for (i = 0; i < nlocal; i++) maxtouch = MAX(maxtouch,npartner[i]); } /* ---------------------------------------------------------------------- */ void FixShearHistory::min_setup_pre_exchange() { if (*computeflag) pre_exchange(); *computeflag = 0; } /* ---------------------------------------------------------------------- */ void FixShearHistory::min_pre_exchange() { pre_exchange(); } /* ---------------------------------------------------------------------- memory usage of local atom-based arrays ------------------------------------------------------------------------- */ double FixShearHistory::memory_usage() { int nmax = atom->nmax; double bytes = nmax * sizeof(int); bytes = nmax * sizeof(int *); bytes = nmax * sizeof(double *); - bytes += ipage->ndatum * sizeof(int); - bytes += dpage->ndatum * sizeof(double[3]); + + int nmypage = comm->nthreads; + for (int i = 0; i < nmypage; i++) { + bytes += ipage[i].size(); + bytes += dpage[i].size(); + } + return bytes; } /* ---------------------------------------------------------------------- allocate local atom-based arrays ------------------------------------------------------------------------- */ void FixShearHistory::grow_arrays(int nmax) { memory->grow(npartner,nmax,"shear_history:npartner"); partner = (int **) memory->srealloc(partner,nmax*sizeof(int *), "shear_history:partner"); typedef double (*sptype)[3]; shearpartner = (sptype *) memory->srealloc(shearpartner,nmax*sizeof(sptype), "shear_history:shearpartner"); } /* ---------------------------------------------------------------------- copy values within local atom-based arrays ------------------------------------------------------------------------- */ void FixShearHistory::copy_arrays(int i, int j, int delflag) { // just copy pointers for partner and shearpartner // b/c can't overwrite chunk allocation inside ipage,dpage // incoming atoms in unpack_exchange just grab new chunks // so are orphaning chunks for migrating atoms // OK, b/c will reset ipage,dpage on next reneighboring npartner[j] = npartner[i]; partner[j] = partner[i]; shearpartner[j] = shearpartner[i]; } /* ---------------------------------------------------------------------- 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) { // NOTE: how do I know comm buf is big enough if extreme # of touching neighs // Comm::BUFEXTRA may need to be increased 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) { // allocate new chunks from ipage,dpage for incoming values int m = 0; npartner[nlocal] = static_cast (buf[m++]); maxtouch = MAX(maxtouch,npartner[nlocal]); partner[nlocal] = ipage->get(npartner[nlocal]); shearpartner[nlocal] = dpage->get(npartner[nlocal]); 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++; // allocate new chunks from ipage,dpage for incoming values npartner[nlocal] = static_cast (extra[nlocal][m++]); maxtouch = MAX(maxtouch,npartner[nlocal]); partner[nlocal] = ipage->get(npartner[nlocal]); shearpartner[nlocal] = dpage->get(npartner[nlocal]); 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() { // maxtouch_all = max touching partners across all procs int maxtouch_all; MPI_Allreduce(&maxtouch,&maxtouch_all,1,MPI_INT,MPI_MAX,world); return 4*maxtouch_all + 2; } /* ---------------------------------------------------------------------- size of atom nlocal's restart data ------------------------------------------------------------------------- */ int FixShearHistory::size_restart(int nlocal) { return 4*npartner[nlocal] + 2; } diff --git a/src/my_page.h b/src/my_page.h index 1628a4bab..5fdf1e135 100644 --- a/src/my_page.h +++ b/src/my_page.h @@ -1,202 +1,232 @@ -/* ---------------------------------------------------------------------- +/* -*- c++ -*- ---------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- MyPage = templated class for storing chunks of datums in pages chunks are not returnable, can only reset and start over replaces many small mallocs with a few large mallocs pages are never freed, so can reuse w/out reallocs usage: request one datum at a time, repeat, clear request chunks of datums in each get() or vget(), repeat, clear chunk size can vary from request to request chunk size can be known in advance or registered after usage via vgot() inputs: template T = one datum, e.g. int, double, struct, int[3] for int[3], access datum as ivec[i][2] - maxchunk = max # of datums in one chunk, default = 1 - pagesize = # of datums in one page, default = 1024 - should be insure big enough to store multiple chunks - pagedelta = # of pages to allocate at a time, default = 1 methods: T *get() = return ptr to one datum T *get(N) = return ptr to N datums, N < maxchunk required T *vget() = return ptr to maxchunk datums, use as needed, then call vgot() all gets return NULL if error encountered vgot(N) = used N datums of previous vget(), N < maxchunk required + void init(maxchunk, pagesize, pagedelta) + define allocation params and allocate first page(s) + call right after constructor + can call again to reset allocation params and free previous pages + maxchunk = max # of datums in one chunk, default = 1 + pagesize = # of datums in one page, default = 1024 + should be big enough to store multiple chunks + pagedelta = # of pages to allocate at a time, default = 1 + return 1 if bad params void reset() = clear pages w/out freeing int size() = return total size of allocated pages in bytes -public variables: - ndatum = total # of stored datums - nchunk = total # of stored chunks - errorflag = flag for various error conditions + int status() = return error status + 0 = ok, 1 = chunksize > maxchunk, 2 = allocation error ------------------------------------------------------------------------- */ #ifndef LAMMPS_MY_PAGE_H #define LAMMPS_MY_PAGE_H #include "stdlib.h" namespace LAMMPS_NS { template class MyPage { - public: int ndatum; // total # of stored datums int nchunk; // total # of stored chunks - int errorflag; // flag > 1 if error has occurred - // 1 = invalid inputs - // 2 = memory allocation error - // 3 = chunk size exceeded maxchunk - MyPage(int user_maxchunk = 1, int user_pagesize = 1024, - int user_pagedelta = 1) { + public: + MyPage() { + ndatum = nchunk = 0; + pages = NULL; + npage = 0; + errorflag = 0; + } + + // (re)initialize allocation params + // also allocate first page(s) + + int init(int user_maxchunk = 1, int user_pagesize = 1024, + int user_pagedelta = 1) { maxchunk = user_maxchunk; pagesize = user_pagesize; pagedelta = user_pagedelta; - errorflag = 0; - if (maxchunk <= 0 || pagesize <= 0 || pagedelta <= 0) errorflag = 1; - if (maxchunk > pagesize) errorflag = 1; - if (errorflag) return; + if (maxchunk <= 0 || pagesize <= 0 || pagedelta <= 0) return 1; + if (maxchunk > pagesize) return 1; + + // free any previously allocated pages + + for (int i = 0; i < npage; i++) free(pages[i]); + free(pages); // initial page allocation ndatum = nchunk = 0; pages = NULL; npage = 0; allocate(); - if (errorflag) return; + if (errorflag) return 2; ipage = index = 0; page = pages[ipage]; + return 0; } - // free all pages of allocated memory + // free all allocated pages ~MyPage() { for (int i = 0; i < npage; i++) free(pages[i]); free(pages); } // get ptr to one datum // return NULL if run out of memory T *get() { ndatum++; nchunk++; if (index < pagesize) return &page[index++]; ipage++; if (ipage == npage) { allocate(); if (errorflag) return NULL; } page = pages[ipage]; index = 0; return &page[index++]; } // get ptr to location that can store N datums // error if N > maxchunk // return NULL if run out of memory T *get(int n) { if (n > maxchunk) { - errorflag = 3; + errorflag = 1; return NULL; } ndatum += n; nchunk++; if (index+n <= pagesize) { int start = index; index += n; return &page[start]; } ipage++; if (ipage == npage) { allocate(); if (errorflag) return NULL; } page = pages[ipage]; index = n; return &page[0]; } // get ptr to location that can store maxchunk datums // will return same ptr as previous call if vgot() not called // return NULL if run out of memory T *vget() { if (index+maxchunk <= pagesize) return &page[index]; ipage++; if (ipage == npage) { allocate(); if (errorflag) return NULL; } page = pages[ipage]; index = 0; return &page[index]; } // increment by N = # of values stored in loc returned by vget() // OK to not call if vget() ptr was not used // error if N > maxchunk void vgot(int n) { - if (n > maxchunk) errorflag = 3; + if (n > maxchunk) errorflag = 1; ndatum += n; nchunk++; index += n; } - // reset index to beginning of first page - // effectively clears all pages, without freeing any memory + // clear all pages, without freeing any memory void reset() { ndatum = nchunk = 0; index = ipage = 0; page = pages[ipage]; } - // return total size of all allocated pages + // return total size of allocated pages - int size() { + int size() const { return npage*pagesize*sizeof(T); } - private: - int maxchunk; // max # of datums in one requested chunk - int pagesize; // # of datums in one page, default = 1024 - int pagedelta; // # of pages to allocate at once, default = 1 + // return error status + int status() const { + return errorflag; + } + + private: T **pages; // list of allocated pages T *page; // ptr to current page int npage; // # of allocated pages int ipage; // index of current page int index; // current index on current page + int maxchunk; // max # of datums in one requested chunk + int pagesize; // # of datums in one page, default = 1024 + int pagedelta; // # of pages to allocate at once, default = 1 + + int errorflag; // flag > 0 if error has occurred + // 1 = chunk size exceeded maxchunk + // 2 = memory allocation error + void allocate() { npage += pagedelta; pages = (T **) realloc(pages,npage*sizeof(T *)); if (!pages) { errorflag = 2; return; } + + void *ptr; for (int i = npage-pagedelta; i < npage; i++) { +#if defined(LAMMPS_MEMALIGN) + if (posix_memalign(&ptr, LAMMPS_MEMALIGN, pagesize*sizeof(T))) + errorflag = 2; + pages[i] = (T *) ptr; +#else pages[i] = (T *) malloc(pagesize*sizeof(T)); if (!pages[i]) errorflag = 2; +#endif } } }; } #endif diff --git a/src/neigh_derive.cpp b/src/neigh_derive.cpp index 4bda3d71d..343dc1dc6 100644 --- a/src/neigh_derive.cpp +++ b/src/neigh_derive.cpp @@ -1,504 +1,459 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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 "my_page.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,joriginal; int *neighptr,*jlist; int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; - int **pages = list->pages; + MyPage *ipage = list->ipage; + 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; + ipage->reset(); // 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; + neighptr = ipage->vget(); // loop over parent full list i = ilist_full[ii]; jlist = firstneigh_full[i]; jnum = numneigh_full[i]; for (jj = 0; jj < jnum; jj++) { 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) + ipage->vgot(n); + if (ipage->status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } 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 *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; - int **pages = list->pages; + MyPage *ipage = list->ipage; + 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; + ipage->reset(); // 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; + neighptr = ipage->vget(); 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++) { joriginal = jlist[jj]; j = joriginal & NEIGHMASK; if (j < nlocal) { if (i > j) 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; } } neighptr[n++] = joriginal; } ilist[inum++] = i; firstneigh[i] = neighptr; numneigh[i] = n; - npnt += n; - if (n > oneatom) + ipage->vgot(n); + if (ipage->status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } 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 *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; - int **pages = list->pages; + MyPage *ipage = list->ipage; + 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; + ipage->reset(); // 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; + neighptr = ipage->vget(); // loop over parent non-skip list jlist = firstneigh_skip[i]; jnum = numneigh_skip[i]; for (jj = 0; jj < jnum; jj++) { 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) + ipage->vgot(n); + if (ipage->status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } 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 *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; - int **pages = list->pages; + MyPage *ipage = list->ipage; + 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; + MyPage *ipage_touch = listgranhistory->ipage; + MyPage *dpage_shear = listgranhistory->dpage; int inum = 0; - int npage = 0; - int npnt = 0; + ipage->reset(); + ipage_touch->reset(); + dpage_shear->reset(); // 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]; + n = nn = 0; + neighptr = ipage->vget(); + touchptr = ipage_touch->vget(); + shearptr = dpage_shear->vget(); // 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++) { 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; + ipage->vgot(n); + if (ipage->status()) + error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); + firsttouch[i] = touchptr; firstshear[i] = shearptr; - npnt += n; - if (n > oneatom) - error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); + ipage_touch->vgot(n); + dpage_shear->vgot(nn); } 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 *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; - int **pages = list->pages; + MyPage *ipage = list->ipage; + 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; + MyPage *ipage_inner = listinner->ipage; + 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 *ilist_middle,*numneigh_middle,**firstneigh_middle; + MyPage *ipage_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; + ipage_middle = listmiddle->ipage; 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; + ipage->reset(); + ipage_inner->reset(); + if (respamiddle) ipage_middle->reset(); // 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; - + n = n_inner = 0; + neighptr = ipage->vget(); + neighptr_inner = ipage_inner->vget(); 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; + neighptr_middle = ipage_middle->vget(); } // loop over parent outer rRESPA list jlist = firstneigh_skip[i]; jnum = numneigh_skip[i]; for (jj = 0; jj < jnum; jj++) { 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++) { 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++) { joriginal = jlist[jj]; j = joriginal & NEIGHMASK; if (ijskip[itype][type[j]]) continue; neighptr_middle[n_middle++] = joriginal; } } - ilist[inum++] = i; + ilist[inum] = i; firstneigh[i] = neighptr; numneigh[i] = n; - npnt += n; - if (n > oneatom) + ipage->vgot(n); + if (ipage->status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); firstneigh_inner[i] = neighptr_inner; numneigh_inner[i] = n_inner; - npnt_inner += n_inner; - if (n_inner > oneatom) + ipage_inner->vgot(n); + if (ipage_inner->status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); if (respamiddle) { firstneigh_middle[i] = neighptr_middle; numneigh_middle[i] = n_middle; - npnt_middle += n_middle; - if (n_middle > oneatom) + ipage_middle->vgot(n); + if (ipage_middle->status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } } 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; + list->ipage = listcopy->ipage; + list->dpage = listcopy->dpage; } diff --git a/src/neigh_full.cpp b/src/neigh_full.cpp index 970e3c572..0c830b372 100644 --- a/src/neigh_full.cpp +++ b/src/neigh_full.cpp @@ -1,542 +1,503 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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 "domain.h" +#include "my_page.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; + MyPage *ipage = list->ipage; int inum = 0; - int npage = 0; - int npnt = 0; + ipage->reset(); // 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; + neighptr = ipage->vget(); 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]); if (which == 0) neighptr[n++] = j; else if (domain->minimum_image_check(delx,dely,delz)) neighptr[n++] = j; else 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) + ipage->vgot(n); + if (ipage->status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } list->inum = inum; list->gnum = 0; } /* ---------------------------------------------------------------------- N^2 search for all neighbors include neighbors of ghost atoms, but no "special neighbors" for ghosts 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; + MyPage *ipage = list->ipage; int inum = 0; - int npage = 0; - int npnt = 0; + ipage->reset(); // 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; + neighptr = ipage->vget(); 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 // no molecular test when i = ghost atom 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]); if (which == 0) neighptr[n++] = j; else if (domain->minimum_image_check(delx,dely,delz)) neighptr[n++] = j; else 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]) neighptr[n++] = j; } } ilist[inum++] = i; firstneigh[i] = neighptr; numneigh[i] = n; - npnt += n; - if (n > oneatom) + ipage->vgot(n); + if (ipage->status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } 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 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; + MyPage *ipage = list->ipage; int inum = 0; - int npage = 0; - int npnt = 0; + ipage->reset(); // 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; + neighptr = ipage->vget(); 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]); if (which == 0) neighptr[n++] = j; else if (domain->minimum_image_check(delx,dely,delz)) neighptr[n++] = j; else 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) + ipage->vgot(n); + if (ipage->status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } list->inum = inum; list->gnum = 0; } /* ---------------------------------------------------------------------- binned neighbor list construction for all neighbors include neighbors of ghost atoms, but no "special neighbors" for ghosts 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; + MyPage *ipage = list->ipage; int inum = 0; - int npage = 0; - int npnt = 0; + ipage->reset(); // 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; + neighptr = ipage->vget(); 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 // no molecular test when i = ghost atom 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]); if (which == 0) neighptr[n++] = j; else if (domain->minimum_image_check(delx,dely,delz)) neighptr[n++] = j; else 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]) neighptr[n++] = j; } } } ilist[inum++] = i; firstneigh[i] = neighptr; numneigh[i] = n; - npnt += n; - if (n > oneatom) + ipage->vgot(n); + if (ipage->status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } 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 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; + MyPage *ipage = list->ipage; int inum = 0; - int npage = 0; - int npnt = 0; + ipage->reset(); 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; + neighptr = ipage->vget(); 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]); if (which == 0) neighptr[n++] = j; else if (domain->minimum_image_check(delx,dely,delz)) neighptr[n++] = j; else 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) + ipage->vgot(n); + if (ipage->status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } list->inum = inum; list->gnum = 0; } diff --git a/src/neigh_gran.cpp b/src/neigh_gran.cpp index b9fd604f6..204988e23 100644 --- a/src/neigh_gran.cpp +++ b/src/neigh_gran.cpp @@ -1,624 +1,586 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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 "fix_shear_history.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- granular particles N^2 / 2 search for neighbor pairs with partial Newton's 3rd law shear history must be accounted for when a neighbor pair is added 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::granular_nsq_no_newton(NeighList *list) { int i,j,m,n,nn,bitmask; double xtmp,ytmp,ztmp,delx,dely,delz,rsq; double radi,radsum,cutsq; int *neighptr,*touchptr; double *shearptr; NeighList *listgranhistory; int *npartner,**partner; double (**shearpartner)[3]; int **firsttouch; double **firstshear; - int **pages_touch; - double **pages_shear; + MyPage *ipage_touch; + MyPage *dpage_shear; double **x = atom->x; double *radius = atom->radius; int *tag = atom->tag; 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; bitmask = group->bitmask[includegroup]; } int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; - int **pages = list->pages; + MyPage *ipage = list->ipage; FixShearHistory *fix_history = list->fix_history; if (fix_history) { npartner = fix_history->npartner; partner = fix_history->partner; shearpartner = fix_history->shearpartner; listgranhistory = list->listgranhistory; firsttouch = listgranhistory->firstneigh; firstshear = listgranhistory->firstdouble; - pages_touch = listgranhistory->pages; - pages_shear = listgranhistory->dpages; + ipage_touch = listgranhistory->ipage; + dpage_shear = listgranhistory->dpage; } int inum = 0; - int npage = 0; - int npnt = 0; + ipage->reset(); + if (fix_history) { + ipage_touch->reset(); + dpage_shear->reset(); + } for (i = 0; i < nlocal; i++) { - - if (pgsize - npnt < oneatom) { - npnt = 0; - npage++; - if (npage == list->maxpage) { - pages = list->add_pages(); - if (fix_history) { - pages_touch = listgranhistory->add_pages(); - pages_shear = listgranhistory->dpages; - } - } - } - n = 0; - neighptr = &pages[npage][npnt]; + neighptr = ipage->vget(); if (fix_history) { nn = 0; - touchptr = &pages_touch[npage][npnt]; - shearptr = &pages_shear[npage][3*npnt]; + touchptr = ipage_touch->vget(); + shearptr = dpage_shear->vget(); } xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; radi = radius[i]; // loop over remaining atoms, owned and ghost for (j = i+1; j < nall; j++) { if (includegroup && !(mask[j] & bitmask)) continue; if (exclude && exclusion(i,j,type[i],type[j],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; radsum = radi + radius[j]; cutsq = (radsum+skin) * (radsum+skin); if (rsq <= cutsq) { neighptr[n] = j; if (fix_history) { if (rsq < radsum*radsum) { for (m = 0; m < npartner[i]; m++) if (partner[i][m] == tag[j]) break; if (m < npartner[i]) { touchptr[n] = 1; shearptr[nn++] = shearpartner[i][m][0]; shearptr[nn++] = shearpartner[i][m][1]; shearptr[nn++] = shearpartner[i][m][2]; } else { touchptr[n] = 0; shearptr[nn++] = 0.0; shearptr[nn++] = 0.0; shearptr[nn++] = 0.0; } } else { touchptr[n] = 0; shearptr[nn++] = 0.0; shearptr[nn++] = 0.0; shearptr[nn++] = 0.0; } } n++; } } ilist[inum++] = i; firstneigh[i] = neighptr; numneigh[i] = n; + ipage->vgot(n); + if (ipage->status()) + error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); + if (fix_history) { firsttouch[i] = touchptr; firstshear[i] = shearptr; + ipage_touch->vgot(n); + dpage_shear->vgot(nn); } - npnt += n; - if (n > oneatom) - error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } list->inum = inum; } /* ---------------------------------------------------------------------- granular particles N^2 / 2 search for neighbor pairs with full Newton's 3rd law no shear history is allowed for this option 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::granular_nsq_newton(NeighList *list) { int i,j,n,itag,jtag,bitmask; double xtmp,ytmp,ztmp,delx,dely,delz,rsq; double radi,radsum,cutsq; int *neighptr; double **x = atom->x; double *radius = atom->radius; int *tag = atom->tag; 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; bitmask = group->bitmask[includegroup]; } int *ilist = list->ilist; int *numneigh = list->numneigh; int **firstneigh = list->firstneigh; - int **pages = list->pages; + MyPage *ipage = list->ipage; int inum = 0; - int npage = 0; - int npnt = 0; + ipage->reset(); for (i = 0; i < nlocal; i++) { - - if (pgsize - npnt < oneatom) { - npnt = 0; - npage++; - if (npage == list->maxpage) pages = list->add_pages(); - } - n = 0; - neighptr = &pages[npage][npnt]; + neighptr = ipage->vget(); itag = tag[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; radi = radius[i]; // 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; } } } if (exclude && exclusion(i,j,type[i],type[j],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; radsum = radi + radius[j]; cutsq = (radsum+skin) * (radsum+skin); if (rsq <= cutsq) neighptr[n++] = j; } ilist[inum++] = i; firstneigh[i] = neighptr; numneigh[i] = n; - npnt += n; - if (n > oneatom) + ipage->vgot(n); + if (ipage->status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } list->inum = inum; } /* ---------------------------------------------------------------------- granular particles binned neighbor list construction with partial Newton's 3rd law shear history must be accounted for when a neighbor pair is added 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::granular_bin_no_newton(NeighList *list) { int i,j,k,m,n,nn,ibin; double xtmp,ytmp,ztmp,delx,dely,delz,rsq; double radi,radsum,cutsq; int *neighptr,*touchptr; double *shearptr; NeighList *listgranhistory; int *npartner,**partner; double (**shearpartner)[3]; int **firsttouch; double **firstshear; - int **pages_touch; - double **pages_shear; + MyPage *ipage_touch; + MyPage *dpage_shear; // bin local & ghost atoms bin_atoms(); // loop over each atom, storing neighbors double **x = atom->x; double *radius = atom->radius; int *tag = atom->tag; int *type = atom->type; int *mask = atom->mask; int *molecule = atom->molecule; int nlocal = atom->nlocal; 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; + MyPage *ipage = list->ipage; FixShearHistory *fix_history = list->fix_history; if (fix_history) { npartner = fix_history->npartner; partner = fix_history->partner; shearpartner = fix_history->shearpartner; listgranhistory = list->listgranhistory; firsttouch = listgranhistory->firstneigh; firstshear = listgranhistory->firstdouble; - pages_touch = listgranhistory->pages; - pages_shear = listgranhistory->dpages; + ipage_touch = listgranhistory->ipage; + dpage_shear = listgranhistory->dpage; } int inum = 0; - int npage = 0; - int npnt = 0; + ipage->reset(); + if (fix_history) { + ipage_touch->reset(); + dpage_shear->reset(); + } for (i = 0; i < nlocal; i++) { - - if (pgsize - npnt < oneatom) { - npnt = 0; - npage++; - if (npage == list->maxpage) { - pages = list->add_pages(); - if (fix_history) { - pages_touch = listgranhistory->add_pages(); - pages_shear = listgranhistory->dpages; - } - } - } - n = 0; - neighptr = &pages[npage][npnt]; + neighptr = ipage->vget(); if (fix_history) { nn = 0; - touchptr = &pages_touch[npage][npnt]; - shearptr = &pages_shear[npage][3*npnt]; + touchptr = ipage_touch->vget(); + shearptr = dpage_shear->vget(); } xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; radi = radius[i]; 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; if (exclude && exclusion(i,j,type[i],type[j],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; radsum = radi + radius[j]; cutsq = (radsum+skin) * (radsum+skin); if (rsq <= cutsq) { neighptr[n] = j; if (fix_history) { if (rsq < radsum*radsum) { for (m = 0; m < npartner[i]; m++) if (partner[i][m] == tag[j]) break; if (m < npartner[i]) { touchptr[n] = 1; shearptr[nn++] = shearpartner[i][m][0]; shearptr[nn++] = shearpartner[i][m][1]; shearptr[nn++] = shearpartner[i][m][2]; } else { touchptr[n] = 0; shearptr[nn++] = 0.0; shearptr[nn++] = 0.0; shearptr[nn++] = 0.0; } } else { touchptr[n] = 0; shearptr[nn++] = 0.0; shearptr[nn++] = 0.0; shearptr[nn++] = 0.0; } } n++; } } } ilist[inum++] = i; firstneigh[i] = neighptr; numneigh[i] = n; + ipage->vgot(n); + if (ipage->status()) + error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); + if (fix_history) { firsttouch[i] = touchptr; firstshear[i] = shearptr; + ipage_touch->vgot(n); + dpage_shear->vgot(nn); } - npnt += n; - if (n > oneatom) - error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } list->inum = inum; } /* ---------------------------------------------------------------------- granular particles binned neighbor list construction with full Newton's 3rd law no shear history is allowed for this option each owned atom i checks its own bin and other bins in Newton stencil every pair stored exactly once by some processor ------------------------------------------------------------------------- */ void Neighbor::granular_bin_newton(NeighList *list) { int i,j,k,n,ibin; double xtmp,ytmp,ztmp,delx,dely,delz,rsq; double radi,radsum,cutsq; int *neighptr; // bin local & ghost atoms bin_atoms(); // loop over each atom, storing neighbors double **x = atom->x; double *radius = atom->radius; int *type = atom->type; int *mask = atom->mask; int *molecule = atom->molecule; int nlocal = atom->nlocal; 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; + MyPage *ipage = list->ipage; int inum = 0; - int npage = 0; - int npnt = 0; + ipage->reset(); for (i = 0; i < nlocal; i++) { - - if (pgsize - npnt < oneatom) { - npnt = 0; - npage++; - if (npage == list->maxpage) pages = list->add_pages(); - } - n = 0; - neighptr = &pages[npage][npnt]; + neighptr = ipage->vget(); xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; radi = radius[i]; // 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; } } if (exclude && exclusion(i,j,type[i],type[j],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; radsum = radi + radius[j]; cutsq = (radsum+skin) * (radsum+skin); if (rsq <= cutsq) 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]) { if (exclude && exclusion(i,j,type[i],type[j],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; radsum = radi + radius[j]; cutsq = (radsum+skin) * (radsum+skin); if (rsq <= cutsq) neighptr[n++] = j; } } ilist[inum++] = i; firstneigh[i] = neighptr; numneigh[i] = n; - npnt += n; - if (n > oneatom) + ipage->vgot(n); + if (ipage->status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } list->inum = inum; } /* ---------------------------------------------------------------------- granular particles binned neighbor list construction with Newton's 3rd law for triclinic no shear history is allowed for this option each owned atom i checks its own bin and other bins in triclinic stencil every pair stored exactly once by some processor ------------------------------------------------------------------------- */ void Neighbor::granular_bin_newton_tri(NeighList *list) { int i,j,k,n,ibin; double xtmp,ytmp,ztmp,delx,dely,delz,rsq; double radi,radsum,cutsq; int *neighptr; // bin local & ghost atoms bin_atoms(); // loop over each atom, storing neighbors double **x = atom->x; double *radius = atom->radius; int *type = atom->type; int *mask = atom->mask; int *molecule = atom->molecule; int nlocal = atom->nlocal; 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; + MyPage *ipage = list->ipage; int inum = 0; - int npage = 0; - int npnt = 0; + ipage->reset(); for (i = 0; i < nlocal; i++) { - - if (pgsize - npnt < oneatom) { - npnt = 0; - npage++; - if (npage == list->maxpage) pages = list->add_pages(); - } - n = 0; - neighptr = &pages[npage][npnt]; + neighptr = ipage->vget(); xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; radi = radius[i]; // 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; } } if (exclude && exclusion(i,j,type[i],type[j],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; radsum = radi + radius[j]; cutsq = (radsum+skin) * (radsum+skin); if (rsq <= cutsq) neighptr[n++] = j; } } ilist[inum++] = i; firstneigh[i] = neighptr; numneigh[i] = n; - npnt += n; - if (n > oneatom) + ipage->vgot(n); + if (ipage->status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } list->inum = inum; } diff --git a/src/neigh_half_bin.cpp b/src/neigh_half_bin.cpp index 9d89274ab..ef55cb5ba 100644 --- a/src/neigh_half_bin.cpp +++ b/src/neigh_half_bin.cpp @@ -1,487 +1,456 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "neighbor.h" #include "neigh_list.h" #include "atom.h" #include "domain.h" +#include "my_page.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; 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; + MyPage *ipage = list->ipage; int inum = 0; - int npage = 0; - int npnt = 0; + ipage->reset(); 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; + neighptr = ipage->vget(); 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]); if (which == 0) neighptr[n++] = j; else if (domain->minimum_image_check(delx,dely,delz)) neighptr[n++] = j; else 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) + ipage->vgot(n); + if (ipage->status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } list->inum = inum; } /* ---------------------------------------------------------------------- binned neighbor list construction with partial Newton's 3rd law include neighbors of ghost atoms, but no "special neighbors" for ghosts owned and ghost atoms check own bin and other bins in stencil pair stored once if i,j are both owned and i < j pair stored by me if i owned and j ghost (also stored by proc owning j) pair stored once if i,j are both ghost and i < j ------------------------------------------------------------------------- */ void Neighbor::half_bin_no_newton_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 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; 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; + MyPage *ipage = list->ipage; int inum = 0; - int npage = 0; - int npnt = 0; + ipage->reset(); 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; + neighptr = ipage->vget(); 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 // when i is a ghost atom, must check if stencil bin is out of bounds // only store pair if i < j // stores own/own pairs only once // stores own/ghost pairs with owned atom only, on both procs // stores ghost/ghost pairs only once // no molecular test when i = ghost atom 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 (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]); if (which == 0) neighptr[n++] = j; else if (domain->minimum_image_check(delx,dely,delz)) neighptr[n++] = j; else 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 (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 <= cutneighghostsq[itype][jtype]) neighptr[n++] = j; } } } ilist[inum++] = i; firstneigh[i] = neighptr; numneigh[i] = n; - npnt += n; - if (n > oneatom) + ipage->vgot(n); + if (ipage->status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } list->inum = atom->nlocal; list->gnum = inum - atom->nlocal; } /* ---------------------------------------------------------------------- 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; 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; + MyPage *ipage = list->ipage; int inum = 0; - int npage = 0; - int npnt = 0; + ipage->reset(); 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; + neighptr = ipage->vget(); 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]); if (which == 0) neighptr[n++] = j; else if (domain->minimum_image_check(delx,dely,delz)) neighptr[n++] = j; else if (which > 0) neighptr[n++] = j ^ (which << SBBITS); // OLD: 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]); if (which == 0) neighptr[n++] = j; else if (domain->minimum_image_check(delx,dely,delz)) neighptr[n++] = j; else if (which > 0) neighptr[n++] = j ^ (which << SBBITS); // OLD: 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) + ipage->vgot(n); + if (ipage->status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } 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; 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; + MyPage *ipage = list->ipage; int inum = 0; - int npage = 0; - int npnt = 0; + ipage->reset(); 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; + neighptr = ipage->vget(); 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]); if (which == 0) neighptr[n++] = j; else if (domain->minimum_image_check(delx,dely,delz)) neighptr[n++] = j; else 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) + ipage->vgot(n); + if (ipage->status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } list->inum = inum; } diff --git a/src/neigh_half_multi.cpp b/src/neigh_half_multi.cpp index bee0bfffc..46a76be6d 100644 --- a/src/neigh_half_multi.cpp +++ b/src/neigh_half_multi.cpp @@ -1,379 +1,356 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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 "domain.h" +#include "my_page.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 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; + MyPage *ipage = list->ipage; int inum = 0; - int npage = 0; - int npnt = 0; + ipage->reset(); 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; + neighptr = ipage->vget(); 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]); if (which == 0) neighptr[n++] = j; else if (domain->minimum_image_check(delx,dely,delz)) neighptr[n++] = j; else 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) + ipage->vgot(n); + if (ipage->status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } 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 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; + MyPage *ipage = list->ipage; int inum = 0; - int npage = 0; - int npnt = 0; + ipage->reset(); 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; + neighptr = ipage->vget(); 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]); if (which == 0) neighptr[n++] = j; else if (domain->minimum_image_check(delx,dely,delz)) neighptr[n++] = j; else 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]); if (which == 0) neighptr[n++] = j; else if (domain->minimum_image_check(delx,dely,delz)) neighptr[n++] = j; else 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) + ipage->vgot(n); + if (ipage->status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } 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 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; + MyPage *ipage = list->ipage; int inum = 0; - int npage = 0; - int npnt = 0; + ipage->reset(); 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; + neighptr = ipage->vget(); 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]); if (which == 0) neighptr[n++] = j; else if (domain->minimum_image_check(delx,dely,delz)) neighptr[n++] = j; else 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) + ipage->vgot(n); + if (ipage->status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } list->inum = inum; } diff --git a/src/neigh_half_nsq.cpp b/src/neigh_half_nsq.cpp index 7266df0eb..8446c9d98 100644 --- a/src/neigh_half_nsq.cpp +++ b/src/neigh_half_nsq.cpp @@ -1,331 +1,307 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "neighbor.h" #include "neigh_list.h" #include "atom.h" #include "domain.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; 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; + MyPage *ipage = list->ipage; int inum = 0; - int npage = 0; - int npnt = 0; + ipage->reset(); // 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; + neighptr = ipage->vget(); itype = type[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; // loop over remaining atoms, owned and ghost // only store pair if i < j 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]); if (which == 0) neighptr[n++] = j; else if (domain->minimum_image_check(delx,dely,delz)) neighptr[n++] = j; else 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) + ipage->vgot(n); + if (ipage->status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } list->inum = inum; } /* ---------------------------------------------------------------------- N^2 / 2 search for neighbor pairs with partial Newton's 3rd law include neighbors of ghost atoms, but no "special neighbors" for ghosts pair stored once if i,j are both owned and i < j pair stored by me if i owned and j ghost (also stored by proc owning j) pair stored once if i,j are both ghost and i < j ------------------------------------------------------------------------- */ void Neighbor::half_nsq_no_newton_ghost(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; + MyPage *ipage = list->ipage; int inum = 0; - int npage = 0; - int npnt = 0; + ipage->reset(); // 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; + neighptr = ipage->vget(); itype = type[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; // loop over remaining atoms, owned and ghost // only store pair if i < j // stores own/own pairs only once // stores own/ghost pairs with owned atom only, on both procs // stores ghost/ghost pairs only once // no molecular test when i = ghost atom if (i < nlocal) { 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]); if (which == 0) neighptr[n++] = j; else if (domain->minimum_image_check(delx,dely,delz)) neighptr[n++] = j; else if (which > 0) neighptr[n++] = j ^ (which << SBBITS); } else neighptr[n++] = j; } } } else { 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]) neighptr[n++] = j; } } ilist[inum++] = i; firstneigh[i] = neighptr; numneigh[i] = n; - npnt += n; - if (n > oneatom) + ipage->vgot(n); + if (ipage->status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } list->inum = atom->nlocal; list->gnum = inum - atom->nlocal; } /* ---------------------------------------------------------------------- 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; + MyPage *ipage = list->ipage; int inum = 0; - int npage = 0; - int npnt = 0; + ipage->reset(); 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; + neighptr = ipage->vget(); 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]); if (which == 0) neighptr[n++] = j; else if (domain->minimum_image_check(delx,dely,delz)) neighptr[n++] = j; else 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) + ipage->vgot(n); + if (ipage->status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } list->inum = inum; } diff --git a/src/neigh_list.cpp b/src/neigh_list.cpp index 316b39ed7..aac201b01 100644 --- a/src/neigh_list.cpp +++ b/src/neigh_list.cpp @@ -1,291 +1,288 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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 "neigh_list.h" #include "atom.h" #include "comm.h" #include "update.h" #include "neighbor.h" #include "neigh_request.h" +#include "my_page.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define PGDELTA 1 enum{NSQ,BIN,MULTI}; // also in neighbor.cpp /* ---------------------------------------------------------------------- */ -NeighList::NeighList(LAMMPS *lmp, int size, int onesize) : Pointers(lmp) +NeighList::NeighList(LAMMPS *lmp) : + Pointers(lmp) { maxatoms = 0; - pgsize = size; - oneatom = onesize; inum = gnum = 0; ilist = NULL; numneigh = NULL; firstneigh = NULL; firstdouble = NULL; - maxpage = 0; - pages = NULL; - dpages = NULL; - dnum = 0; - iskip = NULL; ijskip = NULL; listgranhistory = NULL; fix_history = NULL; respamiddle = 0; listinner = NULL; listmiddle = NULL; listfull = NULL; listcopy = NULL; listskip = NULL; maxstencil = 0; stencil = NULL; stencilxyz = NULL; maxstencil_multi = 0; nstencil_multi = NULL; stencil_multi = NULL; distsq_multi = NULL; + + ipage = NULL; + dpage = NULL; } /* ---------------------------------------------------------------------- */ NeighList::~NeighList() { if (!listcopy) { memory->destroy(ilist); memory->destroy(numneigh); memory->sfree(firstneigh); memory->sfree(firstdouble); - for (int i = 0; i < maxpage; i++) memory->destroy(pages[i]); - memory->sfree(pages); - if (dnum) { - for (int i = 0; i < maxpage; i++) memory->destroy(dpages[i]); - memory->sfree(dpages); - } + delete [] ipage; + if (dnum) delete [] dpage; } delete [] iskip; memory->destroy(ijskip); if (maxstencil) memory->destroy(stencil); if (ghostflag) memory->destroy(stencilxyz); if (maxstencil_multi) { for (int i = 1; i <= atom->ntypes; i++) { memory->destroy(stencil_multi[i]); memory->destroy(distsq_multi[i]); } delete [] nstencil_multi; delete [] stencil_multi; delete [] distsq_multi; } } +/* ---------------------------------------------------------------------- */ + +void NeighList::setup_pages(int pgsize_caller, int oneatom_caller, + int dnum_caller) +{ + pgsize = pgsize_caller; + oneatom = oneatom_caller; + dnum = dnum_caller; + + int nmypage = comm->nthreads; + ipage = new MyPage[nmypage]; + for (int i = 0; i < nmypage; i++) + ipage[i].init(oneatom,pgsize,PGDELTA); + + if (dnum) { + dpage = new MyPage[nmypage]; + for (int i = 0; i < nmypage; i++) + dpage[i].init(dnum*oneatom,dnum*pgsize,PGDELTA); + } + else dpage = NULL; +} + /* ---------------------------------------------------------------------- grow atom arrays to allow for nmax atoms triggered by more atoms on a processor caller knows if this list stores neighs of local atoms or local+ghost ------------------------------------------------------------------------- */ void NeighList::grow(int nmax) { // skip if this list is already long enough to store nmax atoms if (nmax <= maxatoms) return; maxatoms = nmax; memory->destroy(ilist); memory->destroy(numneigh); memory->sfree(firstneigh); memory->sfree(firstdouble); memory->create(ilist,maxatoms,"neighlist:ilist"); memory->create(numneigh,maxatoms,"neighlist:numneigh"); firstneigh = (int **) memory->smalloc(maxatoms*sizeof(int *), "neighlist:firstneigh"); if (dnum) firstdouble = (double **) memory->smalloc(maxatoms*sizeof(double *), "neighlist:firstdouble"); } /* ---------------------------------------------------------------------- insure stencils are large enough for smax bins style = BIN or MULTI ------------------------------------------------------------------------- */ void NeighList::stencil_allocate(int smax, int style) { int i; if (style == BIN) { if (smax > maxstencil) { maxstencil = smax; memory->destroy(stencil); memory->create(stencil,maxstencil,"neighlist:stencil"); if (ghostflag) { memory->destroy(stencilxyz); memory->create(stencilxyz,maxstencil,3,"neighlist:stencilxyz"); } } } else { int n = atom->ntypes; if (maxstencil_multi == 0) { nstencil_multi = new int[n+1]; stencil_multi = new int*[n+1]; distsq_multi = new double*[n+1]; for (i = 1; i <= n; i++) { nstencil_multi[i] = 0; stencil_multi[i] = NULL; distsq_multi[i] = NULL; } } if (smax > maxstencil_multi) { maxstencil_multi = smax; for (i = 1; i <= n; i++) { memory->destroy(stencil_multi[i]); memory->destroy(distsq_multi[i]); memory->create(stencil_multi[i],maxstencil_multi, "neighlist:stencil_multi"); memory->create(distsq_multi[i],maxstencil_multi, "neighlist:distsq_multi"); } } } } -/* ---------------------------------------------------------------------- - add PGDELTA pages to neighbor list -------------------------------------------------------------------------- */ - -int **NeighList::add_pages(int howmany) -{ - int toppage = maxpage; - maxpage += howmany*PGDELTA; - - pages = (int **) - memory->srealloc(pages,maxpage*sizeof(int *),"neighlist:pages"); - for (int i = toppage; i < maxpage; i++) - memory->create(pages[i],pgsize,"neighlist:pages[i]"); - - if (dnum) { - dpages = (double **) - memory->srealloc(dpages,maxpage*sizeof(double *),"neighlist:dpages"); - for (int i = toppage; i < maxpage; i++) - memory->create(dpages[i],dnum*pgsize,"neighlist:dpages[i]"); - } - - return pages; -} - /* ---------------------------------------------------------------------- copy skip info from request rq into list's iskip,ijskip ------------------------------------------------------------------------- */ void NeighList::copy_skip_info(int *rq_iskip, int **rq_ijskip) { int ntypes = atom->ntypes; iskip = new int[ntypes+1]; memory->create(ijskip,ntypes+1,ntypes+1,"neigh_list:ijskip"); int i,j; for (i = 1; i <= ntypes; i++) iskip[i] = rq_iskip[i]; for (i = 1; i <= ntypes; i++) for (j = 1; j <= ntypes; j++) ijskip[i][j] = rq_ijskip[i][j]; } /* ---------------------------------------------------------------------- print attributes of this list and associated request ------------------------------------------------------------------------- */ void NeighList::print_attributes() { if (comm->me != 0) return; NeighRequest *rq = neighbor->requests[index]; printf("Neighbor list/request %d:\n",index); printf(" %d = build flag\n",buildflag); printf(" %d = grow flag\n",growflag); printf(" %d = stencil flag\n",stencilflag); printf(" %d = ghost flag\n",ghostflag); printf("\n"); printf(" %d = pair\n",rq->pair); printf(" %d = fix\n",rq->fix); printf(" %d = compute\n",rq->compute); printf(" %d = command\n",rq->command); printf("\n"); printf(" %d = half\n",rq->half); printf(" %d = full\n",rq->full); printf(" %d = gran\n",rq->gran); printf(" %d = granhistory\n",rq->granhistory); printf(" %d = respainner\n",rq->respainner); printf(" %d = respamiddle\n",rq->respamiddle); printf(" %d = respaouter\n",rq->respaouter); printf(" %d = half_from_full\n",rq->half_from_full); printf("\n"); printf(" %d = occasional\n",rq->occasional); printf(" %d = dnum\n",rq->dnum); printf(" %d = omp\n",rq->omp); printf(" %d = ghost\n",rq->ghost); printf(" %d = cudable\n",rq->cudable); printf(" %d = omp\n",rq->omp); printf(" %d = copy\n",rq->copy); printf(" %d = skip\n",rq->skip); printf(" %d = otherlist\n",rq->otherlist); printf(" %p = listskip\n",listskip); printf("\n"); } /* ---------------------------------------------------------------------- return # of bytes of allocated memory if growflag = 0, maxatoms & maxpage will also be 0 if stencilflag = 0, maxstencil * maxstencil_multi will also be 0 ------------------------------------------------------------------------- */ bigint NeighList::memory_usage() { bigint bytes = 0; bytes += memory->usage(ilist,maxatoms); bytes += memory->usage(numneigh,maxatoms); bytes += maxatoms * sizeof(int *); - bytes += memory->usage(pages,maxpage,pgsize); + int nmypage = comm->nthreads; + for (int i = 0; i < nmypage; i++) + bytes += ipage[i].size(); + if (dnum) { - bytes += maxatoms * sizeof(double *); - bytes += memory->usage(dpages,maxpage,dnum*pgsize); + for (int i = 0; i < nmypage; i++) { + bytes += maxatoms * sizeof(double *); + bytes += dpage[i].size(); + } } if (maxstencil) bytes += memory->usage(stencil,maxstencil); if (ghostflag) bytes += memory->usage(stencilxyz,maxstencil,3); if (maxstencil_multi) { bytes += memory->usage(stencil_multi,atom->ntypes,maxstencil_multi); bytes += memory->usage(distsq_multi,atom->ntypes,maxstencil_multi); } return bytes; } diff --git a/src/neigh_list.h b/src/neigh_list.h index d29f3a7db..b5b277c21 100644 --- a/src/neigh_list.h +++ b/src/neigh_list.h @@ -1,99 +1,96 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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_NEIGH_LIST_H #define LMP_NEIGH_LIST_H #include "pointers.h" #include "my_page.h" namespace LAMMPS_NS { class NeighList : protected Pointers { public: int index; // index of which neigh list it is // needed when a class invokes it directly // also indexes the request it came from int buildflag; // 1 if pair_build invoked every reneigh int growflag; // 1 if stores atom-based arrays & pages int stencilflag; // 1 if stores stencil arrays int ghostflag; // 1 if it stores neighbors of ghosts // data structs to store neighbor pairs I,J and associated values int inum; // # of I atoms neighbors are stored for int gnum; // # of ghost atoms neighbors are stored for int *ilist; // local indices of I atoms int *numneigh; // # of J neighbors for each I atom int **firstneigh; // ptr to 1st J int value of each I atom double **firstdouble; // ptr to 1st J double value of each I atom int pgsize; // size of each page int oneatom; // max size for one atom - int maxpage; // # of pages currently allocated - int **pages; // neighbor list pages for ints - double **dpages; // neighbor list pages for doubles - int dnum; // # of doubles for each pair (0 if none) - - MyPage *page; + int dnum; // # of doubles per neighbor, 0 if none + MyPage *ipage; // pages of neighbor indices + MyPage *dpage; // pages of neighbor doubles, if dnum > 0 // atom types to skip when building list // iskip,ijskip are just ptrs to corresponding request int *iskip; // iskip[i] = 1 if atoms of type I are not in list int **ijskip; // ijskip[i][j] = 1 if pairs of type I,J are not in list // settings and pointers for related neighbor lists and fixes NeighList *listgranhistory; // point at history list class FixShearHistory *fix_history; // fix that stores history info int respamiddle; // 1 if this respaouter has middle list NeighList *listinner; // me = respaouter, point to respainner NeighList *listmiddle; // me = respaouter, point to respamiddle NeighList *listfull; // me = half list, point to full I derive from NeighList *listcopy; // me = copy list, point to list I copy from NeighList *listskip; // me = skip list, point to list I skip from // stencils of bin indices for neighbor finding int maxstencil; // max size of stencil int nstencil; // # of bins in stencil int *stencil; // list of bin offsets int **stencilxyz; // bin offsets in xyz dims int maxstencil_multi; // max sizes of stencils int *nstencil_multi; // # bins in each type-based multi stencil int **stencil_multi; // list of bin offsets in each stencil double **distsq_multi; // sq distances to bins in each stencil class CudaNeighList *cuda_list; // CUDA neighbor list - NeighList(class LAMMPS *, int, int); + NeighList(class LAMMPS *); ~NeighList(); + void setup_pages(int, int, int); // setup page data structures void grow(int); // grow maxlocal void stencil_allocate(int, int); // allocate stencil arrays - int **add_pages(int howmany=1); // add pages to neigh list void copy_skip_info(int *, int **); // copy skip info from a neigh request void print_attributes(); // debug routine int get_maxlocal() {return maxatoms;} bigint memory_usage(); private: int maxatoms; // size of allocated atom arrays }; } #endif diff --git a/src/neigh_respa.cpp b/src/neigh_respa.cpp index c152eba2b..8d1ea14ae 100644 --- a/src/neigh_respa.cpp +++ b/src/neigh_respa.cpp @@ -1,953 +1,834 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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 "domain.h" #include "group.h" +#include "my_page.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,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; + MyPage *ipage = list->ipage; NeighList *listinner = list->listinner; int *ilist_inner = listinner->ilist; int *numneigh_inner = listinner->numneigh; int **firstneigh_inner = listinner->firstneigh; - int **pages_inner = listinner->pages; + MyPage *ipage_inner = listinner->ipage; NeighList *listmiddle; - int *ilist_middle,*numneigh_middle,**firstneigh_middle,**pages_middle; + int *ilist_middle,*numneigh_middle,**firstneigh_middle; + MyPage *ipage_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; + ipage_middle = listmiddle->ipage; } 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; - int which = 0; int minchange = 0; + ipage->reset(); + ipage_inner->reset(); + if (respamiddle) ipage_middle->reset(); 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; - + n = n_inner = 0; + neighptr = ipage->vget(); + neighptr_inner = ipage_inner->vget(); 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; + neighptr_middle = ipage_middle->vget(); } 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]); if (which == 0) neighptr[n++] = j; else if (minchange = domain->minimum_image_check(delx,dely,delz)) neighptr[n++] = j; else 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 (minchange) neighptr_inner[n_inner++] = 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 (minchange) neighptr_middle[n_middle++] = 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) + ipage->vgot(n); + if (ipage->status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); ilist_inner[inum] = i; firstneigh_inner[i] = neighptr_inner; numneigh_inner[i] = n_inner; - npnt_inner += n_inner; - if (n_inner > oneatom) + ipage_inner->vgot(n_inner); + if (ipage_inner->status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); if (respamiddle) { ilist_middle[inum] = i; firstneigh_middle[i] = neighptr_middle; numneigh_middle[i] = n_middle; - npnt_middle += n_middle; - if (n_middle > oneatom) + ipage_middle->vgot(n_middle); + if (ipage_middle->status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } 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,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; + MyPage *ipage = list->ipage; NeighList *listinner = list->listinner; int *ilist_inner = listinner->ilist; int *numneigh_inner = listinner->numneigh; int **firstneigh_inner = listinner->firstneigh; - int **pages_inner = listinner->pages; + MyPage *ipage_inner = listinner->ipage; NeighList *listmiddle; - int *ilist_middle,*numneigh_middle,**firstneigh_middle,**pages_middle; + int *ilist_middle,*numneigh_middle,**firstneigh_middle; + MyPage *ipage_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; + ipage_middle = listmiddle->ipage; } 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; - int which = 0; int minchange = 0; + ipage->reset(); + ipage_inner->reset(); + if (respamiddle) ipage_middle->reset(); 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; - + n = n_inner = 0; + neighptr = ipage->vget(); + neighptr_inner = ipage_inner->vget(); 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; + neighptr_middle = ipage_middle->vget(); } 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]); if (which == 0) neighptr[n++] = j; else if (minchange = domain->minimum_image_check(delx,dely,delz)) neighptr[n++] = j; else 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 (minchange) neighptr_inner[n_inner++] = 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 (minchange) neighptr_middle[n_middle++] = 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) + ipage->vgot(n); + if (ipage->status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); ilist_inner[inum] = i; firstneigh_inner[i] = neighptr_inner; numneigh_inner[i] = n_inner; - npnt_inner += n_inner; - if (n_inner > oneatom) + ipage_inner->vgot(n_inner); + if (ipage_inner->status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); if (respamiddle) { ilist_middle[inum] = i; firstneigh_middle[i] = neighptr_middle; numneigh_middle[i] = n_middle; - npnt_middle += n_middle; - if (n_middle > oneatom) + ipage_middle->vgot(n_middle); + if (ipage_middle->status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } 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,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 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; + MyPage *ipage = list->ipage; NeighList *listinner = list->listinner; int *ilist_inner = listinner->ilist; int *numneigh_inner = listinner->numneigh; int **firstneigh_inner = listinner->firstneigh; - int **pages_inner = listinner->pages; + MyPage *ipage_inner = listinner->ipage; NeighList *listmiddle; - int *ilist_middle,*numneigh_middle,**firstneigh_middle,**pages_middle; + int *ilist_middle,*numneigh_middle,**firstneigh_middle; + MyPage *ipage_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; + ipage_middle = listmiddle->ipage; } 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; - int which = 0; int minchange = 0; + ipage->reset(); + ipage_inner->reset(); + if (respamiddle) ipage_middle->reset(); 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; - + n = n_inner = 0; + neighptr = ipage->vget(); + neighptr_inner = ipage_inner->vget(); 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; + neighptr_middle = ipage_middle->vget(); } 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]); if (which == 0) neighptr[n++] = j; else if (minchange = domain->minimum_image_check(delx,dely,delz)) neighptr[n++] = j; else 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 (minchange) neighptr_inner[n_inner++] = 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 (minchange) neighptr_middle[n_middle++] = 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) + ipage->vgot(n); + if (ipage->status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); ilist_inner[inum] = i; firstneigh_inner[i] = neighptr_inner; numneigh_inner[i] = n_inner; - npnt_inner += n_inner; - if (n_inner > oneatom) + ipage_inner->vgot(n_inner); + if (ipage_inner->status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); if (respamiddle) { ilist_middle[inum] = i; firstneigh_middle[i] = neighptr_middle; numneigh_middle[i] = n_middle; - npnt_middle += n_middle; - if (n_middle > oneatom) + ipage_middle->vgot(n_middle); + if (ipage_middle->status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } 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,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 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; + MyPage *ipage = list->ipage; NeighList *listinner = list->listinner; int *ilist_inner = listinner->ilist; int *numneigh_inner = listinner->numneigh; int **firstneigh_inner = listinner->firstneigh; - int **pages_inner = listinner->pages; + MyPage *ipage_inner = listinner->ipage; NeighList *listmiddle; - int *ilist_middle,*numneigh_middle,**firstneigh_middle,**pages_middle; + int *ilist_middle,*numneigh_middle,**firstneigh_middle; + MyPage *ipage_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; + ipage_middle = listmiddle->ipage; } 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; - int which = 0; int minchange = 0; + ipage->reset(); + ipage_inner->reset(); + if (respamiddle) ipage_middle->reset(); 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; - + n = n_inner = 0; + neighptr = ipage->vget(); + neighptr_inner = ipage_inner->vget(); 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; + neighptr_middle = ipage_middle->vget(); } 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]); if (which == 0) neighptr[n++] = j; else if (minchange = domain->minimum_image_check(delx,dely,delz)) neighptr[n++] = j; else 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 (minchange) neighptr_inner[n_inner++] = 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 (minchange) neighptr_middle[n_middle++] = 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]); if (which == 0) neighptr[n++] = j; else if (minchange = domain->minimum_image_check(delx,dely,delz)) neighptr[n++] = j; else 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 (minchange) neighptr_inner[n_inner++] = 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 (minchange) neighptr_middle[n_middle++] = 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) + ipage->vgot(n); + if (ipage->status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); ilist_inner[inum] = i; firstneigh_inner[i] = neighptr_inner; numneigh_inner[i] = n_inner; - npnt_inner += n_inner; - if (n_inner > oneatom) + ipage_inner->vgot(n_inner); + if (ipage_inner->status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); if (respamiddle) { ilist_middle[inum] = i; firstneigh_middle[i] = neighptr_middle; numneigh_middle[i] = n_middle; - npnt_middle += n_middle; - if (n_middle > oneatom) + ipage_middle->vgot(n_middle); + if (ipage_middle->status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } 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,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 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; + MyPage *ipage = list->ipage; NeighList *listinner = list->listinner; int *ilist_inner = listinner->ilist; int *numneigh_inner = listinner->numneigh; int **firstneigh_inner = listinner->firstneigh; - int **pages_inner = listinner->pages; + MyPage *ipage_inner = listinner->ipage; NeighList *listmiddle; - int *ilist_middle,*numneigh_middle,**firstneigh_middle,**pages_middle; + int *ilist_middle,*numneigh_middle,**firstneigh_middle; + MyPage *ipage_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; + ipage_middle = listmiddle->ipage; } 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; - int which = 0; int minchange = 0; + ipage->reset(); + ipage_inner->reset(); + if (respamiddle) ipage_middle->reset(); 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; - + n = n_inner = 0; + neighptr = ipage->vget(); + neighptr_inner = ipage_inner->vget(); 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; + neighptr_middle = ipage_middle->vget(); } 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]); if (which == 0) neighptr[n++] = j; else if (minchange = domain->minimum_image_check(delx,dely,delz)) neighptr[n++] = j; else 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 (minchange) neighptr_inner[n_inner++] = 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 (minchange) neighptr_middle[n_middle++] = 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) + ipage->vgot(n); + if (ipage->status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); ilist_inner[inum] = i; firstneigh_inner[i] = neighptr_inner; numneigh_inner[i] = n_inner; - npnt_inner += n_inner; - if (n_inner > oneatom) + ipage_inner->vgot(n_inner); + if (ipage_inner->status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); if (respamiddle) { ilist_middle[inum] = i; firstneigh_middle[i] = neighptr_middle; numneigh_middle[i] = n_middle; - npnt_middle += n_middle; - if (n_middle > oneatom) + ipage_middle->vgot(n_middle); + if (ipage_middle->status()) error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); } inum++; } list->inum = inum; listinner->inum = inum; if (respamiddle) listmiddle->inum = inum; } diff --git a/src/neighbor.cpp b/src/neighbor.cpp index 0f597b64d..b9ecb4c47 100644 --- a/src/neighbor.cpp +++ b/src/neighbor.cpp @@ -1,1949 +1,1946 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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 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; cluster_check = 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_pgsize = pgsize; old_oneatom = oneatom; 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(FLERR,"Neighbor delay must be 0 or multiple of every setting"); if (pgsize < 10*oneatom) error->all(FLERR,"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_flag) 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 && strstr(update->integrate_style,"respa")) { 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 // warn if exclusions used with KSpace solver 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(FLERR,"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]]; } if (exclude && force->kspace && me == 0) error->warning(FLERR,"Neighbor exclusions used with KSpace solver " "may give inconsistent Coulombic energies"); // ------------------------------------------------------------------ // pairwise lists // test if pairwise lists need to be re-created // no need to re-create if: // neigh style, triclinic, pgsize, oneatom have not changed // current requests = old requests int same = 1; if (style != old_style) same = 0; if (triclinic != old_triclinic) same = 0; if (pgsize != old_pgsize) same = 0; if (oneatom != old_oneatom) 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,oneatom); + lists[i] = new NeighList(lmp); + lists[i]->setup_pages(pgsize,oneatom,requests[i]->dnum); 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 and processed flag is important // since don't want to re-process skip or copy lists further down // skip list needs to have granhistory or respa info added // copy: point this list at request->otherlist, could be a skip list // skip: point this list at request->otherlist, copy skip info from request // also set granular and respa info if applicable // 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: // whether request is occasional or not doesn't matter // if request = half and non-skip pair half/respaouter exists, // become copy of that list if cudable flag matches // if request = full and non-skip pair full exists, // become copy of that list if cudable flag matches // if request = half and non-skip pair full exists, // become half_from_full of that list if cudable flag matches // if no matches, do nothing, fix/compute list will be built directly // ok if parent is copy list int processed; for (i = 0; i < nlist; i++) { processed = 0; if (requests[i]->copy) { lists[i]->listcopy = lists[requests[i]->otherlist]; processed = 1; } else if (requests[i]->skip) { lists[i]->listskip = lists[requests[i]->otherlist]; lists[i]->copy_skip_info(requests[i]->iskip,requests[i]->ijskip); processed = 1; } else if (requests[i]->half_from_full) { lists[i]->listfull = lists[i-1]; processed = 1; } 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]; processed = 1; } 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]; } processed = 1; } if (processed) continue; 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]->gran && requests[j]->pair && requests[j]->skip == 0 && requests[j]->gran) break; if (requests[i]->half && requests[j]->pair && requests[j]->skip == 0 && requests[j]->respaouter) break; } if (j < nlist && requests[j]->cudable != requests[i]->cudable) j = nlist; if (j < nlist) { requests[i]->copy = 1; requests[i]->otherlist = j; 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[j]->cudable != requests[i]->cudable) j = nlist; 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 // also set cudable to 0 if any neigh list request is not cudable for (i = 0; i < nlist; i++) { choose_build(i,requests[i]); if (style != NSQ) choose_stencil(i,requests[i]); else stencil_create[i] = NULL; if (!requests[i]->cudable) cudable = 0; } // 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 + // allocate atom arrays for neighbor 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(); - } + if (lists[i]->growflag) lists[i]->grow(maxatom); // 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->omp == 0) { 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) { if (rq->ghost == 0) pb = &Neighbor::half_nsq_no_newton; else if (includegroup) error->all(FLERR,"Neighbor include group not allowed " "with ghost neighbors"); else pb = &Neighbor::half_nsq_no_newton_ghost; } 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) { if (rq->ghost == 0) pb = &Neighbor::half_nsq_no_newton; else if (includegroup) error->all(FLERR,"Neighbor include group not allowed " "with ghost neighbors"); else pb = &Neighbor::half_nsq_no_newton_ghost; } } else if (style == BIN) { if (rq->newton == 0) { if (newton_pair == 0) { if (rq->ghost == 0) pb = &Neighbor::half_bin_no_newton; else if (includegroup) error->all(FLERR,"Neighbor include group not allowed " "with ghost neighbors"); else pb = &Neighbor::half_bin_no_newton_ghost; } 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) { if (rq->ghost == 0) pb = &Neighbor::half_bin_no_newton; else if (includegroup) error->all(FLERR,"Neighbor include group not allowed " "with ghost neighbors"); else pb = &Neighbor::half_bin_no_newton_ghost; } } else if (style == MULTI) { if (rq->ghost == 1) error->all(FLERR, "Neighbor multi not yet enabled for ghost neighbors"); 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(FLERR, "Neighbor include group not allowed with ghost neighbors"); else pb = &Neighbor::full_nsq_ghost; } else if (style == BIN) { if (rq->ghost == 0) pb = &Neighbor::full_bin; else if (includegroup) error->all(FLERR, "Neighbor include group not allowed with ghost neighbors"); else pb = &Neighbor::full_bin_ghost; } else if (style == MULTI) { if (rq->ghost == 1) error->all(FLERR, "Neighbor multi not yet enabled for ghost neighbors"); pb = &Neighbor::full_multi; } } 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(FLERR,"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(FLERR,"Neighbor multi not yet enabled for rRESPA"); } // OMP versions of build methods } else { 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_omp; else if (newton_pair == 1) pb = &Neighbor::half_from_full_newton_omp; } else if (rq->half) { if (style == NSQ) { if (rq->newton == 0) { if (newton_pair == 0) { if (rq->ghost == 0) pb = &Neighbor::half_nsq_no_newton_omp; else if (includegroup) error->all(FLERR,"Neighbor include group not allowed " "with ghost neighbors"); else pb = &Neighbor::half_nsq_no_newton_ghost_omp; } else if (newton_pair == 1) pb = &Neighbor::half_nsq_newton_omp; } else if (rq->newton == 1) { pb = &Neighbor::half_nsq_newton_omp; } else if (rq->newton == 2) { if (rq->ghost == 0) pb = &Neighbor::half_nsq_no_newton_omp; else if (includegroup) error->all(FLERR,"Neighbor include group not allowed " "with ghost neighbors"); else pb = &Neighbor::half_nsq_no_newton_ghost_omp; } } else if (style == BIN) { if (rq->newton == 0) { if (newton_pair == 0) { if (rq->ghost == 0) pb = &Neighbor::half_bin_no_newton_omp; else if (includegroup) error->all(FLERR,"Neighbor include group not allowed " "with ghost neighbors"); else pb = &Neighbor::half_bin_no_newton_ghost_omp; } else if (triclinic == 0) { pb = &Neighbor::half_bin_newton_omp; } else if (triclinic == 1) pb = &Neighbor::half_bin_newton_tri_omp; } else if (rq->newton == 1) { if (triclinic == 0) pb = &Neighbor::half_bin_newton_omp; else if (triclinic == 1) pb = &Neighbor::half_bin_newton_tri_omp; } else if (rq->newton == 2) { if (rq->ghost == 0) pb = &Neighbor::half_bin_no_newton_omp; else if (includegroup) error->all(FLERR,"Neighbor include group not allowed " "with ghost neighbors"); else pb = &Neighbor::half_bin_no_newton_ghost_omp; } } else if (style == MULTI) { if (rq->ghost == 1) error->all(FLERR, "Neighbor multi not yet enabled for ghost neighbors"); if (rq->newton == 0) { if (newton_pair == 0) pb = &Neighbor::half_multi_no_newton_omp; else if (triclinic == 0) pb = &Neighbor::half_multi_newton_omp; else if (triclinic == 1) pb = &Neighbor::half_multi_newton_tri_omp; } else if (rq->newton == 1) { if (triclinic == 0) pb = &Neighbor::half_multi_newton_omp; else if (triclinic == 1) pb = &Neighbor::half_multi_newton_tri_omp; } else if (rq->newton == 2) pb = &Neighbor::half_multi_no_newton_omp; } } else if (rq->full) { if (style == NSQ) { if (rq->ghost == 0) pb = &Neighbor::full_nsq_omp; else if (includegroup) error->all(FLERR, "Neighbor include group not allowed with ghost neighbors"); else pb = &Neighbor::full_nsq_ghost_omp; } else if (style == BIN) { if (rq->ghost == 0) pb = &Neighbor::full_bin_omp; else if (includegroup) error->all(FLERR, "Neighbor include group not allowed with ghost neighbors"); else pb = &Neighbor::full_bin_ghost_omp; } else if (style == MULTI) { if (rq->ghost == 1) error->all(FLERR, "Neighbor multi not yet enabled for ghost neighbors"); pb = &Neighbor::full_multi_omp; } } else if (rq->gran) { if (style == NSQ) { if (newton_pair == 0) pb = &Neighbor::granular_nsq_no_newton_omp; else if (newton_pair == 1) pb = &Neighbor::granular_nsq_newton_omp; } else if (style == BIN) { if (newton_pair == 0) pb = &Neighbor::granular_bin_no_newton_omp; else if (triclinic == 0) pb = &Neighbor::granular_bin_newton_omp; else if (triclinic == 1) pb = &Neighbor::granular_bin_newton_tri_omp; } else if (style == MULTI) error->all(FLERR,"Neighbor multi not yet enabled for granular"); } else if (rq->respaouter) { if (style == NSQ) { if (newton_pair == 0) pb = &Neighbor::respa_nsq_no_newton_omp; else if (newton_pair == 1) pb = &Neighbor::respa_nsq_newton_omp; } else if (style == BIN) { if (newton_pair == 0) pb = &Neighbor::respa_bin_no_newton_omp; else if (triclinic == 0) pb = &Neighbor::respa_bin_newton_omp; else if (triclinic == 1) pb = &Neighbor::respa_bin_newton_tri_omp; } else if (style == MULTI) error->all(FLERR,"Neighbor multi not yet enabled for rRESPA"); } } 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) { if (rq->ghost) sc = &Neighbor::stencil_half_ghost_bin_2d_no_newton; else sc = &Neighbor::stencil_half_bin_2d_no_newton; } else if (dimension == 3) { if (rq->ghost) sc = &Neighbor::stencil_half_ghost_bin_3d_no_newton; else 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) if (rq->ghost) sc = &Neighbor::stencil_half_ghost_bin_2d_no_newton; else sc = &Neighbor::stencil_half_bin_2d_no_newton; else if (dimension == 3) { if (rq->ghost) sc = &Neighbor::stencil_half_ghost_bin_3d_no_newton; else 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 topology lists only built if topoflag = 1 ------------------------------------------------------------------------- */ void Neighbor::build(int topoflag) { int i; ago = 0; ncalls++; lastcall = update->ntimestep; // 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 neighbor list with special bond flags will not overflow if (atom->nlocal+atom->nghost > NEIGHMASK) error->one(FLERR,"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 && topoflag) build_topology(); } /* ---------------------------------------------------------------------- build all topology neighbor lists every few timesteps normally built with pair lists, but USER-CUDA separates them ------------------------------------------------------------------------- */ void Neighbor::build_topology() { 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(FLERR,"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(FLERR,"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(FLERR,"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(FLERR,"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 = ((bigint) mbinx) * ((bigint) mbiny) * ((bigint) mbinz); if (bbin > MAXSMALLINT) error->one(FLERR,"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(FLERR,"Illegal neighbor command"); skin = force->numeric(FLERR,arg[0]); if (skin < 0.0) error->all(FLERR,"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(FLERR,"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(FLERR,"Illegal neigh_modify command"); every = force->inumeric(FLERR,arg[iarg+1]); if (every <= 0) error->all(FLERR,"Illegal neigh_modify command"); iarg += 2; } else if (strcmp(arg[iarg],"delay") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal neigh_modify command"); delay = force->inumeric(FLERR,arg[iarg+1]); if (delay < 0) error->all(FLERR,"Illegal neigh_modify command"); iarg += 2; } else if (strcmp(arg[iarg],"check") == 0) { if (iarg+2 > narg) error->all(FLERR,"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(FLERR,"Illegal neigh_modify command"); iarg += 2; } else if (strcmp(arg[iarg],"once") == 0) { if (iarg+2 > narg) error->all(FLERR,"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(FLERR,"Illegal neigh_modify command"); iarg += 2; } else if (strcmp(arg[iarg],"page") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal neigh_modify command"); old_pgsize = pgsize; pgsize = force->inumeric(FLERR,arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"one") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal neigh_modify command"); old_oneatom = oneatom; oneatom = force->inumeric(FLERR,arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"binsize") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal neigh_modify command"); binsize_user = force->numeric(FLERR,arg[iarg+1]); if (binsize_user <= 0.0) binsizeflag = 0; else binsizeflag = 1; iarg += 2; } else if (strcmp(arg[iarg],"cluster") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal neigh_modify command"); if (strcmp(arg[iarg+1],"yes") == 0) cluster_check = 1; else if (strcmp(arg[iarg+1],"no") == 0) cluster_check = 0; else error->all(FLERR,"Illegal neigh_modify command"); iarg += 2; } else if (strcmp(arg[iarg],"include") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal neigh_modify command"); includegroup = group->find(arg[iarg+1]); if (includegroup < 0) error->all(FLERR,"Invalid group ID in neigh_modify command"); if (includegroup && (atom->firstgroupname == NULL || strcmp(arg[iarg+1],atom->firstgroupname) != 0)) error->all(FLERR, "Neigh_modify include group != atom_modify first group"); iarg += 2; } else if (strcmp(arg[iarg],"exclude") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal neigh_modify command"); if (strcmp(arg[iarg+1],"type") == 0) { if (iarg+4 > narg) error->all(FLERR,"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] = force->inumeric(FLERR,arg[iarg+2]); ex2_type[nex_type] = force->inumeric(FLERR,arg[iarg+3]); nex_type++; iarg += 4; } else if (strcmp(arg[iarg+1],"group") == 0) { if (iarg+4 > narg) error->all(FLERR,"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(FLERR,"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(FLERR,"Illegal neigh_modify command"); if (atom->molecule_flag == 0) error->all(FLERR,"Neigh_modify exclude molecule " "requires atom attribute molecule"); 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(FLERR,"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(FLERR,"Illegal neigh_modify command"); } else error->all(FLERR,"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) const { 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; } /* ---------------------------------------------------------------------- return the value of exclude - used to check compatibility with GPU ------------------------------------------------------------------------- */ int Neighbor::exclude_setting() { return exclude; }