From 85e934681d298a2fa226562e9dedfb18365b9968 Mon Sep 17 00:00:00 2001 From: Dan Stefan Bolintineanu Date: Mon, 16 Apr 2018 12:38:14 -0600 Subject: [PATCH 01/44] Added DMT and JKR pair styles with rolling friction --- src/GRANULAR/pair_gran_dmt_rolling.cpp | 720 +++++++++++++++++++++ src/GRANULAR/pair_gran_dmt_rolling.h | 55 ++ src/GRANULAR/pair_gran_hertz_history.cpp | 2 +- src/GRANULAR/pair_gran_hooke_history.cpp | 5 +- src/GRANULAR/pair_gran_hooke_history.h | 4 +- src/GRANULAR/pair_gran_jkr_rolling.cpp | 763 +++++++++++++++++++++++ src/GRANULAR/pair_gran_jkr_rolling.h | 56 ++ 7 files changed, 1601 insertions(+), 4 deletions(-) create mode 100644 src/GRANULAR/pair_gran_dmt_rolling.cpp create mode 100644 src/GRANULAR/pair_gran_dmt_rolling.h create mode 100644 src/GRANULAR/pair_gran_jkr_rolling.cpp create mode 100644 src/GRANULAR/pair_gran_jkr_rolling.h diff --git a/src/GRANULAR/pair_gran_dmt_rolling.cpp b/src/GRANULAR/pair_gran_dmt_rolling.cpp new file mode 100644 index 0000000000..08299f85b5 --- /dev/null +++ b/src/GRANULAR/pair_gran_dmt_rolling.cpp @@ -0,0 +1,720 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. + ------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Contributing authors: Leo Silbert (SNL), Gary Grest (SNL) + ------------------------------------------------------------------------- */ + +#include +#include +#include +#include +#include "pair_gran_dmt_rolling.h" +#include "atom.h" +#include "update.h" +#include "force.h" +#include "fix.h" +#include "fix_neigh_history.h" +#include "neighbor.h" +#include "neigh_list.h" +#include "comm.h" +#include "memory.h" +#include "error.h" +#include "math_const.h" + +using namespace LAMMPS_NS; +using namespace MathConst; + +#define TWOTHIRDS 0.6666666666666666 +#define EPSILON 1e-10 + +enum {TSUJI, BRILLIANTOV}; +enum {INDEP, BRILLROLL}; + +/* ---------------------------------------------------------------------- */ + +PairGranDMTRolling::PairGranDMTRolling(LAMMPS *lmp) : + PairGranHookeHistory(lmp, 7), + E_one(0), G_one(0), pois(0), muS_one(0), cor(0), alpha_one(0), + Ecoh_one(0), kR_one(0), muR_one(0), etaR_one(0) +{ + int ntypes = atom->ntypes; + memory->create(E,ntypes+1,ntypes+1,"pair:E"); + memory->create(G,ntypes+1,ntypes+1,"pair:G"); + memory->create(alpha,ntypes+1,ntypes+1,"pair:alpha"); + memory->create(gamman,ntypes+1,ntypes+1,"pair:gamman"); + memory->create(muS,ntypes+1,ntypes+1,"pair:muS"); + memory->create(Ecoh,ntypes+1,ntypes+1,"pair:Ecoh"); + memory->create(kR,ntypes+1,ntypes+1,"pair:kR"); + memory->create(muR,ntypes+1,ntypes+1,"pair:muR"); + memory->create(etaR,ntypes+1,ntypes+1,"pair:etaR"); +} + +/* ---------------------------------------------------------------------- */ +PairGranDMTRolling::~PairGranDMTRolling() +{ + delete [] E_one; + delete [] G_one; + delete [] pois; + delete [] muS_one; + delete [] cor; + delete [] alpha_one; + delete [] Ecoh_one; + delete [] kR_one; + delete [] muR_one; + delete [] etaR_one; + //TODO: Make all this work with standard pair coeff type commands. + //Also these should not be in the destructor. + memory->destroy(E); + memory->destroy(G); + memory->destroy(alpha); + memory->destroy(gamman); + memory->destroy(muS); + memory->destroy(Ecoh); + memory->destroy(kR); + memory->destroy(muR); + memory->destroy(etaR); +} +/* ---------------------------------------------------------------------- */ + +void PairGranDMTRolling::compute(int eflag, int vflag) +{ + int i,j,ii,jj,inum,jnum; + int itype,jtype; + double xtmp,ytmp,ztmp,delx,dely,delz,fx,fy,fz,nx,ny,nz; + double radi,radj,radsum,rsq,r,rinv,rsqinv,R,a; + double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3; + double wr1,wr2,wr3; + double vtr1,vtr2,vtr3,vrel; + double kn, kt, k_Q, k_R, eta_N, eta_T, eta_Q, eta_R; + double Fhz, Fdamp, Fdmt, Fne, Fntot, Fscrit, Frcrit; + double overlap; + double mi,mj,meff,damp,ccel,tor1,tor2,tor3; + double relrot1,relrot2,relrot3,vrl1,vrl2,vrl3,vrlmag,vrlmaginv; + double rollmag, rolldotn, scalefac; + double fr, fr1, fr2, fr3; + double signtwist, magtwist, magtortwist, Mtcrit; + double fs,fs1,fs2,fs3,roll1,roll2,roll3,torroll1,torroll2,torroll3; + double tortwist1, tortwist2, tortwist3; + double shrmag,rsht; + int *ilist,*jlist,*numneigh,**firstneigh; + int *touch,**firsttouch; + double *shear,*allshear,**firstshear; + + if (eflag || vflag) ev_setup(eflag,vflag); + else evflag = vflag_fdotr = 0; + + int shearupdate = 1; + if (update->setupflag) shearupdate = 0; + + // update rigid body info for owned & ghost atoms if using FixRigid masses + // body[i] = which body atom I is in, -1 if none + // mass_body = mass of each rigid body + + if (fix_rigid && neighbor->ago == 0){ + int tmp; + int *body = (int *) fix_rigid->extract("body",tmp); + double *mass_body = (double *) fix_rigid->extract("masstotal",tmp); + if (atom->nmax > nmax) { + memory->destroy(mass_rigid); + nmax = atom->nmax; + memory->create(mass_rigid,nmax,"pair:mass_rigid"); + } + int nlocal = atom->nlocal; + for (i = 0; i < nlocal; i++) + if (body[i] >= 0) mass_rigid[i] = mass_body[body[i]]; + else mass_rigid[i] = 0.0; + comm->forward_comm_pair(this); + } + + double **x = atom->x; + double **v = atom->v; + double **f = atom->f; + double **omega = atom->omega; + double **torque = atom->torque; + double *radius = atom->radius; + double *rmass = atom->rmass; + int *type = atom->type; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + inum = list->inum; + ilist = list->ilist; + numneigh = list->numneigh; + firstneigh = list->firstneigh; + firsttouch = fix_history->firstflag; + firstshear = fix_history->firstvalue; + + // loop over neighbors of my atoms + + for (ii = 0; ii < inum; ii++) { + i = ilist[ii]; + itype = type[i]; + xtmp = x[i][0]; + ytmp = x[i][1]; + ztmp = x[i][2]; + radi = radius[i]; + touch = firsttouch[i]; + allshear = firstshear[i]; + jlist = firstneigh[i]; + jnum = numneigh[i]; + + for (jj = 0; jj < jnum; jj++) { + j = jlist[jj]; + jtype = type[j]; + j &= NEIGHMASK; + + delx = xtmp - x[j][0]; + dely = ytmp - x[j][1]; + delz = ztmp - x[j][2]; + rsq = delx*delx + dely*dely + delz*delz; + radj = radius[j]; + radsum = radi + radj; + + if (rsq >= radsum*radsum){ + // unset non-touching neighbors + touch[jj] = 0; + shear = &allshear[size_history*jj]; + for (int k = 0; k < size_history; k++) + shear[k] = 0.0; + } else { + r = sqrt(rsq); + rinv = 1.0/r; + rsqinv = 1.0/rsq; + R = radi*radj/(radi+radj); + nx = delx*rinv; + ny = dely*rinv; + nz = delz*rinv; + + // relative translational velocity + + vr1 = v[i][0] - v[j][0]; + vr2 = v[i][1] - v[j][1]; + vr3 = v[i][2] - v[j][2]; + + // normal component + + vnnr = vr1*nx + vr2*ny + vr3*nz; //v_R . n + vn1 = nx*vnnr; + vn2 = ny*vnnr; + vn3 = nz*vnnr; + + // meff = effective mass of pair of particles + // if I or J part of rigid body, use body mass + // if I or J is frozen, meff is other particle + + mi = rmass[i]; + mj = rmass[j]; + if (fix_rigid) { + if (mass_rigid[i] > 0.0) mi = mass_rigid[i]; + if (mass_rigid[j] > 0.0) mj = mass_rigid[j]; + } + + meff = mi*mj / (mi+mj); + if (mask[i] & freeze_group_bit) meff = mj; + if (mask[j] & freeze_group_bit) meff = mi; + + //**************************************** + //Normal force = Hertzian contact + DMT + damping + //**************************************** + overlap = radsum - r; + a = sqrt(R*overlap); + kn = 4.0/3.0*E[itype][jtype]*a; + Fhz = kn*overlap; + + //Damping (based on Tsuji et al) + if (normaldamp == BRILLIANTOV) eta_N = a*meff*gamman[itype][jtype]; + else if (normaldamp == TSUJI) eta_N=alpha[itype][jtype]*sqrt(meff*kn); + + Fdamp = -eta_N*vnnr; //F_nd eq 23 and Zhao eq 19 + + //DMT + Fdmt = -4*MY_PI*Ecoh[itype][jtype]*R; + + Fne = Fhz + Fdmt; + Fntot = Fne + Fdamp; + + //**************************************** + //Tangential force, including shear history effects + //**************************************** + + // tangential component + vt1 = vr1 - vn1; + vt2 = vr2 - vn2; + vt3 = vr3 - vn3; + + // relative rotational velocity + //Luding Gran Matt 2008, v10,p235 suggests correcting radi and radj by subtracting + //delta/2, i.e. instead of radi, use distance to center of contact point? + wr1 = (radi*omega[i][0] + radj*omega[j][0]); + wr2 = (radi*omega[i][1] + radj*omega[j][1]); + wr3 = (radi*omega[i][2] + radj*omega[j][2]); + + // relative tangential velocities + vtr1 = vt1 - (nz*wr2-ny*wr3); + vtr2 = vt2 - (nx*wr3-nz*wr1); + vtr3 = vt3 - (ny*wr1-nx*wr2); + vrel = vtr1*vtr1 + vtr2*vtr2 + vtr3*vtr3; + vrel = sqrt(vrel); + + // shear history effects + touch[jj] = 1; + shear = &allshear[size_history*jj]; + shrmag = sqrt(shear[0]*shear[0] + shear[1]*shear[1] + + shear[2]*shear[2]); + + // Rotate and update shear displacements. + // See e.g. eq. 17 of Luding, Gran. Matter 2008, v10,p235 + if (shearupdate) { + rsht = shear[0]*nx + shear[1]*ny + shear[2]*nz; + if (fabs(rsht) < EPSILON) rsht = 0; + if (rsht > 0){ + scalefac = shrmag/(shrmag - rsht); //if rhst == shrmag, contacting pair has rotated 90 deg. in one step, in which case you deserve a crash! + shear[0] -= rsht*nx; + shear[1] -= rsht*ny; + shear[2] -= rsht*nz; + //Also rescale to preserve magnitude + shear[0] *= scalefac; + shear[1] *= scalefac; + shear[2] *= scalefac; + } + //Update shear history + shear[0] += vtr1*dt; + shear[1] += vtr2*dt; + shear[2] += vtr3*dt; + } + + // tangential forces = shear + tangential velocity damping + // following Zhao and Marshall Phys Fluids v20, p043302 (2008) + kt=8.0*G[itype][jtype]*a; + + eta_T = eta_N; //Based on discussion in Marshall; eta_T can also be an independent parameter + fs1 = -kt*shear[0] - eta_T*vtr1; //eq 26 + fs2 = -kt*shear[1] - eta_T*vtr2; + fs3 = -kt*shear[2] - eta_T*vtr3; + + // rescale frictional displacements and forces if needed + Fscrit = muS[itype][jtype] * fabs(Fne); + // For JKR, use eq 43 of Marshall. For DMT, use Fne instead + shrmag = sqrt(shear[0]*shear[0] + shear[1]*shear[1] + + shear[2]*shear[2]); + fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); + if (fs > Fscrit) { + if (shrmag != 0.0) { + //shear[0] = (Fcrit/fs) * (shear[0] + eta_T*vtr1/kt) - eta_T*vtr1/kt; + //shear[1] = (Fcrit/fs) * (shear[1] + eta_T*vtr1/kt) - eta_T*vtr1/kt; + //shear[2] = (Fcrit/fs) * (shear[2] + eta_T*vtr1/kt) - eta_T*vtr1/kt; + shear[0] = -1.0/kt*(Fscrit*fs1/fs + eta_T*vtr1); //Same as above, but simpler (check!) + shear[1] = -1.0/kt*(Fscrit*fs2/fs + eta_T*vtr2); + shear[2] = -1.0/kt*(Fscrit*fs3/fs + eta_T*vtr3); + fs1 *= Fscrit/fs; + fs2 *= Fscrit/fs; + fs3 *= Fscrit/fs; + } else fs1 = fs2 = fs3 = 0.0; + } + + //**************************************** + // Rolling force, including shear history effects + //**************************************** + + relrot1 = omega[i][0] - omega[j][0]; + relrot2 = omega[i][1] - omega[j][1]; + relrot3 = omega[i][2] - omega[j][2]; + + // rolling velocity, see eq. 31 of Wang et al, Particuology v 23, p 49 (2015) + // This is different from the Marshall papers, which use the Bagi/Kuhn formulation + // for rolling velocity (see Wang et al for why the latter is wrong) + vrl1 = R*(relrot2*nz - relrot3*ny); //- 0.5*((radj-radi)/radsum)*vtr1; + vrl2 = R*(relrot3*nx - relrot1*nz); //- 0.5*((radj-radi)/radsum)*vtr2; + vrl3 = R*(relrot1*ny - relrot2*nx); //- 0.5*((radj-radi)/radsum)*vtr3; + vrlmag = sqrt(vrl1*vrl1+vrl2*vrl2+vrl3*vrl3); + if (vrlmag != 0.0) vrlmaginv = 1.0/vrlmag; + else vrlmaginv = 0.0; + + // Rolling displacement + rollmag = sqrt(shear[3]*shear[3] + shear[4]*shear[4] + shear[5]*shear[5]); + rolldotn = shear[3]*nx + shear[4]*ny + shear[5]*nz; + + if (shearupdate) { + if (fabs(rolldotn) < EPSILON) rolldotn = 0; + if (rolldotn > 0){ //Rotate into tangential plane + scalefac = rollmag/(rollmag - rolldotn); + shear[3] -= rolldotn*nx; + shear[4] -= rolldotn*ny; + shear[5] -= rolldotn*nz; + //Also rescale to preserve magnitude + shear[3] *= scalefac; + shear[4] *= scalefac; + shear[5] *= scalefac; + } + shear[3] += vrl1*dt; + shear[4] += vrl2*dt; + shear[5] += vrl3*dt; + } + + k_R = kR[itype][jtype]; + if (rollingdamp == INDEP) eta_R = etaR[itype][jtype]; + else if (rollingdamp == BRILLROLL) eta_R = muR[itype][jtype]*fabs(Fne); + fr1 = -k_R*shear[3] - eta_R*vrl1; + fr2 = -k_R*shear[4] - eta_R*vrl2; + fr3 = -k_R*shear[5] - eta_R*vrl3; + + // rescale frictional displacements and forces if needed + Frcrit = muR[itype][jtype] * fabs(Fne); + + fr = sqrt(fr1*fr1 + fr2*fr2 + fr3*fr3); + if (fr > Frcrit) { + if (rollmag != 0.0) { + shear[3] = -1.0/k_R*(Frcrit*fr1/fr + eta_R*vrl1); + shear[4] = -1.0/k_R*(Frcrit*fr2/fr + eta_R*vrl2); + shear[5] = -1.0/k_R*(Frcrit*fr3/fr + eta_R*vrl3); + fr1 *= Frcrit/fr; + fr2 *= Frcrit/fr; + fr3 *= Frcrit/fr; + } else fr1 = fr2 = fr3 = 0.0; + } + + + //**************************************** + // Twisting torque, including shear history effects + //**************************************** + magtwist = relrot1*nx + relrot2*ny + relrot3*nz; //Omega_T (eq 29 of Marshall) + shear[6] += magtwist*dt; + k_Q = 0.5*kt*a*a;; //eq 32 + eta_Q = 0.5*eta_T*a*a; + magtortwist = -k_Q*shear[6] - eta_Q*magtwist;//M_t torque (eq 30) + + signtwist = (magtwist > 0) - (magtwist < 0); + Mtcrit=TWOTHIRDS*a*Fscrit;//critical torque (eq 44) + if (fabs(magtortwist) > Mtcrit){ + shear[6] = 1.0/k_Q*(Mtcrit*signtwist - eta_Q*magtwist); + magtortwist = -Mtcrit * signtwist; //eq 34 + } + + // Apply forces & torques + + fx = nx*Fntot + fs1; + fy = ny*Fntot + fs2; + fz = nz*Fntot + fs3; + + f[i][0] += fx; + f[i][1] += fy; + f[i][2] += fz; + + tor1 = ny*fs3 - nz*fs2; + tor2 = nz*fs1 - nx*fs3; + tor3 = nx*fs2 - ny*fs1; + + torque[i][0] -= radi*tor1; + torque[i][1] -= radi*tor2; + torque[i][2] -= radi*tor3; + + tortwist1 = magtortwist * nx; + tortwist2 = magtortwist * ny; + tortwist3 = magtortwist * nz; + + torque[i][0] += tortwist1; + torque[i][1] += tortwist2; + torque[i][2] += tortwist3; + + torroll1 = R*(ny*fr3 - nz*fr2); //n cross fr + torroll2 = R*(nz*fr1 - nx*fr3); + torroll3 = R*(nx*fr2 - ny*fr1); + + torque[i][0] += torroll1; + torque[i][1] += torroll2; + torque[i][2] += torroll3; + + if (force->newton_pair || j < nlocal) { + f[j][0] -= fx; + f[j][1] -= fy; + f[j][2] -= fz; + + torque[j][0] -= radj*tor1; + torque[j][1] -= radj*tor2; + torque[j][2] -= radj*tor3; + + torque[j][0] -= tortwist1; + torque[j][1] -= tortwist2; + torque[j][2] -= tortwist3; + + torque[j][0] -= torroll1; + torque[j][1] -= torroll2; + torque[j][2] -= torroll3; + } + if (evflag) ev_tally_xyz(i,j,nlocal,0, + 0.0,0.0,fx,fy,fz,delx,dely,delz); + } + } + } +} + +/* ---------------------------------------------------------------------- + global settings + ------------------------------------------------------------------------- */ + +void PairGranDMTRolling::settings(int narg, char **arg) +{ + if (narg < 6) error->all(FLERR,"Illegal pair_style command"); + + int ntypes = atom->ntypes; + + if (narg < 8*ntypes) error->all(FLERR,"Illegal pair_style command"); + + E_one = new double[ntypes+1]; + G_one = new double[ntypes+1]; + pois = new double[ntypes+1]; + muS_one = new double[ntypes+1]; + cor = new double[ntypes+1]; + alpha_one = new double[ntypes+1]; + Ecoh_one = new double[ntypes+1]; + kR_one = new double[ntypes+1]; + muR_one = new double[ntypes+1]; + etaR_one = new double[ntypes+1]; + + for (int i=0; i < ntypes;i++){ + E_one[i+1] = force->numeric(FLERR, arg[i]); + G_one[i+1] = force->numeric(FLERR, arg[ntypes+i]); + muS_one[i+1] = force->numeric(FLERR, arg[2*ntypes+i]); + cor[i+1] = force->numeric(FLERR, arg[3*ntypes+i]); + Ecoh_one[i+1] = force->numeric(FLERR, arg[4*ntypes+i]); + kR_one[i+1] = force->numeric(FLERR, arg[5*ntypes+i]); + muR_one[i+1] = force->numeric(FLERR, arg[6*ntypes+i]); + etaR_one[i+1] = force->numeric(FLERR, arg[7*ntypes+i]); + } + + //Defaults + normaldamp = TSUJI; + rollingdamp = INDEP; + + int iarg = 8*ntypes; + while (iarg < narg){ + if (strcmp(arg[iarg],"normaldamp") == 0){ + if (iarg+2 > narg) error->all(FLERR, "Invalid pair/gran/dmt/rolling entry"); + if (strcmp(arg[iarg+1],"tsuji") == 0) normaldamp = TSUJI; + else if (strcmp(arg[iarg+1],"brilliantov") == 0) normaldamp = BRILLIANTOV; + else error->all(FLERR, "Invalid normal damping model for pair/gran/dmt/rolling"); + iarg += 2; + } + else if (strcmp(arg[iarg],"rollingdamp") == 0){ + if (iarg+2 > narg) error->all(FLERR, "Invalid pair/gran/dmt/rolling entry"); + if (strcmp(arg[iarg+1],"independent") == 0) rollingdamp = INDEP; + else if (strcmp(arg[iarg+1],"brilliantov") == 0) rollingdamp = BRILLROLL; + else error->all(FLERR, "Invalid rolling damping model for pair/gran/dmt/rolling"); + iarg += 2; + } + else{ + iarg +=1; + } + } + + //Derived from inputs + for (int i=1; i <= ntypes; i++){ + pois[i] = E_one[i]/(2.0*G_one[i]) - 1.0; + alpha_one[i] = 1.2728-4.2783*cor[i]+11.087*cor[i]*cor[i]-22.348*cor[i]*cor[i]*cor[i]+27.467*cor[i]*cor[i]*cor[i]*cor[i]-18.022*cor[i]*cor[i]*cor[i]*cor[i]*cor[i]+4.8218*cor[i]*cor[i]*cor[i]*cor[i]*cor[i]*cor[i]; + for (int j=i; j <= ntypes; j++){ + E[i][j] = E[j][i] = 1/((1-pois[i]*pois[i])/E_one[i]+(1-pois[j]*pois[j])/E_one[j]); + G[i][j] = G[j][i] = 1/((2-pois[i])/G_one[i]+(2-pois[j])/G_one[j]); + if (normaldamp == TSUJI){ + alpha[i][j] = alpha[j][i] = sqrt(alpha_one[i]*alpha_one[j]); + } + else if (normaldamp == BRILLIANTOV){ + gamman[i][j] = gamman[j][i] = sqrt(cor[i]*cor[j]); + } + muS[i][j] = muS[j][i] = sqrt(muS_one[i]*muS_one[j]); + Ecoh[i][j] = Ecoh[j][i] = sqrt(Ecoh_one[i]*Ecoh_one[j]); + kR[i][j] = kR[j][i] = sqrt(kR_one[i]*kR_one[j]); + etaR[i][j] = etaR[j][i] = sqrt(etaR_one[i]*etaR_one[j]); + muR[i][j] = muR[j][i] = sqrt(muR_one[i]*muR_one[j]); + } + } +} + +/* ---------------------------------------------------------------------- */ + +double PairGranDMTRolling::single(int i, int j, int itype, int jtype, + double rsq, + double factor_coul, double factor_lj, + double &fforce) +{ + double radi,radj,radsum; + double r,rinv,rsqinv,delx,dely,delz, nx, ny, nz, R; + double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3,wr1,wr2,wr3; + double overlap, a; + double mi,mj,meff,damp,kn,kt; + double Fhz,Fdamp,Fdmt,Fne,Fntot,Fscrit; + double eta_N,eta_T; + double vtr1,vtr2,vtr3,vrel; + double fs1,fs2,fs3,fs; + double shrmag; + + + double *radius = atom->radius; + radi = radius[i]; + radj = radius[j]; + radsum = radi + radj; + + if (rsq >= radsum*radsum) { + fforce = 0.0; + svector[0] = svector[1] = svector[2] = svector[3] = 0.0; + return 0.0; + } + + r = sqrt(rsq); + rinv = 1.0/r; + rsqinv = 1.0/rsq; + R = radi*radj/radsum; + + // relative translational velocity + + double **v = atom->v; + vr1 = v[i][0] - v[j][0]; + vr2 = v[i][1] - v[j][1]; + vr3 = v[i][2] - v[j][2]; + + // normal component + + double **x = atom->x; + delx = x[i][0] - x[j][0]; + dely = x[i][1] - x[j][1]; + delz = x[i][2] - x[j][2]; + + nx = delx*rinv; + ny = dely*rinv; + nz = delz*rinv; + + + vnnr = vr1*nx + vr2*ny + vr3*nz; + vn1 = nx*vnnr; + vn2 = ny*vnnr; + vn3 = nz*vnnr; + + // tangential component + + vt1 = vr1 - vn1; + vt2 = vr2 - vn2; + vt3 = vr3 - vn3; + + // relative rotational velocity + + double **omega = atom->omega; + wr1 = (radi*omega[i][0] + radj*omega[j][0]); + wr2 = (radi*omega[i][1] + radj*omega[j][1]); + wr3 = (radi*omega[i][2] + radj*omega[j][2]); + + // meff = effective mass of pair of particles + // if I or J part of rigid body, use body mass + // if I or J is frozen, meff is other particle + + double *rmass = atom->rmass; + int *type = atom->type; + int *mask = atom->mask; + + mi = rmass[i]; + mj = rmass[j]; + if (fix_rigid) { + // NOTE: ensure mass_rigid is current for owned+ghost atoms? + if (mass_rigid[i] > 0.0) mi = mass_rigid[i]; + if (mass_rigid[j] > 0.0) mj = mass_rigid[j]; + } + + meff = mi*mj / (mi+mj); + if (mask[i] & freeze_group_bit) meff = mj; + if (mask[j] & freeze_group_bit) meff = mi; + + + // normal force = Hertzian contact + normal velocity damping + overlap = radsum - r; + a = sqrt(R*overlap); + kn = 4.0/3.0*E[itype][jtype]*a; + Fhz = kn*overlap; + + //Damping (based on Tsuji et al) + + eta_N=alpha[itype][jtype]*sqrt(meff*kn); + Fdamp = -eta_N*vnnr; //F_nd eq 23 and Zhao eq 19 + + //DMT + Fdmt = -4*MY_PI*Ecoh[itype][jtype]*R; + + Fne = Fhz + Fdmt; + Fntot = Fne + Fdamp; + + // relative velocities + + vtr1 = vt1 - (nz*wr2-ny*wr3); + vtr2 = vt2 - (nx*wr3-nz*wr1); + vtr3 = vt3 - (ny*wr1-nx*wr2); + vrel = vtr1*vtr1 + vtr2*vtr2 + vtr3*vtr3; + vrel = sqrt(vrel); + + // shear history effects + // neighprev = index of found neigh on previous call + // search entire jnum list of neighbors of I for neighbor J + // start from neighprev, since will typically be next neighbor + // reset neighprev to 0 as necessary + + int jnum = list->numneigh[i]; + int *jlist = list->firstneigh[i]; + double *allshear = fix_history->firstvalue[i]; + + for (int jj = 0; jj < jnum; jj++) { + neighprev++; + if (neighprev >= jnum) neighprev = 0; + if (jlist[neighprev] == j) break; + } + + double *shear = &allshear[size_history*neighprev]; + shrmag = sqrt(shear[0]*shear[0] + shear[1]*shear[1] + + shear[2]*shear[2]); + + // tangential forces = shear + tangential velocity damping + kt=8.0*G[itype][jtype]*a; + + eta_T = eta_N; + fs1 = -kt*shear[0] - eta_T*vtr1; + fs2 = -kt*shear[1] - eta_T*vtr2; + fs3 = -kt*shear[2] - eta_T*vtr3; + + // rescale frictional displacements and forces if needed + + fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); + Fscrit= muS[itype][jtype] * fabs(Fne); + + if (fs > Fscrit) { + if (shrmag != 0.0) { + fs1 *= Fscrit/fs; + fs2 *= Fscrit/fs; + fs3 *= Fscrit/fs; + fs *= Fscrit/fs; + } else fs1 = fs2 = fs3 = fs = 0.0; + } + + // set all forces and return no energy + + fforce = Fntot; + + // set single_extra quantities + + svector[0] = fs1; + svector[1] = fs2; + svector[2] = fs3; + svector[3] = fs; + svector[4] = vn1; + svector[5] = vn2; + svector[6] = vn3; + svector[7] = vt1; + svector[8] = vt2; + svector[9] = vt3; + return 0.0; +} diff --git a/src/GRANULAR/pair_gran_dmt_rolling.h b/src/GRANULAR/pair_gran_dmt_rolling.h new file mode 100644 index 0000000000..8f4ae2005e --- /dev/null +++ b/src/GRANULAR/pair_gran_dmt_rolling.h @@ -0,0 +1,55 @@ +/* -*- 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. +------------------------------------------------------------------------- */ + +#ifdef PAIR_CLASS + +PairStyle(gran/dmt/rolling,PairGranDMTRolling) + +#else + +#ifndef LMP_PAIR_GRAN_DMT_ROLLING_H +#define LMP_PAIR_GRAN_DMT_ROLLING_H + +#include "pair_gran_hooke_history.h" + +namespace LAMMPS_NS { + +class PairGranDMTRolling : public PairGranHookeHistory { +public: + PairGranDMTRolling(class LAMMPS *); + virtual ~PairGranDMTRolling(); + virtual void compute(int, int); + void settings(int, char **); //Eventually set this through coeff method so that user can specify a particular i-j set of coefficients + double single(int, int, int, int, double, double, double, double &); + double *E_one, *G_one, *pois, *muS_one, *cor, *alpha_one, *Ecoh_one, *kR_one, *muR_one, *etaR_one; //Public so as to be accessible to fix/wall/gran +private: + double **E, **G, **alpha, **muS, **Ecoh, **kR, **muR, **etaR, **gamman; + int normaldamp, rollingdamp; + + +}; + +} + +#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. + + */ diff --git a/src/GRANULAR/pair_gran_hertz_history.cpp b/src/GRANULAR/pair_gran_hertz_history.cpp index 9723531625..5508b17d99 100644 --- a/src/GRANULAR/pair_gran_hertz_history.cpp +++ b/src/GRANULAR/pair_gran_hertz_history.cpp @@ -36,7 +36,7 @@ using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ PairGranHertzHistory::PairGranHertzHistory(LAMMPS *lmp) : - PairGranHookeHistory(lmp) {} + PairGranHookeHistory(lmp, 3) {} /* ---------------------------------------------------------------------- */ diff --git a/src/GRANULAR/pair_gran_hooke_history.cpp b/src/GRANULAR/pair_gran_hooke_history.cpp index 4f120150de..f1a155f2e4 100644 --- a/src/GRANULAR/pair_gran_hooke_history.cpp +++ b/src/GRANULAR/pair_gran_hooke_history.cpp @@ -39,7 +39,8 @@ using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ -PairGranHookeHistory::PairGranHookeHistory(LAMMPS *lmp) : Pair(lmp) +PairGranHookeHistory::PairGranHookeHistory(LAMMPS *lmp, int _size_history) : Pair(lmp), + size_history(_size_history) { single_enable = 1; no_virial_fdotr_compute = 1; @@ -412,7 +413,7 @@ void PairGranHookeHistory::init_style() if (history && fix_history == NULL) { char dnumstr[16]; - sprintf(dnumstr,"%d",3); + sprintf(dnumstr,"%d",size_history); char **fixarg = new char*[4]; fixarg[0] = (char *) "NEIGH_HISTORY"; fixarg[1] = (char *) "all"; diff --git a/src/GRANULAR/pair_gran_hooke_history.h b/src/GRANULAR/pair_gran_hooke_history.h index 3ca5c73116..c35de04109 100644 --- a/src/GRANULAR/pair_gran_hooke_history.h +++ b/src/GRANULAR/pair_gran_hooke_history.h @@ -26,7 +26,7 @@ namespace LAMMPS_NS { class PairGranHookeHistory : public Pair { public: - PairGranHookeHistory(class LAMMPS *); + PairGranHookeHistory(class LAMMPS *, int size_history = 3); virtual ~PairGranHookeHistory(); virtual void compute(int, int); virtual void settings(int, char **); @@ -54,6 +54,8 @@ class PairGranHookeHistory : public Pair { double *onerad_dynamic,*onerad_frozen; double *maxrad_dynamic,*maxrad_frozen; + int size_history; + class FixNeighHistory *fix_history; // storage of rigid body masses for use in granular interactions diff --git a/src/GRANULAR/pair_gran_jkr_rolling.cpp b/src/GRANULAR/pair_gran_jkr_rolling.cpp new file mode 100644 index 0000000000..ce109cccbc --- /dev/null +++ b/src/GRANULAR/pair_gran_jkr_rolling.cpp @@ -0,0 +1,763 @@ +/* ---------------------------------------------------------------------- + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. + ------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Contributing authors: Leo Silbert (SNL), Gary Grest (SNL) + ------------------------------------------------------------------------- */ + +#include +#include +#include +#include +#include "pair_gran_jkr_rolling.h" +#include "atom.h" +#include "update.h" +#include "force.h" +#include "fix.h" +#include "fix_neigh_history.h" +#include "neighbor.h" +#include "neigh_list.h" +#include "comm.h" +#include "memory.h" +#include "error.h" +#include "math_const.h" + +using namespace LAMMPS_NS; +using namespace MathConst; + +#define ONETHIRD 0.33333333333333333 +#define TWOTHIRDS 0.66666666666666666 +#define POW6ONE 0.550321208149104 //6^(-1/3) +#define POW6TWO 0.30285343213869 //6^(-2/3) + +#define EPSILON 1e-10 + +enum {TSUJI, BRILLIANTOV}; +enum {INDEP, BRILLROLL}; + +/* ---------------------------------------------------------------------- */ + +PairGranJKRRolling::PairGranJKRRolling(LAMMPS *lmp) : + PairGranHookeHistory(lmp, 7) +{ + E_one = NULL; + G_one = NULL; + pois = NULL; + muS_one = NULL; + cor = NULL; + alpha_one = NULL; + Ecoh_one = NULL; + kR_one = NULL; + muR_one = NULL; + etaR_one = NULL; + int ntypes = atom->ntypes; + memory->create(E,ntypes+1,ntypes+1,"pair:E"); + memory->create(G,ntypes+1,ntypes+1,"pair:G"); + memory->create(alpha,ntypes+1,ntypes+1,"pair:alpha"); + memory->create(gamman,ntypes+1,ntypes+1,"pair:gamman"); + memory->create(muS,ntypes+1,ntypes+1,"pair:muS"); + memory->create(Ecoh,ntypes+1,ntypes+1,"pair:Ecoh"); + memory->create(kR,ntypes+1,ntypes+1,"pair:kR"); + memory->create(muR,ntypes+1,ntypes+1,"pair:muR"); + memory->create(etaR,ntypes+1,ntypes+1,"pair:etaR"); +} + +/* ---------------------------------------------------------------------- */ +PairGranJKRRolling::~PairGranJKRRolling() +{ + delete [] E_one; + delete [] G_one; + delete [] pois; + delete [] muS_one; + delete [] cor; + delete [] alpha_one; + delete [] Ecoh_one; + delete [] kR_one; + delete [] muR_one; + delete [] etaR_one; + //TODO: Make all this work with standard pair coeff type commands. + //Also these should not be in the destructor. + memory->destroy(E); + memory->destroy(G); + memory->destroy(alpha); + memory->destroy(gamman); + memory->destroy(muS); + memory->destroy(Ecoh); + memory->destroy(kR); + memory->destroy(muR); + memory->destroy(etaR); +} +/* ---------------------------------------------------------------------- */ + +void PairGranJKRRolling::compute(int eflag, int vflag) +{ + int i,j,ii,jj,inum,jnum; + int itype,jtype; + double xtmp,ytmp,ztmp,delx,dely,delz,fx,fy,fz,nx,ny,nz; + double radi,radj,radsum,rsq,r,rinv,rsqinv,R,a; + double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3; + double wr1,wr2,wr3; + double vtr1,vtr2,vtr3,vrel; + double kn, kt, k_Q, k_R, eta_N, eta_T, eta_Q, eta_R; + double Fne, Fdamp, Fntot, Fscrit, Frcrit, F_C, delta_C, delta_Cinv; + double overlap, olapsq, olapcubed, sqrtterm, tmp, a0; + double keyterm, keyterm2, keyterm3, aovera0, foverFc; + double mi,mj,meff,damp,ccel,tor1,tor2,tor3; + double relrot1,relrot2,relrot3,vrl1,vrl2,vrl3,vrlmag,vrlmaginv; + double rollmag, rolldotn, scalefac; + double fr, fr1, fr2, fr3; + double signtwist, magtwist, magtortwist, Mtcrit; + double fs,fs1,fs2,fs3,roll1,roll2,roll3,torroll1,torroll2,torroll3; + double tortwist1, tortwist2, tortwist3; + double shrmag,rsht; + int *ilist,*jlist,*numneigh,**firstneigh; + int *touch,**firsttouch; + double *shear,*allshear,**firstshear; + + if (eflag || vflag) ev_setup(eflag,vflag); + else evflag = vflag_fdotr = 0; + + int shearupdate = 1; + if (update->setupflag) shearupdate = 0; + + // update rigid body info for owned & ghost atoms if using FixRigid masses + // body[i] = which body atom I is in, -1 if none + // mass_body = mass of each rigid body + + if (fix_rigid && neighbor->ago == 0){ + int tmp; + int *body = (int *) fix_rigid->extract("body",tmp); + double *mass_body = (double *) fix_rigid->extract("masstotal",tmp); + if (atom->nmax > nmax) { + memory->destroy(mass_rigid); + nmax = atom->nmax; + memory->create(mass_rigid,nmax,"pair:mass_rigid"); + } + int nlocal = atom->nlocal; + for (i = 0; i < nlocal; i++) + if (body[i] >= 0) mass_rigid[i] = mass_body[body[i]]; + else mass_rigid[i] = 0.0; + comm->forward_comm_pair(this); + } + + double **x = atom->x; + double **v = atom->v; + double **f = atom->f; + double **omega = atom->omega; + double **torque = atom->torque; + double *radius = atom->radius; + double *rmass = atom->rmass; + int *type = atom->type; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + inum = list->inum; + ilist = list->ilist; + numneigh = list->numneigh; + firstneigh = list->firstneigh; + firsttouch = fix_history->firstflag; + firstshear = fix_history->firstvalue; + + // loop over neighbors of my atoms + + for (ii = 0; ii < inum; ii++) { + i = ilist[ii]; + itype = type[i]; + xtmp = x[i][0]; + ytmp = x[i][1]; + ztmp = x[i][2]; + radi = radius[i]; + touch = firsttouch[i]; + allshear = firstshear[i]; + jlist = firstneigh[i]; + jnum = numneigh[i]; + + for (jj = 0; jj < jnum; jj++) { + j = jlist[jj]; + jtype = type[j]; + j &= NEIGHMASK; + + delx = xtmp - x[j][0]; + dely = ytmp - x[j][1]; + delz = ztmp - x[j][2]; + rsq = delx*delx + dely*dely + delz*delz; + radj = radius[j]; + radsum = radi + radj; + R = radi*radj/(radi+radj); + a0 = pow(9.0*M_PI*Ecoh[itype][jtype]*R*R/E[itype][jtype],ONETHIRD); + delta_C = 0.5*a0*a0*POW6ONE/R; + + if ((rsq >= radsum*radsum && touch[jj] == 0) || + (rsq >= (radsum+delta_C)*(radsum+delta_C))){ + // unset non-touching neighbors + touch[jj] = 0; + shear = &allshear[size_history*jj]; + for (int k = 0; k < size_history; k++) + shear[k] = 0.0; + } else { + F_C = 3.0*R*M_PI*Ecoh[itype][jtype]; + r = sqrt(rsq); + rinv = 1.0/r; + rsqinv = 1.0/rsq; + + nx = delx*rinv; + ny = dely*rinv; + nz = delz*rinv; + + // relative translational velocity + + vr1 = v[i][0] - v[j][0]; + vr2 = v[i][1] - v[j][1]; + vr3 = v[i][2] - v[j][2]; + + // normal component + + vnnr = vr1*nx + vr2*ny + vr3*nz; //v_R . n + vn1 = nx*vnnr; + vn2 = ny*vnnr; + vn3 = nz*vnnr; + + // meff = effective mass of pair of particles + // if I or J part of rigid body, use body mass + // if I or J is frozen, meff is other particle + + mi = rmass[i]; + mj = rmass[j]; + if (fix_rigid) { + if (mass_rigid[i] > 0.0) mi = mass_rigid[i]; + if (mass_rigid[j] > 0.0) mj = mass_rigid[j]; + } + + meff = mi*mj / (mi+mj); + if (mask[i] & freeze_group_bit) meff = mj; + if (mask[j] & freeze_group_bit) meff = mi; + + //**************************************** + //Normal force = JKR-adjusted Hertzian contact + damping + //**************************************** + if (Ecoh[itype][jtype] != 0.0) delta_Cinv = 1.0/delta_C; + else delta_Cinv = 1.0; + overlap = (radsum - r)*delta_Cinv; + olapsq = overlap*overlap; + olapcubed = olapsq*overlap; + sqrtterm = sqrt(1.0 + olapcubed); + tmp = 2.0 + olapcubed + 2.0*sqrtterm; + keyterm = pow(tmp,ONETHIRD); + keyterm2 = olapsq/keyterm; + keyterm3 = sqrt(overlap + keyterm2 + keyterm); + aovera0 = POW6TWO * (keyterm3 + + sqrt(2.0*overlap - keyterm2 - keyterm + 4.0/keyterm3));// eq 41 + a = aovera0*a0; + foverFc = 4.0*((aovera0*aovera0*aovera0) - pow(aovera0,1.5));//F_ne/F_C (eq 40) + + Fne = F_C*foverFc; + + //Damping + kn = 4.0/3.0*E[itype][jtype]*a; + if (normaldamp == BRILLIANTOV) eta_N = a*meff*gamman[itype][jtype]; + else if (normaldamp == TSUJI) eta_N=alpha[itype][jtype]*sqrt(meff*kn); + + Fdamp = -eta_N*vnnr; //F_nd eq 23 and Zhao eq 19 + + Fntot = Fne + Fdamp; + + //**************************************** + //Tangential force, including shear history effects + //**************************************** + + // tangential component + vt1 = vr1 - vn1; + vt2 = vr2 - vn2; + vt3 = vr3 - vn3; + + // relative rotational velocity + //Luding Gran Matt 2008, v10,p235 suggests correcting radi and radj by subtracting + //delta/2, i.e. instead of radi, use distance to center of contact point? + wr1 = (radi*omega[i][0] + radj*omega[j][0]); + wr2 = (radi*omega[i][1] + radj*omega[j][1]); + wr3 = (radi*omega[i][2] + radj*omega[j][2]); + + // relative tangential velocities + vtr1 = vt1 - (nz*wr2-ny*wr3); + vtr2 = vt2 - (nx*wr3-nz*wr1); + vtr3 = vt3 - (ny*wr1-nx*wr2); + vrel = vtr1*vtr1 + vtr2*vtr2 + vtr3*vtr3; + vrel = sqrt(vrel); + + // shear history effects + touch[jj] = 1; + shear = &allshear[size_history*jj]; + shrmag = sqrt(shear[0]*shear[0] + shear[1]*shear[1] + + shear[2]*shear[2]); + + // Rotate and update shear displacements. + // See e.g. eq. 17 of Luding, Gran. Matter 2008, v10,p235 + if (shearupdate) { + rsht = shear[0]*nx + shear[1]*ny + shear[2]*nz; + if (fabs(rsht) < EPSILON) rsht = 0; + if (rsht > 0){ + scalefac = shrmag/(shrmag - rsht); //if rhst == shrmag, contacting pair has rotated 90 deg. in one step, in which case you deserve a crash! + shear[0] -= rsht*nx; + shear[1] -= rsht*ny; + shear[2] -= rsht*nz; + //Also rescale to preserve magnitude + shear[0] *= scalefac; + shear[1] *= scalefac; + shear[2] *= scalefac; + } + //Update shear history + shear[0] += vtr1*dt; + shear[1] += vtr2*dt; + shear[2] += vtr3*dt; + } + + // tangential forces = shear + tangential velocity damping + // following Zhao and Marshall Phys Fluids v20, p043302 (2008) + kt=8.0*G[itype][jtype]*a; + + eta_T = eta_N; //Based on discussion in Marshall; eta_T can also be an independent parameter + fs1 = -kt*shear[0] - eta_T*vtr1; //eq 26 + fs2 = -kt*shear[1] - eta_T*vtr2; + fs3 = -kt*shear[2] - eta_T*vtr3; + + // rescale frictional displacements and forces if needed + Fscrit = muS[itype][jtype] * fabs(Fne + 2*F_C); + // For JKR, use eq 43 of Marshall. For DMT, use Fne instead + + fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); + if (fs > Fscrit) { + if (shrmag != 0.0) { + //shear[0] = (Fcrit/fs) * (shear[0] + eta_T*vtr1/kt) - eta_T*vtr1/kt; + //shear[1] = (Fcrit/fs) * (shear[1] + eta_T*vtr1/kt) - eta_T*vtr1/kt; + //shear[2] = (Fcrit/fs) * (shear[2] + eta_T*vtr1/kt) - eta_T*vtr1/kt; + shear[0] = -1.0/kt*(Fscrit*fs1/fs + eta_T*vtr1); //Same as above, but simpler (check!) + shear[1] = -1.0/kt*(Fscrit*fs2/fs + eta_T*vtr2); + shear[2] = -1.0/kt*(Fscrit*fs3/fs + eta_T*vtr3); + fs1 *= Fscrit/fs; + fs2 *= Fscrit/fs; + fs3 *= Fscrit/fs; + } else fs1 = fs2 = fs3 = 0.0; + } + + //**************************************** + // Rolling force, including shear history effects + //**************************************** + + relrot1 = omega[i][0] - omega[j][0]; + relrot2 = omega[i][1] - omega[j][1]; + relrot3 = omega[i][2] - omega[j][2]; + + // rolling velocity, see eq. 31 of Wang et al, Particuology v 23, p 49 (2015) + // This is different from the Marshall papers, which use the Bagi/Kuhn formulation + // for rolling velocity (see Wang et al for why the latter is wrong) + vrl1 = R*(relrot2*nz - relrot3*ny); //- 0.5*((radj-radi)/radsum)*vtr1; + vrl2 = R*(relrot3*nx - relrot1*nz); //- 0.5*((radj-radi)/radsum)*vtr2; + vrl3 = R*(relrot1*ny - relrot2*nx); //- 0.5*((radj-radi)/radsum)*vtr3; + vrlmag = sqrt(vrl1*vrl1+vrl2*vrl2+vrl3*vrl3); + if (vrlmag != 0.0) vrlmaginv = 1.0/vrlmag; + else vrlmaginv = 0.0; + + // Rolling displacement + rollmag = sqrt(shear[3]*shear[3] + shear[4]*shear[4] + shear[5]*shear[5]); + rolldotn = shear[3]*nx + shear[4]*ny + shear[5]*nz; + + if (shearupdate) { + if (fabs(rolldotn) < EPSILON) rolldotn = 0; + if (rolldotn > 0){ //Rotate into tangential plane + scalefac = rollmag/(rollmag - rolldotn); + shear[3] -= rolldotn*nx; + shear[4] -= rolldotn*ny; + shear[5] -= rolldotn*nz; + //Also rescale to preserve magnitude + shear[3] *= scalefac; + shear[4] *= scalefac; + shear[5] *= scalefac; + } + shear[3] += vrl1*dt; + shear[4] += vrl2*dt; + shear[5] += vrl3*dt; + } + + k_R = kR[itype][jtype]*4.0*F_C*pow(aovera0,1.5); + if (rollingdamp == INDEP) eta_R = etaR[itype][jtype]; + else if (rollingdamp == BRILLROLL) eta_R = muR[itype][jtype]*fabs(Fne); + fr1 = -k_R*shear[3] - eta_R*vrl1; + fr2 = -k_R*shear[4] - eta_R*vrl2; + fr3 = -k_R*shear[5] - eta_R*vrl3; + + // rescale frictional displacements and forces if needed + Frcrit = muR[itype][jtype] * fabs(Fne + 2*F_C); + + fr = sqrt(fr1*fr1 + fr2*fr2 + fr3*fr3); + if (fr > Frcrit) { + if (rollmag != 0.0) { + shear[3] = -1.0/k_R*(Frcrit*fr1/fr + eta_R*vrl1); + shear[4] = -1.0/k_R*(Frcrit*fr2/fr + eta_R*vrl2); + shear[5] = -1.0/k_R*(Frcrit*fr3/fr + eta_R*vrl3); + fr1 *= Frcrit/fr; + fr2 *= Frcrit/fr; + fr3 *= Frcrit/fr; + } else fr1 = fr2 = fr3 = 0.0; + } + + + //**************************************** + // Twisting torque, including shear history effects + //**************************************** + magtwist = relrot1*nx + relrot2*ny + relrot3*nz; //Omega_T (eq 29 of Marshall) + shear[6] += magtwist*dt; + k_Q = 0.5*kt*a*a;; //eq 32 + eta_Q = 0.5*eta_T*a*a; + magtortwist = -k_Q*shear[6] - eta_Q*magtwist;//M_t torque (eq 30) + + signtwist = (magtwist > 0) - (magtwist < 0); + Mtcrit=TWOTHIRDS*a*Fscrit;//critical torque (eq 44) + if (fabs(magtortwist) > Mtcrit) { + //shear[6] = Mtcrit/k_Q*magtwist/fabs(magtwist); + shear[6] = 1.0/k_Q*(Mtcrit*signtwist - eta_Q*magtwist); + magtortwist = -Mtcrit * signtwist; //eq 34 + } + + // Apply forces & torques + + fx = nx*Fntot + fs1; + fy = ny*Fntot + fs2; + fz = nz*Fntot + fs3; + + f[i][0] += fx; + f[i][1] += fy; + f[i][2] += fz; + + tor1 = ny*fs3 - nz*fs2; + tor2 = nz*fs1 - nx*fs3; + tor3 = nx*fs2 - ny*fs1; + + torque[i][0] -= radi*tor1; + torque[i][1] -= radi*tor2; + torque[i][2] -= radi*tor3; + + tortwist1 = magtortwist * nx; + tortwist2 = magtortwist * ny; + tortwist3 = magtortwist * nz; + + torque[i][0] += tortwist1; + torque[i][1] += tortwist2; + torque[i][2] += tortwist3; + + torroll1 = R*(ny*fr3 - nz*fr2); //n cross fr + torroll2 = R*(nz*fr1 - nx*fr3); + torroll3 = R*(nx*fr2 - ny*fr1); + + torque[i][0] += torroll1; + torque[i][1] += torroll2; + torque[i][2] += torroll3; + + if (force->newton_pair || j < nlocal) { + f[j][0] -= fx; + f[j][1] -= fy; + f[j][2] -= fz; + + torque[j][0] -= radj*tor1; + torque[j][1] -= radj*tor2; + torque[j][2] -= radj*tor3; + + torque[j][0] -= tortwist1; + torque[j][1] -= tortwist2; + torque[j][2] -= tortwist3; + + torque[j][0] -= torroll1; + torque[j][1] -= torroll2; + torque[j][2] -= torroll3; + } + if (evflag) ev_tally_xyz(i,j,nlocal,0, + 0.0,0.0,fx,fy,fz,delx,dely,delz); + } + } + } +} + +/* ---------------------------------------------------------------------- + global settings + ------------------------------------------------------------------------- */ + +void PairGranJKRRolling::settings(int narg, char **arg) +{ + if (narg < 6) error->all(FLERR,"Illegal pair_style command"); + + int ntypes = atom->ntypes; + + if (narg < 8*ntypes) error->all(FLERR,"Illegal pair_style command"); + + E_one = new double[ntypes+1]; + G_one = new double[ntypes+1]; + pois = new double[ntypes+1]; + muS_one = new double[ntypes+1]; + cor = new double[ntypes+1]; + alpha_one = new double[ntypes+1]; + Ecoh_one = new double[ntypes+1]; + kR_one = new double[ntypes+1]; + muR_one = new double[ntypes+1]; + etaR_one = new double[ntypes+1]; + + //Defaults + normaldamp = TSUJI; + rollingdamp = INDEP; + + int iarg = 8*ntypes; + while (iarg < narg){ + if (strcmp(arg[iarg],"normaldamp") == 0){ + if (iarg+2 > narg) error->all(FLERR, "Invalid pair/gran/dmt/rolling entry"); + if (strcmp(arg[iarg+1],"tsuji") == 0) normaldamp = TSUJI; + else if (strcmp(arg[iarg+1],"brilliantov") == 0) normaldamp = BRILLIANTOV; + else error->all(FLERR, "Invalid normal damping model for pair/gran/dmt/rolling"); + iarg += 2; + } + else if (strcmp(arg[iarg],"rollingdamp") == 0){ + if (iarg+2 > narg) error->all(FLERR, "Invalid pair/gran/dmt/rolling entry"); + if (strcmp(arg[iarg+1],"independent") == 0) rollingdamp = INDEP; + else if (strcmp(arg[iarg+1],"brilliantov") == 0) rollingdamp = BRILLROLL; + else error->all(FLERR, "Invalid rolling damping model for pair/gran/dmt/rolling"); + iarg +=2; + } + else iarg += 1; + } + + for (int i=0; i < ntypes;i++){ + + E_one[i+1] = force->numeric(FLERR, arg[i]); + G_one[i+1] = force->numeric(FLERR, arg[ntypes+i]); + muS_one[i+1] = force->numeric(FLERR, arg[2*ntypes+i]); + cor[i+1] = force->numeric(FLERR, arg[3*ntypes+i]); + Ecoh_one[i+1] = force->numeric(FLERR, arg[4*ntypes+i]); + kR_one[i+1] = force->numeric(FLERR, arg[5*ntypes+i]); + muR_one[i+1] = force->numeric(FLERR, arg[6*ntypes+i]); + etaR_one[i+1] = force->numeric(FLERR, arg[7*ntypes+i]); + } + + //Optional keywords: + // normaldamp tsuji, or normaldamp brilliantov + // rollingdamp brilliantov + + //Derived from inputs + for (int i=1; i <= ntypes; i++){ + pois[i] = E_one[i]/(2.0*G_one[i]) - 1.0; + alpha_one[i] = 1.2728-4.2783*cor[i]+11.087*cor[i]*cor[i]-22.348*cor[i]*cor[i]*cor[i]+27.467*cor[i]*cor[i]*cor[i]*cor[i]-18.022*cor[i]*cor[i]*cor[i]*cor[i]*cor[i]+4.8218*cor[i]*cor[i]*cor[i]*cor[i]*cor[i]*cor[i]; + for (int j=i; j <= ntypes; j++){ + E[i][j] = E[j][i] = 1/((1-pois[i]*pois[i])/E_one[i]+(1-pois[j]*pois[j])/E_one[j]); + G[i][j] = G[j][i] = 1/((2-pois[i])/G_one[i]+(2-pois[j])/G_one[j]); + if (normaldamp == TSUJI){ + alpha[i][j] = alpha[j][i] = sqrt(alpha_one[i]*alpha_one[j]); + } + else if (normaldamp == BRILLIANTOV){ + gamman[i][j] = gamman[j][i] = sqrt(cor[i]*cor[j]); + } + muS[i][j] = muS[j][i] = sqrt(muS_one[i]*muS_one[j]); + Ecoh[i][j] = Ecoh[j][i] = sqrt(Ecoh_one[i]*Ecoh_one[j]); + kR[i][j] = kR[j][i] = sqrt(kR_one[i]*kR_one[j]); + etaR[i][j] = etaR[j][i] = sqrt(etaR_one[i]*etaR_one[j]); + muR[i][j] = muR[j][i] = sqrt(muR_one[i]*muR_one[j]); + } + } +} + +/* ---------------------------------------------------------------------- */ + +double PairGranJKRRolling::single(int i, int j, int itype, int jtype, + double rsq, + double factor_coul, double factor_lj, + double &fforce) +{//TODO: update PairGranJKRRolling::single for JKR + double radi,radj,radsum; + double r,rinv,rsqinv,delx,dely,delz, nx, ny, nz, R; + double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3,wr1,wr2,wr3; + double overlap, a; + double mi,mj,meff,damp,kn,kt; + double Fdamp,Fne,Fntot,Fscrit; + double eta_N,eta_T; + double vtr1,vtr2,vtr3,vrel; + double fs1,fs2,fs3,fs; + double shrmag; + double F_C, delta_C, olapsq, olapcubed, sqrtterm, tmp, a0; + double keyterm, keyterm2, keyterm3, aovera0, foverFc; + + double *radius = atom->radius; + radi = radius[i]; + radj = radius[j]; + radsum = radi + radj; + + r = sqrt(rsq); + rinv = 1.0/r; + rsqinv = 1.0/rsq; + R = radi*radj/(radi+radj); + a0 = pow(9.0*M_PI*Ecoh[itype][jtype]*R*R/E[itype][jtype],ONETHIRD); + delta_C = 0.5*a0*a0*POW6ONE/R; + + int *touch = fix_history->firstflag[i]; + if ((rsq >= (radsum+delta_C)*(radsum+delta_C) )|| + (rsq >= radsum*radsum && touch[j])){ + fforce = 0.0; + svector[0] = svector[1] = svector[2] = svector[3] = 0.0; + return 0.0; + } + + // relative translational velocity + + double **v = atom->v; + vr1 = v[i][0] - v[j][0]; + vr2 = v[i][1] - v[j][1]; + vr3 = v[i][2] - v[j][2]; + + // normal component + + double **x = atom->x; + delx = x[i][0] - x[j][0]; + dely = x[i][1] - x[j][1]; + delz = x[i][2] - x[j][2]; + + nx = delx*rinv; + ny = dely*rinv; + nz = delz*rinv; + + + vnnr = vr1*nx + vr2*ny + vr3*nz; + vn1 = nx*vnnr; + vn2 = ny*vnnr; + vn3 = nz*vnnr; + + // tangential component + + vt1 = vr1 - vn1; + vt2 = vr2 - vn2; + vt3 = vr3 - vn3; + + // relative rotational velocity + + double **omega = atom->omega; + wr1 = (radi*omega[i][0] + radj*omega[j][0]); + wr2 = (radi*omega[i][1] + radj*omega[j][1]); + wr3 = (radi*omega[i][2] + radj*omega[j][2]); + + // meff = effective mass of pair of particles + // if I or J part of rigid body, use body mass + // if I or J is frozen, meff is other particle + + double *rmass = atom->rmass; + int *type = atom->type; + int *mask = atom->mask; + + mi = rmass[i]; + mj = rmass[j]; + if (fix_rigid) { + // NOTE: ensure mass_rigid is current for owned+ghost atoms? + if (mass_rigid[i] > 0.0) mi = mass_rigid[i]; + if (mass_rigid[j] > 0.0) mj = mass_rigid[j]; + } + + meff = mi*mj / (mi+mj); + if (mask[i] & freeze_group_bit) meff = mj; + if (mask[j] & freeze_group_bit) meff = mi; + + + // normal force = JKR + F_C = 3.0*R*M_PI*Ecoh[itype][jtype]; + overlap = radsum - r; + olapsq = overlap*overlap; + olapcubed = olapsq*olapsq; + sqrtterm = sqrt(1.0 + olapcubed); + tmp = 2.0 + olapcubed + 2.0*sqrtterm; + keyterm = pow(tmp,ONETHIRD); + keyterm2 = olapsq/keyterm; + keyterm3 = sqrt(overlap + keyterm2 + keyterm); + aovera0 = POW6TWO * (keyterm3 + + sqrt(2.0*overlap - keyterm2 - keyterm + 4.0/keyterm3));// eq 41 + a = aovera0*a0; + foverFc = 4.0*((aovera0*aovera0*aovera0) - pow(aovera0,1.5));//F_ne/F_C (eq 40) + + Fne = F_C*foverFc; + + //Damping + kn = 4.0/3.0*E[itype][jtype]*a; + if (normaldamp == BRILLIANTOV) eta_N = a*meff*gamman[itype][jtype]; + else if (normaldamp == TSUJI) eta_N=alpha[itype][jtype]*sqrt(meff*kn); + + Fdamp = -eta_N*vnnr; //F_nd eq 23 and Zhao eq 19 + + Fntot = Fne + Fdamp; + + // relative velocities + + vtr1 = vt1 - (nz*wr2-ny*wr3); + vtr2 = vt2 - (nx*wr3-nz*wr1); + vtr3 = vt3 - (ny*wr1-nx*wr2); + vrel = vtr1*vtr1 + vtr2*vtr2 + vtr3*vtr3; + vrel = sqrt(vrel); + + // shear history effects + // neighprev = index of found neigh on previous call + // search entire jnum list of neighbors of I for neighbor J + // start from neighprev, since will typically be next neighbor + // reset neighprev to 0 as necessary + + int jnum = list->numneigh[i]; + int *jlist = list->firstneigh[i]; + double *allshear = fix_history->firstvalue[i]; + + for (int jj = 0; jj < jnum; jj++) { + neighprev++; + if (neighprev >= jnum) neighprev = 0; + if (jlist[neighprev] == j) break; + } + + double *shear = &allshear[size_history*neighprev]; + shrmag = sqrt(shear[0]*shear[0] + shear[1]*shear[1] + + shear[2]*shear[2]); + + // tangential forces = shear + tangential velocity damping + kt=8.0*G[itype][jtype]*a; + + eta_T = eta_N; + fs1 = -kt*shear[0] - eta_T*vtr1; + fs2 = -kt*shear[1] - eta_T*vtr2; + fs3 = -kt*shear[2] - eta_T*vtr3; + + // rescale frictional displacements and forces if needed + + fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); + Fscrit= muS[itype][jtype] * fabs(Fne + 2*F_C); + + if (fs > Fscrit) { + if (shrmag != 0.0) { + fs1 *= Fscrit/fs; + fs2 *= Fscrit/fs; + fs3 *= Fscrit/fs; + fs *= Fscrit/fs; + } else fs1 = fs2 = fs3 = fs = 0.0; + } + + // set all forces and return no energy + + fforce = Fntot; + + // set single_extra quantities + + svector[0] = fs1; + svector[1] = fs2; + svector[2] = fs3; + svector[3] = fs; + svector[4] = vn1; + svector[5] = vn2; + svector[6] = vn3; + svector[7] = vt1; + svector[8] = vt2; + svector[9] = vt3; + return 0.0; +} diff --git a/src/GRANULAR/pair_gran_jkr_rolling.h b/src/GRANULAR/pair_gran_jkr_rolling.h new file mode 100644 index 0000000000..8c4b339eb3 --- /dev/null +++ b/src/GRANULAR/pair_gran_jkr_rolling.h @@ -0,0 +1,56 @@ +/* -*- 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. +------------------------------------------------------------------------- */ + +#ifdef PAIR_CLASS + +PairStyle(gran/jkr/rolling,PairGranJKRRolling) + +#else + +#ifndef LMP_PAIR_GRAN_JKR_ROLLING_H +#define LMP_PAIR_GRAN_JKR_ROLLING_H + +#include "pair_gran_hooke_history.h" + +namespace LAMMPS_NS { + +class PairGranJKRRolling : public PairGranHookeHistory { +public: + PairGranJKRRolling(class LAMMPS *); + virtual ~PairGranJKRRolling(); + virtual void compute(int, int); + void settings(int, char **); //Eventually set this through coeff method so that user can specify a particular i-j set of coefficients + double single(int, int, int, int, double, double, double, double &); + double *E_one, *G_one, *pois, *muS_one, *cor, *alpha_one, *Ecoh_one, *kR_one, *muR_one, *etaR_one; //Public so as to be accessible to fix/wall/gran +private: + double **E, **G, **alpha, **muS, **Ecoh, **kR, **muR, **etaR, **gamman; + int normaldamp, rollingdamp; + + + +}; + +} + +#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. + + */ From f94c5b7637ac5840ddbd3db0e5f45e07e1413477 Mon Sep 17 00:00:00 2001 From: Dan Stefan Bolintineanu Date: Mon, 16 Apr 2018 12:40:22 -0600 Subject: [PATCH 02/44] Added 'store_contacts' option to fix/wall/gran/region to store info about individual particle-wall contacts --- src/GRANULAR/fix_wall_gran.cpp | 112 ++++++++++++++++++++++---- src/GRANULAR/fix_wall_gran.h | 11 ++- src/GRANULAR/fix_wall_gran_region.cpp | 96 ++++++++++++++-------- 3 files changed, 166 insertions(+), 53 deletions(-) diff --git a/src/GRANULAR/fix_wall_gran.cpp b/src/GRANULAR/fix_wall_gran.cpp index 033c35dbac..a8386238d7 100644 --- a/src/GRANULAR/fix_wall_gran.cpp +++ b/src/GRANULAR/fix_wall_gran.cpp @@ -100,7 +100,6 @@ FixWallGran::FixWallGran(LAMMPS *lmp, int narg, char **arg) : iarg = 10; } - else { if (narg < 10) error->all(FLERR,"Illegal fix wall/gran command"); @@ -165,6 +164,7 @@ FixWallGran::FixWallGran(LAMMPS *lmp, int narg, char **arg) : wiggle = 0; wshear = 0; + peratom_flag = 0; while (iarg < narg) { if (strcmp(arg[iarg],"wiggle") == 0) { @@ -186,7 +186,13 @@ FixWallGran::FixWallGran(LAMMPS *lmp, int narg, char **arg) : vshear = force->numeric(FLERR,arg[iarg+2]); wshear = 1; iarg += 3; + } else if (strcmp(arg[iarg],"store_contacts") == 0){ + peratom_flag = 1; + size_peratom_cols = 8; //Could make this a user input option? + peratom_freq = 1; + iarg += 1; } else error->all(FLERR,"Illegal fix wall/gran command"); + } if (wallstyle == XPLANE && domain->xperiodic) @@ -239,6 +245,13 @@ FixWallGran::FixWallGran(LAMMPS *lmp, int narg, char **arg) : shearone[i][j] = 0.0; } + if (peratom_flag){ + int nlocal = atom->nlocal; + for (int i = 0; i < nlocal; i++) + for (int m = 0; m < size_peratom_cols; m++) + array_atom[i][m] = 0.0; + } + time_origin = update->ntimestep; } @@ -425,20 +438,37 @@ void FixWallGran::post_force(int vflag) meff = rmass[i]; if (fix_rigid && mass_rigid[i] > 0.0) meff = mass_rigid[i]; + // store contact info + if (peratom_flag){ + array_atom[i][0] = (double)atom->tag[i]; + array_atom[i][4] = x[i][0] - dx; + array_atom[i][5] = x[i][1] - dy; + array_atom[i][6] = x[i][2] - dz; + array_atom[i][7] = radius[i]; + } + // invoke sphere/wall interaction + double *contact; + if (peratom_flag) + contact = array_atom[i]; + else + contact = NULL; if (pairstyle == HOOKE) hooke(rsq,dx,dy,dz,vwall,v[i],f[i], - omega[i],torque[i],radius[i],meff); + omega[i],torque[i],radius[i],meff, contact); else if (pairstyle == HOOKE_HISTORY) hooke_history(rsq,dx,dy,dz,vwall,v[i],f[i], - omega[i],torque[i],radius[i],meff,shearone[i]); + omega[i],torque[i],radius[i],meff,shearone[i], + contact); else if (pairstyle == HERTZ_HISTORY) hertz_history(rsq,dx,dy,dz,vwall,rwall,v[i],f[i], - omega[i],torque[i],radius[i],meff,shearone[i]); + omega[i],torque[i],radius[i],meff,shearone[i], + contact); else if (pairstyle == BONDED_HISTORY) bonded_history(rsq,dx,dy,dz,vwall,rwall,v[i],f[i], - omega[i],torque[i],radius[i],meff,shearone[i]); + omega[i],torque[i],radius[i],meff,shearone[i], + contact); } } } @@ -456,7 +486,7 @@ void FixWallGran::post_force_respa(int vflag, int ilevel, int iloop) void FixWallGran::hooke(double rsq, double dx, double dy, double dz, double *vwall, double *v, double *f, double *omega, double *torque, - double radius, double meff) + double radius, double meff, double* contact) { double r,vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3; double wr1,wr2,wr3,damp,ccel,vtr1,vtr2,vtr3,vrel; @@ -523,6 +553,12 @@ void FixWallGran::hooke(double rsq, double dx, double dy, double dz, fy = dy*ccel + fs2; fz = dz*ccel + fs3; + if (peratom_flag){ + contact[1] = fx; + contact[2] = fy; + contact[3] = fz; + } + f[0] += fx; f[1] += fy; f[2] += fz; @@ -540,7 +576,8 @@ void FixWallGran::hooke(double rsq, double dx, double dy, double dz, void FixWallGran::hooke_history(double rsq, double dx, double dy, double dz, double *vwall, double *v, double *f, double *omega, double *torque, - double radius, double meff, double *shear) + double radius, double meff, double *shear, + double *contact) { double r,vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3; double wr1,wr2,wr3,damp,ccel,vtr1,vtr2,vtr3,vrel; @@ -643,6 +680,12 @@ void FixWallGran::hooke_history(double rsq, double dx, double dy, double dz, f[1] += fy; f[2] += fz; + if (peratom_flag){ + contact[1] = fx; + contact[2] = fy; + contact[3] = fz; + } + tor1 = rinv * (dy*fs3 - dz*fs2); tor2 = rinv * (dz*fs1 - dx*fs3); tor3 = rinv * (dx*fs2 - dy*fs1); @@ -656,7 +699,8 @@ void FixWallGran::hooke_history(double rsq, double dx, double dy, double dz, void FixWallGran::hertz_history(double rsq, double dx, double dy, double dz, double *vwall, double rwall, double *v, double *f, double *omega, double *torque, - double radius, double meff, double *shear) + double radius, double meff, double *shear, + double *contact) { double r,vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3; double wr1,wr2,wr3,damp,ccel,vtr1,vtr2,vtr3,vrel; @@ -762,6 +806,12 @@ void FixWallGran::hertz_history(double rsq, double dx, double dy, double dz, fy = dy*ccel + fs2; fz = dz*ccel + fs3; + if (peratom_flag){ + contact[1] = fx; + contact[2] = fy; + contact[3] = fz; + } + f[0] += fx; f[1] += fy; f[2] += fz; @@ -780,7 +830,8 @@ void FixWallGran::hertz_history(double rsq, double dx, double dy, double dz, void FixWallGran::bonded_history(double rsq, double dx, double dy, double dz, double *vwall, double rwall, double *v, double *f, double *omega, double *torque, - double radius, double meff, double *shear) + double radius, double meff, double *shear, + double *contact) { double r,vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3; double wr1,wr2,wr3,damp,ccel,vtr1,vtr2,vtr3,vrel; @@ -999,6 +1050,12 @@ void FixWallGran::bonded_history(double rsq, double dx, double dy, double dz, f[1] += fy; f[2] += fz; + if (peratom_flag){ + contact[1] = fx; + contact[2] = fy; + contact[3] = fz; + } + tor1 = rinv * (dy*fs3 - dz*fs2); tor2 = rinv * (dz*fs1 - dx*fs3); tor3 = rinv * (dx*fs2 - dy*fs1); @@ -1025,6 +1082,7 @@ double FixWallGran::memory_usage() double bytes = 0.0; if (history) bytes += nmax*sheardim * sizeof(double); // shear history if (fix_rigid) bytes += nmax * sizeof(int); // mass_rigid + if (peratom_flag) bytes += nmax*size_peratom_cols*sizeof(double); //store contacts return bytes; } @@ -1035,6 +1093,9 @@ double FixWallGran::memory_usage() void FixWallGran::grow_arrays(int nmax) { if (history) memory->grow(shearone,nmax,sheardim,"fix_wall_gran:shearone"); + if (peratom_flag){ + memory->grow(array_atom,nmax,size_peratom_cols,"fix_wall_gran:array_atom"); + } } /* ---------------------------------------------------------------------- @@ -1046,6 +1107,10 @@ void FixWallGran::copy_arrays(int i, int j, int delflag) if (history) for (int m = 0; m < sheardim; m++) shearone[j][m] = shearone[i][m]; + if (peratom_flag){ + for (int m = 0; m < size_peratom_cols; m++) + array_atom[j][m] = array_atom[i][m]; + } } /* ---------------------------------------------------------------------- @@ -1057,6 +1122,10 @@ void FixWallGran::set_arrays(int i) if (history) for (int m = 0; m < sheardim; m++) shearone[i][m] = 0; + if (peratom_flag){ + for (int m = 0; m < size_peratom_cols; m++) + array_atom[i][m] = 0; + } } /* ---------------------------------------------------------------------- @@ -1065,11 +1134,15 @@ void FixWallGran::set_arrays(int i) int FixWallGran::pack_exchange(int i, double *buf) { - if (!history) return 0; - int n = 0; - for (int m = 0; m < sheardim; m++) - buf[n++] = shearone[i][m]; + if (history){ + for (int m = 0; m < sheardim; m++) + buf[n++] = shearone[i][m]; + } + if (peratom_flag){ + for (int m = 0; m < size_peratom_cols; m++) + buf[n++] = array_atom[i][m]; + } return n; } @@ -1079,11 +1152,15 @@ int FixWallGran::pack_exchange(int i, double *buf) int FixWallGran::unpack_exchange(int nlocal, double *buf) { - if (!history) return 0; - int n = 0; - for (int m = 0; m < sheardim; m++) - shearone[nlocal][m] = buf[n++]; + if (history){ + for (int m = 0; m < sheardim; m++) + shearone[nlocal][m] = buf[n++]; + } + if (peratom_flag){ + for (int m = 0; m < size_peratom_cols; m++) + array_atom[nlocal][m] = buf[n++]; + } return n; } @@ -1148,3 +1225,4 @@ void FixWallGran::reset_dt() { dt = update->dt; } + diff --git a/src/GRANULAR/fix_wall_gran.h b/src/GRANULAR/fix_wall_gran.h index 2403a31907..f1a5dbc842 100644 --- a/src/GRANULAR/fix_wall_gran.h +++ b/src/GRANULAR/fix_wall_gran.h @@ -47,16 +47,16 @@ class FixWallGran : public Fix { void reset_dt(); void hooke(double, double, double, double, double *, - double *, double *, double *, double *, double, double); + double *, double *, double *, double *, double, double, double*); void hooke_history(double, double, double, double, double *, double *, double *, double *, double *, double, double, - double *); + double *, double *); void hertz_history(double, double, double, double, double *, double, double *, double *, double *, double *, double, double, - double *); + double *, double *); void bonded_history(double, double, double, double, double *, double, double *, double *, double *, double *, double, double, - double *); + double *, double *); protected: int wallstyle,wiggle,wshear,axis; @@ -82,6 +82,9 @@ class FixWallGran : public Fix { class Fix *fix_rigid; // ptr to rigid body fix, NULL if none double *mass_rigid; // rigid mass for owned+ghost atoms int nmax; // allocated size of mass_rigid + + // Store particle interactions + int store; }; } diff --git a/src/GRANULAR/fix_wall_gran_region.cpp b/src/GRANULAR/fix_wall_gran_region.cpp index d1c5d4c9c7..e00036c26a 100644 --- a/src/GRANULAR/fix_wall_gran_region.cpp +++ b/src/GRANULAR/fix_wall_gran_region.cpp @@ -238,23 +238,37 @@ void FixWallGranRegion::post_force(int vflag) meff = rmass[i]; if (fix_rigid && mass_rigid[i] > 0.0) meff = mass_rigid[i]; - // invoke sphere/wall interaction + // store contact info + if (peratom_flag){ + array_atom[i][0] = (double)atom->tag[i]; + array_atom[i][4] = x[i][0] - dx; + array_atom[i][5] = x[i][1] - dy; + array_atom[i][6] = x[i][2] - dz; + array_atom[i][7] = radius[i]; + } + // invoke sphere/wall interaction + double *contact; + if (peratom_flag) + contact = array_atom[i]; + else + contact = NULL; + if (pairstyle == HOOKE) hooke(rsq,dx,dy,dz,vwall,v[i],f[i], - omega[i],torque[i],radius[i],meff); + omega[i],torque[i],radius[i],meff, contact); else if (pairstyle == HOOKE_HISTORY) hooke_history(rsq,dx,dy,dz,vwall,v[i],f[i], omega[i],torque[i],radius[i],meff, - shearmany[i][c2r[ic]]); + shearmany[i][c2r[ic]], contact); else if (pairstyle == HERTZ_HISTORY) hertz_history(rsq,dx,dy,dz,vwall,region->contact[ic].radius, v[i],f[i],omega[i],torque[i], - radius[i],meff,shearmany[i][c2r[ic]]); + radius[i],meff,shearmany[i][c2r[ic]], contact); else if (pairstyle == BONDED_HISTORY) bonded_history(rsq,dx,dy,dz,vwall,region->contact[ic].radius, v[i],f[i],omega[i],torque[i], - radius[i],meff,shearmany[i][c2r[ic]]); + radius[i],meff,shearmany[i][c2r[ic]], contact); } } } @@ -341,6 +355,9 @@ void FixWallGranRegion::grow_arrays(int nmax) memory->grow(walls,nmax,tmax,"fix_wall_gran:walls"); memory->grow(shearmany,nmax,tmax,sheardim,"fix_wall_gran:shearmany"); } + if (peratom_flag){ + memory->grow(array_atom,nmax,size_peratom_cols,"fix_wall_gran:array_atom"); + } } /* ---------------------------------------------------------------------- @@ -351,16 +368,20 @@ void FixWallGranRegion::copy_arrays(int i, int j, int delflag) { int m,n,iwall; - if (!history) return; - - n = ncontact[i]; - - for (iwall = 0; iwall < n; iwall++) { - walls[j][iwall] = walls[i][iwall]; - for (m = 0; m < sheardim; m++) - shearmany[j][iwall][m] = shearmany[i][iwall][m]; + if (history){ + n = ncontact[i]; + for (iwall = 0; iwall < n; iwall++) { + walls[j][iwall] = walls[i][iwall]; + for (m = 0; m < sheardim; m++) + shearmany[j][iwall][m] = shearmany[i][iwall][m]; + } + ncontact[j] = ncontact[i]; + } + + if (peratom_flag){ + for (int m = 0; m < size_peratom_cols; m++) + array_atom[j][m] = array_atom[i][m]; } - ncontact[j] = ncontact[i]; } /* ---------------------------------------------------------------------- @@ -369,8 +390,12 @@ void FixWallGranRegion::copy_arrays(int i, int j, int delflag) void FixWallGranRegion::set_arrays(int i) { - if (!history) return; - ncontact[i] = 0; + if (history) + ncontact[i] = 0; + if (peratom_flag){ + for (int m = 0; m < size_peratom_cols; m++) + array_atom[i][m] = 0; + } } /* ---------------------------------------------------------------------- @@ -381,16 +406,19 @@ int FixWallGranRegion::pack_exchange(int i, double *buf) { int m; - if (!history) return 0; - int n = 0; - int count = ncontact[i]; - - buf[n++] = ubuf(count).d; - for (int iwall = 0; iwall < count; iwall++) { - buf[n++] = ubuf(walls[i][iwall]).d; - for (m = 0; m < sheardim; m++) - buf[n++] = shearmany[i][iwall][m]; + if (history){ + int count = ncontact[i]; + buf[n++] = ubuf(count).d; + for (int iwall = 0; iwall < count; iwall++) { + buf[n++] = ubuf(walls[i][iwall]).d; + for (m = 0; m < sheardim; m++) + buf[n++] = shearmany[i][iwall][m]; + } + } + if (peratom_flag){ + for (int m = 0; m < size_peratom_cols; m++) + buf[n++] = array_atom[i][m]; } return n; @@ -404,15 +432,19 @@ int FixWallGranRegion::unpack_exchange(int nlocal, double *buf) { int m; - if (!history) return 0; int n = 0; - int count = ncontact[nlocal] = (int) ubuf(buf[n++]).i; - - for (int iwall = 0; iwall < count; iwall++) { - walls[nlocal][iwall] = (int) ubuf(buf[n++]).i; - for (m = 0; m < sheardim; m++) - shearmany[nlocal][iwall][m] = buf[n++]; + if (history){ + int count = ncontact[nlocal] = (int) ubuf(buf[n++]).i; + for (int iwall = 0; iwall < count; iwall++) { + walls[nlocal][iwall] = (int) ubuf(buf[n++]).i; + for (m = 0; m < sheardim; m++) + shearmany[nlocal][iwall][m] = buf[n++]; + } + } + if (peratom_flag){ + for (int m = 0; m < size_peratom_cols; m++) + array_atom[nlocal][m] = buf[n++]; } return n; From 158c7531fe4a46631eb55d764b62ecba574157e7 Mon Sep 17 00:00:00 2001 From: Dan Stefan Bolintineanu Date: Mon, 16 Apr 2018 15:51:06 -0600 Subject: [PATCH 03/44] Added pair/gran/dmt as a granular wall interaction option --- src/GRANULAR/fix_wall_gran.cpp | 505 ++++++++++--------- src/GRANULAR/fix_wall_gran.h | 26 +- src/GRANULAR/fix_wall_gran_region.cpp | 32 +- src/GRANULAR/pair_gran_dmt_rolling.cpp | 650 ++++++++++++------------- 4 files changed, 633 insertions(+), 580 deletions(-) diff --git a/src/GRANULAR/fix_wall_gran.cpp b/src/GRANULAR/fix_wall_gran.cpp index a8386238d7..0c2aaed403 100644 --- a/src/GRANULAR/fix_wall_gran.cpp +++ b/src/GRANULAR/fix_wall_gran.cpp @@ -39,15 +39,19 @@ using namespace MathConst; // XYZ PLANE need to be 0,1,2 enum{XPLANE=0,YPLANE=1,ZPLANE=2,ZCYLINDER,REGION}; -enum{HOOKE,HOOKE_HISTORY,HERTZ_HISTORY,BONDED_HISTORY}; +enum{HOOKE,HOOKE_HISTORY,HERTZ_HISTORY,JKR_ROLLING,DMT_ROLLING}; enum{NONE,CONSTANT,EQUAL}; +enum {TSUJI, BRILLIANTOV}; +enum {INDEP, BRILLROLL}; + #define BIG 1.0e20 +#define EPSILON 1e-10 /* ---------------------------------------------------------------------- */ FixWallGran::FixWallGran(LAMMPS *lmp, int narg, char **arg) : - Fix(lmp, narg, arg), idregion(NULL), shearone(NULL), fix_rigid(NULL), mass_rigid(NULL) + Fix(lmp, narg, arg), idregion(NULL), shearone(NULL), fix_rigid(NULL), mass_rigid(NULL) { if (narg < 4) error->all(FLERR,"Illegal fix wall/gran command"); @@ -62,7 +66,8 @@ FixWallGran::FixWallGran(LAMMPS *lmp, int narg, char **arg) : if (strcmp(arg[3],"hooke") == 0) pairstyle = HOOKE; else if (strcmp(arg[3],"hooke/history") == 0) pairstyle = HOOKE_HISTORY; else if (strcmp(arg[3],"hertz/history") == 0) pairstyle = HERTZ_HISTORY; - //else if (strcmp(arg[3],"bonded/history") == 0) pairstyle = BONDED_HISTORY; + else if (strcmp(arg[3],"dmt/rolling") == 0) pairstyle = DMT_ROLLING; + //else if (strcmp(arg[3],"jkr/rolling") == 0) pairstyle = JKR_ROLLING; else error->all(FLERR,"Invalid fix wall/gran interaction style"); history = restart_peratom = 1; @@ -72,7 +77,8 @@ FixWallGran::FixWallGran(LAMMPS *lmp, int narg, char **arg) : int iarg; - if (pairstyle != BONDED_HISTORY) { + if (pairstyle != JKR_ROLLING && pairstyle != DMT_ROLLING) { + sheardim = 3; if (narg < 11) error->all(FLERR,"Illegal fix wall/gran command"); kn = force->numeric(FLERR,arg[4]); @@ -101,20 +107,42 @@ FixWallGran::FixWallGran(LAMMPS *lmp, int narg, char **arg) : iarg = 10; } else { - if (narg < 10) error->all(FLERR,"Illegal fix wall/gran command"); + if (narg < 12) error->all(FLERR,"Illegal fix wall/gran command"); - E = force->numeric(FLERR,arg[4]); - G = force->numeric(FLERR,arg[5]); - SurfEnergy = force->numeric(FLERR,arg[6]); - // Note: this doesn't get used, check w/ Jeremy? + sheardim = 7; + Emod = force->numeric(FLERR,arg[4]); + Gmod = force->numeric(FLERR,arg[5]); + xmu = force->numeric(FLERR,arg[6]); gamman = force->numeric(FLERR,arg[7]); + Ecoh = force->numeric(FLERR,arg[8]); + kR = force->numeric(FLERR,arg[9]); + muR = force->numeric(FLERR,arg[10]); + etaR = force->numeric(FLERR,arg[11]); - xmu = force->numeric(FLERR,arg[8]); - // pois = E/(2.0*G) - 1.0; - // kn = 2.0*E/(3.0*(1.0+pois)*(1.0-pois)); - // gammat=0.5*gamman; + //Defaults + normaldamp = TSUJI; + rollingdamp = INDEP; - iarg = 9; + iarg = 12; + for (int iiarg=iarg; iiarg < narg; ++iiarg){ + if (strcmp(arg[iiarg], "normaldamp") == 0){ + if(iiarg+2 > narg) error->all(FLERR, "Invalid fix/wall/gran region command"); + if (strcmp(arg[iiarg+1],"tsuji") == 0){ + normaldamp = TSUJI; + alpha = gamman; + } + else if (strcmp(arg[iiarg+1],"brilliantov") == 0) normaldamp = BRILLIANTOV; + else error->all(FLERR, "Invalid normal damping model for fix wall/gran dmt/rolling"); + iarg += 2; + } + if (strcmp(arg[iiarg], "rollingdamp") == 0){ + if(iiarg+2 > narg) error->all(FLERR, "Invalid fix/wall/gran region command"); + if (strcmp(arg[iarg+1],"independent") == 0) rollingdamp = INDEP; + else if (strcmp(arg[iarg+1],"brilliantov") == 0) rollingdamp = BRILLROLL; + else error->all(FLERR, "Invalid rolling damping model for fix wall/gran dmt/rolling"); + iarg += 2; + } + } } // wallstyle args @@ -224,9 +252,6 @@ FixWallGran::FixWallGran(LAMMPS *lmp, int narg, char **arg) : // perform initial allocation of atom-based arrays // register with Atom class - if (pairstyle == BONDED_HISTORY) sheardim = 7; - else sheardim = 3; - shearone = NULL; grow_arrays(atom->nmax); atom->add_callback(0); @@ -448,27 +473,31 @@ void FixWallGran::post_force(int vflag) } // invoke sphere/wall interaction - double *contact; + double *contact; if (peratom_flag) contact = array_atom[i]; else - contact = NULL; + contact = NULL; if (pairstyle == HOOKE) hooke(rsq,dx,dy,dz,vwall,v[i],f[i], - omega[i],torque[i],radius[i],meff, contact); + omega[i],torque[i],radius[i],meff, contact); else if (pairstyle == HOOKE_HISTORY) hooke_history(rsq,dx,dy,dz,vwall,v[i],f[i], - omega[i],torque[i],radius[i],meff,shearone[i], - contact); + omega[i],torque[i],radius[i],meff,shearone[i], + contact); else if (pairstyle == HERTZ_HISTORY) hertz_history(rsq,dx,dy,dz,vwall,rwall,v[i],f[i], - omega[i],torque[i],radius[i],meff,shearone[i], - contact); - else if (pairstyle == BONDED_HISTORY) - bonded_history(rsq,dx,dy,dz,vwall,rwall,v[i],f[i], - omega[i],torque[i],radius[i],meff,shearone[i], - contact); + omega[i],torque[i],radius[i],meff,shearone[i], + contact); + else if (pairstyle == DMT_ROLLING) + dmt_rolling(rsq,dx,dy,dz,vwall,rwall,v[i],f[i], + omega[i],torque[i],radius[i],meff,shearone[i], + contact); + /*else if (pairstyle == JKR_ROLLING) + jkr_rolling(rsq,dx,dy,dz,vwall,rwall,v[i],f[i], + omega[i],torque[i],radius[i],meff,shearone[i], + contact);*/ } } } @@ -484,9 +513,9 @@ void FixWallGran::post_force_respa(int vflag, int ilevel, int iloop) /* ---------------------------------------------------------------------- */ void FixWallGran::hooke(double rsq, double dx, double dy, double dz, - double *vwall, double *v, - double *f, double *omega, double *torque, - double radius, double meff, double* contact) + double *vwall, double *v, + double *f, double *omega, double *torque, + double radius, double meff, double* contact) { double r,vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3; double wr1,wr2,wr3,damp,ccel,vtr1,vtr2,vtr3,vrel; @@ -554,10 +583,10 @@ void FixWallGran::hooke(double rsq, double dx, double dy, double dz, fz = dz*ccel + fs3; if (peratom_flag){ - contact[1] = fx; - contact[2] = fy; - contact[3] = fz; - } + contact[1] = fx; + contact[2] = fy; + contact[3] = fz; + } f[0] += fx; f[1] += fy; @@ -574,10 +603,10 @@ void FixWallGran::hooke(double rsq, double dx, double dy, double dz, /* ---------------------------------------------------------------------- */ void FixWallGran::hooke_history(double rsq, double dx, double dy, double dz, - double *vwall, double *v, - double *f, double *omega, double *torque, - double radius, double meff, double *shear, - double *contact) + double *vwall, double *v, + double *f, double *omega, double *torque, + double radius, double meff, double *shear, + double *contact) { double r,vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3; double wr1,wr2,wr3,damp,ccel,vtr1,vtr2,vtr3,vrel; @@ -659,11 +688,11 @@ void FixWallGran::hooke_history(double rsq, double dx, double dy, double dz, if (fs > fn) { if (shrmag != 0.0) { shear[0] = (fn/fs) * (shear[0] + meff*gammat*vtr1/kt) - - meff*gammat*vtr1/kt; + meff*gammat*vtr1/kt; shear[1] = (fn/fs) * (shear[1] + meff*gammat*vtr2/kt) - - meff*gammat*vtr2/kt; + meff*gammat*vtr2/kt; shear[2] = (fn/fs) * (shear[2] + meff*gammat*vtr3/kt) - - meff*gammat*vtr3/kt; + meff*gammat*vtr3/kt; fs1 *= fn/fs ; fs2 *= fn/fs; fs3 *= fn/fs; @@ -697,10 +726,10 @@ void FixWallGran::hooke_history(double rsq, double dx, double dy, double dz, /* ---------------------------------------------------------------------- */ void FixWallGran::hertz_history(double rsq, double dx, double dy, double dz, - double *vwall, double rwall, double *v, - double *f, double *omega, double *torque, - double radius, double meff, double *shear, - double *contact) + double *vwall, double rwall, double *v, + double *f, double *omega, double *torque, + double radius, double meff, double *shear, + double *contact) { double r,vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3; double wr1,wr2,wr3,damp,ccel,vtr1,vtr2,vtr3,vrel; @@ -789,11 +818,11 @@ void FixWallGran::hertz_history(double rsq, double dx, double dy, double dz, if (fs > fn) { if (shrmag != 0.0) { shear[0] = (fn/fs) * (shear[0] + meff*gammat*vtr1/kt) - - meff*gammat*vtr1/kt; + meff*gammat*vtr1/kt; shear[1] = (fn/fs) * (shear[1] + meff*gammat*vtr2/kt) - - meff*gammat*vtr2/kt; + meff*gammat*vtr2/kt; shear[2] = (fn/fs) * (shear[2] + meff*gammat*vtr3/kt) - - meff*gammat*vtr3/kt; + meff*gammat*vtr3/kt; fs1 *= fn/fs ; fs2 *= fn/fs; fs3 *= fn/fs; @@ -807,10 +836,10 @@ void FixWallGran::hertz_history(double rsq, double dx, double dy, double dz, fz = dz*ccel + fs3; if (peratom_flag){ - contact[1] = fx; - contact[2] = fy; - contact[3] = fz; - } + contact[1] = fx; + contact[2] = fy; + contact[3] = fz; + } f[0] += fx; f[1] += fy; @@ -825,34 +854,44 @@ void FixWallGran::hertz_history(double rsq, double dx, double dy, double dz, } -/* ---------------------------------------------------------------------- */ - -void FixWallGran::bonded_history(double rsq, double dx, double dy, double dz, - double *vwall, double rwall, double *v, - double *f, double *omega, double *torque, - double radius, double meff, double *shear, - double *contact) +void FixWallGran::dmt_rolling(double rsq, double dx, double dy, double dz, + double *vwall, double rwall, double *v, + double *f, double *omega, double *torque, + double radius, double meff, double *shear, + double *contact) { - double r,vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3; - double wr1,wr2,wr3,damp,ccel,vtr1,vtr2,vtr3,vrel; - double fn,fs,fs1,fs2,fs3,fx,fy,fz,tor1,tor2,tor3; - double shrmag,rsht,polyhertz,rinv,rsqinv; - - double pois,E_eff,G_eff,rad_eff; - double a0,Fcrit,delcrit,delcritinv; - double overlap,olapsq,olapcubed,sqrtterm,tmp,keyterm,keyterm2,keyterm3; - double aovera0,foverFc; - double gammatsuji; - - double ktwist,kroll,twistcrit,rollcrit; + int i,j,ii,jj,inum,jnum; + int itype,jtype; + double xtmp,ytmp,ztmp,delx,dely,delz,fx,fy,fz,nx,ny,nz; + double radi,radj,radsum,r,rinv,rsqinv,R,a; + double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3; + double wr1,wr2,wr3; + double vtr1,vtr2,vtr3,vrel; + double kn, kt, k_Q, k_R, eta_N, eta_T, eta_Q, eta_R; + double Fhz, Fdamp, Fdmt, Fne, Fntot, Fscrit, Frcrit; + double overlap; + double mi,mj,damp,ccel,tor1,tor2,tor3; double relrot1,relrot2,relrot3,vrl1,vrl2,vrl3,vrlmag,vrlmaginv; - double magtwist,magtortwist; - double magrollsq,magroll,magrollinv,magtorroll; + double rollmag, rolldotn, scalefac; + double fr, fr1, fr2, fr3; + double signtwist, magtwist, magtortwist, Mtcrit; + double fs,fs1,fs2,fs3,roll1,roll2,roll3,torroll1,torroll2,torroll3; + double tortwist1, tortwist2, tortwist3; + double shrmag,rsht; + r = sqrt(rsq); rinv = 1.0/r; rsqinv = 1.0/rsq; + radsum = radius + rwall; + if (rwall == 0) R = radius; + else R = radius*rwall/(radius+rwall); + + nx = delx*rinv; + ny = dely*rinv; + nz = delz*rinv; + // relative translational velocity vr1 = v[0] - vwall[0]; @@ -861,13 +900,37 @@ void FixWallGran::bonded_history(double rsq, double dx, double dy, double dz, // normal component - vnnr = vr1*dx + vr2*dy + vr3*dz; - vn1 = dx*vnnr / rsq; - vn2 = dy*vnnr / rsq; - vn3 = dz*vnnr / rsq; + vnnr = vr1*nx + vr2*ny + vr3*nz; //v_R . n + vn1 = nx*vnnr; + vn2 = ny*vnnr; + vn3 = nz*vnnr; + + + //**************************************** + //Normal force = Hertzian contact + DMT + damping + //**************************************** + overlap = radsum - r; + a = sqrt(R*overlap); + kn = 4.0/3.0*Emod*a; + Fhz = kn*overlap; + + //Damping (based on Tsuji et al) + if (normaldamp == BRILLIANTOV) eta_N = a*meff*gamman; + else if (normaldamp == TSUJI) eta_N=alpha*sqrt(meff*kn); + + Fdamp = -eta_N*vnnr; //F_nd eq 23 and Zhao eq 19 + + //DMT + Fdmt = -4*MY_PI*Ecoh*R; + + Fne = Fhz + Fdmt; + Fntot = Fne + Fdamp; + + //**************************************** + //Tangential force, including shear history effects + //**************************************** // tangential component - vt1 = vr1 - vn1; vt2 = vr2 - vn2; vt3 = vr3 - vn3; @@ -878,200 +941,182 @@ void FixWallGran::bonded_history(double rsq, double dx, double dy, double dz, wr2 = radius*omega[1] * rinv; wr3 = radius*omega[2] * rinv; - // normal forces = Hertzian contact + normal velocity damping - // material properties: currently assumes identical materials - - pois = E/(2.0*G) - 1.0; - E_eff=0.5*E/(1.0-pois*pois); - G_eff=G/(4.0-2.0*pois); - - // rwall = 0 is infinite wall radius of curvature (flat wall) - - if (rwall == 0) rad_eff = radius; - else rad_eff = radius*rwall/(radius+rwall); - - Fcrit = rad_eff * (3.0 * M_PI * SurfEnergy); - a0=pow(9.0*M_PI*SurfEnergy*rad_eff*rad_eff/E_eff,1.0/3.0); - delcrit = 1.0/rad_eff*(0.5 * a0*a0/pow(6.0,1.0/3.0)); - delcritinv = 1.0/delcrit; - - overlap = (radius-r) * delcritinv; - olapsq = overlap*overlap; - olapcubed = olapsq*overlap; - sqrtterm = sqrt(1.0 + olapcubed); - tmp = 2.0 + olapcubed + 2.0*sqrtterm; - keyterm = pow(tmp,THIRD); - keyterm2 = olapsq/keyterm; - keyterm3 = sqrt(overlap + keyterm2 + keyterm); - aovera0 = pow(6.0,-TWOTHIRDS) * (keyterm3 + - sqrt(2.0*overlap - keyterm2 - keyterm + 4.0/keyterm3)); - foverFc = 4.0*((aovera0*aovera0*aovera0) - pow(aovera0,1.5)); - ccel = Fcrit*foverFc*rinv; - - // damp = meff*gamman*vnnr*rsqinv; - // ccel = kn*(radius-r)*rinv - damp; - // polyhertz = sqrt((radius-r)*radius); - // ccel *= polyhertz; - - // use Tsuji et al form - - polyhertz = 1.2728- 4.2783*0.9 + 11.087*0.9*0.9 - 22.348*0.9*0.9*0.9 + - 27.467*0.9*0.9*0.9*0.9 - 18.022*0.9*0.9*0.9*0.9*0.9 + - 4.8218*0.9*0.9*0.9*0.9*0.9*0.9; - - gammatsuji = 0.2*sqrt(meff*kn); - damp = gammatsuji*vnnr/rsq; - ccel = ccel - polyhertz * damp; - - // relative velocities - - vtr1 = vt1 - (dz*wr2-dy*wr3); - vtr2 = vt2 - (dx*wr3-dz*wr1); - vtr3 = vt3 - (dy*wr1-dx*wr2); + // relative tangential velocities + vtr1 = vt1 - (nz*wr2-ny*wr3); + vtr2 = vt2 - (nx*wr3-nz*wr1); + vtr3 = vt3 - (ny*wr1-nx*wr2); vrel = vtr1*vtr1 + vtr2*vtr2 + vtr3*vtr3; vrel = sqrt(vrel); // shear history effects + shrmag = sqrt(shear[0]*shear[0] + shear[1]*shear[1] + + shear[2]*shear[2]); + // Rotate and update shear displacements. + // See e.g. eq. 17 of Luding, Gran. Matter 2008, v10,p235 if (shearupdate) { + rsht = shear[0]*nx + shear[1]*ny + shear[2]*nz; + if (fabs(rsht) < EPSILON) rsht = 0; + if (rsht > 0){ + scalefac = shrmag/(shrmag - rsht); //if rhst == shrmag, contacting pair has rotated 90 deg. in one step, in which case you deserve a crash! + shear[0] -= rsht*nx; + shear[1] -= rsht*ny; + shear[2] -= rsht*nz; + //Also rescale to preserve magnitude + shear[0] *= scalefac; + shear[1] *= scalefac; + shear[2] *= scalefac; + } + //Update shear history shear[0] += vtr1*dt; shear[1] += vtr2*dt; shear[2] += vtr3*dt; } - shrmag = sqrt(shear[0]*shear[0] + shear[1]*shear[1] + shear[2]*shear[2]); - - // rotate shear displacements - - rsht = shear[0]*dx + shear[1]*dy + shear[2]*dz; - rsht = rsht*rsqinv; - if (shearupdate) { - shear[0] -= rsht*dx; - shear[1] -= rsht*dy; - shear[2] -= rsht*dz; - } // tangential forces = shear + tangential velocity damping + // following Zhao and Marshall Phys Fluids v20, p043302 (2008) + kt=8.0*Gmod*a; - fs1 = -polyhertz * (kt*shear[0] + meff*gammat*vtr1); - fs2 = -polyhertz * (kt*shear[1] + meff*gammat*vtr2); - fs3 = -polyhertz * (kt*shear[2] + meff*gammat*vtr3); - - kt=8.0*G_eff*a0*aovera0; - - // shear damping uses Tsuji et al form also - - fs1 = -kt*shear[0] - polyhertz*gammatsuji*vtr1; - fs2 = -kt*shear[1] - polyhertz*gammatsuji*vtr2; - fs3 = -kt*shear[2] - polyhertz*gammatsuji*vtr3; + eta_T = eta_N; //Based on discussion in Marshall; eta_T can also be an independent parameter + fs1 = -kt*shear[0] - eta_T*vtr1; //eq 26 + fs2 = -kt*shear[1] - eta_T*vtr2; + fs3 = -kt*shear[2] - eta_T*vtr3; // rescale frictional displacements and forces if needed + Fscrit = xmu * fabs(Fne); + // For JKR, use eq 43 of Marshall. For DMT, use Fne instead + //Redundant, should be same as above? + shrmag = sqrt(shear[0]*shear[0] + shear[1]*shear[1] + + shear[2]*shear[2]); fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); - fn = xmu * fabs(ccel*r + 2.0*Fcrit); - - if (fs > fn) { + if (fs > Fscrit) { if (shrmag != 0.0) { - shear[0] = (fn/fs) * (shear[0] + polyhertz*gammatsuji*vtr1/kt) - - polyhertz*gammatsuji*vtr1/kt; - shear[1] = (fn/fs) * (shear[1] + polyhertz*gammatsuji*vtr2/kt) - - polyhertz*gammatsuji*vtr2/kt; - shear[2] = (fn/fs) * (shear[2] + polyhertz*gammatsuji*vtr3/kt) - - polyhertz*gammatsuji*vtr3/kt; - fs1 *= fn/fs ; - fs2 *= fn/fs; - fs3 *= fn/fs; + //shear[0] = (Fcrit/fs) * (shear[0] + eta_T*vtr1/kt) - eta_T*vtr1/kt; + //shear[1] = (Fcrit/fs) * (shear[1] + eta_T*vtr1/kt) - eta_T*vtr1/kt; + //shear[2] = (Fcrit/fs) * (shear[2] + eta_T*vtr1/kt) - eta_T*vtr1/kt; + shear[0] = -1.0/kt*(Fscrit*fs1/fs + eta_T*vtr1); //Same as above, but simpler (check!) + shear[1] = -1.0/kt*(Fscrit*fs2/fs + eta_T*vtr2); + shear[2] = -1.0/kt*(Fscrit*fs3/fs + eta_T*vtr3); + fs1 *= Fscrit/fs; + fs2 *= Fscrit/fs; + fs3 *= Fscrit/fs; } else fs1 = fs2 = fs3 = 0.0; } - // calculate twisting and rolling components of torque - // NOTE: this assumes spheres! + //**************************************** + // Rolling force, including shear history effects + //**************************************** - relrot1 = omega[0]; - relrot2 = omega[1]; - relrot3 = omega[2]; + relrot1 = omega[0]; //- omega[j][0]; TODO: figure out how to + relrot2 = omega[1]; //- omega[j][1]; incorporate wall angular + relrot3 = omega[2]; //- omega[j][2]; velocity - // rolling velocity - // NOTE: this assumes mondisperse spheres! - - vrl1 = -rad_eff*rinv * (relrot2*dz - relrot3*dy); - vrl2 = -rad_eff*rinv * (relrot3*dx - relrot1*dz); - vrl3 = -rad_eff*rinv * (relrot1*dy - relrot2*dx); + // rolling velocity, see eq. 31 of Wang et al, Particuology v 23, p 49 (2015) + // This is different from the Marshall papers, which use the Bagi/Kuhn formulation + // for rolling velocity (see Wang et al for why the latter is wrong) + vrl1 = R*(relrot2*nz - relrot3*ny); //- 0.5*((radj-radi)/radsum)*vtr1; + vrl2 = R*(relrot3*nx - relrot1*nz); //- 0.5*((radj-radi)/radsum)*vtr2; + vrl3 = R*(relrot1*ny - relrot2*nx); //- 0.5*((radj-radi)/radsum)*vtr3; vrlmag = sqrt(vrl1*vrl1+vrl2*vrl2+vrl3*vrl3); if (vrlmag != 0.0) vrlmaginv = 1.0/vrlmag; else vrlmaginv = 0.0; - // bond history effects + // Rolling displacement + rollmag = sqrt(shear[3]*shear[3] + shear[4]*shear[4] + shear[5]*shear[5]); + rolldotn = shear[3]*nx + shear[4]*ny + shear[5]*nz; - shear[3] += vrl1*dt; - shear[4] += vrl2*dt; - shear[5] += vrl3*dt; + if (shearupdate) { + if (fabs(rolldotn) < EPSILON) rolldotn = 0; + if (rolldotn > 0){ //Rotate into tangential plane + scalefac = rollmag/(rollmag - rolldotn); + shear[3] -= rolldotn*nx; + shear[4] -= rolldotn*ny; + shear[5] -= rolldotn*nz; + //Also rescale to preserve magnitude + shear[3] *= scalefac; + shear[4] *= scalefac; + shear[5] *= scalefac; + } + shear[3] += vrl1*dt; + shear[4] += vrl2*dt; + shear[5] += vrl3*dt; + } - // rotate bonded displacements correctly + if (rollingdamp == BRILLROLL) etaR = muR*fabs(Fne); + fr1 = -kR*shear[3] - etaR*vrl1; + fr2 = -kR*shear[4] - etaR*vrl2; + fr3 = -kR*shear[5] - etaR*vrl3; - double rlt = shear[3]*dx + shear[4]*dy + shear[5]*dz; - rlt /= rsq; - shear[3] -= rlt*dx; - shear[4] -= rlt*dy; - shear[5] -= rlt*dz; + // rescale frictional displacements and forces if needed + Frcrit = muR * fabs(Fne); - // twisting torque + fr = sqrt(fr1*fr1 + fr2*fr2 + fr3*fr3); + if (fr > Frcrit) { + if (rollmag != 0.0) { + shear[3] = -1.0/kR*(Frcrit*fr1/fr + etaR*vrl1); + shear[4] = -1.0/kR*(Frcrit*fr2/fr + etaR*vrl2); + shear[5] = -1.0/kR*(Frcrit*fr3/fr + etaR*vrl3); + fr1 *= Frcrit/fr; + fr2 *= Frcrit/fr; + fr3 *= Frcrit/fr; + } else fr1 = fr2 = fr3 = 0.0; + } - magtwist = rinv*(relrot1*dx + relrot2*dy + relrot3*dz); + + //**************************************** + // Twisting torque, including shear history effects + //**************************************** + magtwist = relrot1*nx + relrot2*ny + relrot3*nz; //Omega_T (eq 29 of Marshall) shear[6] += magtwist*dt; + k_Q = 0.5*kt*a*a;; //eq 32 + eta_Q = 0.5*eta_T*a*a; + magtortwist = -k_Q*shear[6] - eta_Q*magtwist;//M_t torque (eq 30) - ktwist = 0.5*kt*(a0*aovera0)*(a0*aovera0); - magtortwist = -ktwist*shear[6] - - 0.5*polyhertz*gammatsuji*(a0*aovera0)*(a0*aovera0)*magtwist; + signtwist = (magtwist > 0) - (magtwist < 0); + Mtcrit=TWOTHIRDS*a*Fscrit;//critical torque (eq 44) + if (fabs(magtortwist) > Mtcrit){ + shear[6] = 1.0/k_Q*(Mtcrit*signtwist - eta_Q*magtwist); + magtortwist = -Mtcrit * signtwist; //eq 34 + } - twistcrit=TWOTHIRDS*a0*aovera0*Fcrit; - if (fabs(magtortwist) > twistcrit) - magtortwist = -twistcrit * magtwist/fabs(magtwist); + // Apply forces & torques - // rolling torque - - magrollsq = shear[3]*shear[3] + shear[4]*shear[4] + shear[5]*shear[5]; - magroll = sqrt(magrollsq); - if (magroll != 0.0) magrollinv = 1.0/magroll; - else magrollinv = 0.0; - - kroll = 1.0*4.0*Fcrit*pow(aovera0,1.5); - magtorroll = -kroll*magroll - 0.1*gammat*vrlmag; - - rollcrit = 0.01; - if (magroll > rollcrit) magtorroll = -kroll*rollcrit; - - // forces & torques - - fx = dx*ccel + fs1; - fy = dy*ccel + fs2; - fz = dz*ccel + fs3; + fx = nx*Fntot + fs1; + fy = ny*Fntot + fs2; + fz = nz*Fntot + fs3; f[0] += fx; f[1] += fy; f[2] += fz; - if (peratom_flag){ - contact[1] = fx; - contact[2] = fy; - contact[3] = fz; - } + tor1 = ny*fs3 - nz*fs2; + tor2 = nz*fs1 - nx*fs3; + tor3 = nx*fs2 - ny*fs1; - tor1 = rinv * (dy*fs3 - dz*fs2); - tor2 = rinv * (dz*fs1 - dx*fs3); - tor3 = rinv * (dx*fs2 - dy*fs1); - torque[0] -= radius*tor1; - torque[1] -= radius*tor2; - torque[2] -= radius*tor3; + torque[0] -= radi*tor1; + torque[1] -= radi*tor2; + torque[2] -= radi*tor3; - torque[0] += magtortwist * dx*rinv; - torque[1] += magtortwist * dy*rinv; - torque[2] += magtortwist * dz*rinv; + tortwist1 = magtortwist * nx; + tortwist2 = magtortwist * ny; + tortwist3 = magtortwist * nz; + + torque[0] += tortwist1; + torque[1] += tortwist2; + torque[2] += tortwist3; + + torroll1 = R*(ny*fr3 - nz*fr2); //n cross fr + torroll2 = R*(nz*fr1 - nx*fr3); + torroll3 = R*(nx*fr2 - ny*fr1); + + torque[0] += torroll1; + torque[1] += torroll2; + torque[2] += torroll3; - torque[0] += magtorroll * (shear[4]*dz - shear[5]*dy)*rinv*magrollinv; - torque[1] += magtorroll * (shear[5]*dx - shear[3]*dz)*rinv*magrollinv; - torque[2] += magtorroll * (shear[3]*dy - shear[4]*dx)*rinv*magrollinv; } + /* ---------------------------------------------------------------------- memory usage of local atom-based arrays ------------------------------------------------------------------------- */ @@ -1108,8 +1153,8 @@ void FixWallGran::copy_arrays(int i, int j, int delflag) for (int m = 0; m < sheardim; m++) shearone[j][m] = shearone[i][m]; if (peratom_flag){ - for (int m = 0; m < size_peratom_cols; m++) - array_atom[j][m] = array_atom[i][m]; + for (int m = 0; m < size_peratom_cols; m++) + array_atom[j][m] = array_atom[i][m]; } } @@ -1124,7 +1169,7 @@ void FixWallGran::set_arrays(int i) shearone[i][m] = 0; if (peratom_flag){ for (int m = 0; m < size_peratom_cols; m++) - array_atom[i][m] = 0; + array_atom[i][m] = 0; } } diff --git a/src/GRANULAR/fix_wall_gran.h b/src/GRANULAR/fix_wall_gran.h index f1a5dbc842..4212b96544 100644 --- a/src/GRANULAR/fix_wall_gran.h +++ b/src/GRANULAR/fix_wall_gran.h @@ -47,23 +47,31 @@ class FixWallGran : public Fix { void reset_dt(); void hooke(double, double, double, double, double *, - double *, double *, double *, double *, double, double, double*); + double *, double *, double *, double *, double, double, double*); void hooke_history(double, double, double, double, double *, - double *, double *, double *, double *, double, double, - double *, double *); + double *, double *, double *, double *, double, double, + double *, double *); void hertz_history(double, double, double, double, double *, double, - double *, double *, double *, double *, double, double, - double *, double *); - void bonded_history(double, double, double, double, double *, double, - double *, double *, double *, double *, double, double, - double *, double *); + double *, double *, double *, double *, double, double, + double *, double *); + void dmt_rolling(double, double, double, double, double *, double, + double *, double *, double *, double *, double, double, + double *, double *); + // void jkr_rolling(double, double, double, double, double *, double, + // double *, double *, double *, double *, double, double, + // double *, double *); protected: int wallstyle,wiggle,wshear,axis; int pairstyle,nlevels_respa; bigint time_origin; double kn,kt,gamman,gammat,xmu; - double E,G,SurfEnergy; + + //For DMT/ROLLING + int normaldamp, rollingdamp; + double Emod, Gmod, alpha, Ecoh, kR, muR, etaR; + + double lo,hi,cylradius; double amplitude,period,omega,vshear; double dt; diff --git a/src/GRANULAR/fix_wall_gran_region.cpp b/src/GRANULAR/fix_wall_gran_region.cpp index e00036c26a..71b6503f36 100644 --- a/src/GRANULAR/fix_wall_gran_region.cpp +++ b/src/GRANULAR/fix_wall_gran_region.cpp @@ -39,15 +39,15 @@ using namespace MathConst; // same as FixWallGran -enum{HOOKE,HOOKE_HISTORY,HERTZ_HISTORY,BONDED_HISTORY}; +enum{HOOKE,HOOKE_HISTORY,HERTZ_HISTORY,JKR_ROLLING,DMT_ROLLING}; #define BIG 1.0e20 /* ---------------------------------------------------------------------- */ FixWallGranRegion::FixWallGranRegion(LAMMPS *lmp, int narg, char **arg) : - FixWallGran(lmp, narg, arg), region(NULL), region_style(NULL), ncontact(NULL), - walls(NULL), shearmany(NULL), c2r(NULL) + FixWallGran(lmp, narg, arg), region(NULL), region_style(NULL), ncontact(NULL), + walls(NULL), shearmany(NULL), c2r(NULL) { restart_global = 1; motion_resetflag = 0; @@ -114,7 +114,7 @@ void FixWallGranRegion::init() nregion != region->nregion) { char str[256]; sprintf(str,"Region properties for region %s changed between runs, " - "resetting its motion",idregion); + "resetting its motion",idregion); error->warning(FLERR,str); region->reset_vel(); } @@ -122,7 +122,7 @@ void FixWallGranRegion::init() if (motion_resetflag){ char str[256]; sprintf(str,"Region properties for region %s are inconsistent " - "with restart file, resetting its motion",idregion); + "with restart file, resetting its motion",idregion); error->warning(FLERR,str); region->reset_vel(); } @@ -253,22 +253,22 @@ void FixWallGranRegion::post_force(int vflag) contact = array_atom[i]; else contact = NULL; - + if (pairstyle == HOOKE) hooke(rsq,dx,dy,dz,vwall,v[i],f[i], - omega[i],torque[i],radius[i],meff, contact); + omega[i],torque[i],radius[i],meff, contact); else if (pairstyle == HOOKE_HISTORY) hooke_history(rsq,dx,dy,dz,vwall,v[i],f[i], - omega[i],torque[i],radius[i],meff, - shearmany[i][c2r[ic]], contact); + omega[i],torque[i],radius[i],meff, + shearmany[i][c2r[ic]], contact); else if (pairstyle == HERTZ_HISTORY) hertz_history(rsq,dx,dy,dz,vwall,region->contact[ic].radius, - v[i],f[i],omega[i],torque[i], - radius[i],meff,shearmany[i][c2r[ic]], contact); - else if (pairstyle == BONDED_HISTORY) - bonded_history(rsq,dx,dy,dz,vwall,region->contact[ic].radius, - v[i],f[i],omega[i],torque[i], - radius[i],meff,shearmany[i][c2r[ic]], contact); + v[i],f[i],omega[i],torque[i], + radius[i],meff,shearmany[i][c2r[ic]], contact); + else if (pairstyle == DMT_ROLLING) + dmt_rolling(rsq,dx,dy,dz,vwall,region->contact[ic].radius, + v[i],f[i],omega[i],torque[i], + radius[i],meff,shearmany[i][c2r[ic]], contact); } } } @@ -394,7 +394,7 @@ void FixWallGranRegion::set_arrays(int i) ncontact[i] = 0; if (peratom_flag){ for (int m = 0; m < size_peratom_cols; m++) - array_atom[i][m] = 0; + array_atom[i][m] = 0; } } diff --git a/src/GRANULAR/pair_gran_dmt_rolling.cpp b/src/GRANULAR/pair_gran_dmt_rolling.cpp index 08299f85b5..7a71fc7200 100644 --- a/src/GRANULAR/pair_gran_dmt_rolling.cpp +++ b/src/GRANULAR/pair_gran_dmt_rolling.cpp @@ -44,9 +44,9 @@ enum {INDEP, BRILLROLL}; /* ---------------------------------------------------------------------- */ PairGranDMTRolling::PairGranDMTRolling(LAMMPS *lmp) : - PairGranHookeHistory(lmp, 7), - E_one(0), G_one(0), pois(0), muS_one(0), cor(0), alpha_one(0), - Ecoh_one(0), kR_one(0), muR_one(0), etaR_one(0) + PairGranHookeHistory(lmp, 7), + E_one(0), G_one(0), pois(0), muS_one(0), cor(0), alpha_one(0), + Ecoh_one(0), kR_one(0), muR_one(0), etaR_one(0) { int ntypes = atom->ntypes; memory->create(E,ntypes+1,ntypes+1,"pair:E"); @@ -122,19 +122,19 @@ void PairGranDMTRolling::compute(int eflag, int vflag) // mass_body = mass of each rigid body if (fix_rigid && neighbor->ago == 0){ - int tmp; - int *body = (int *) fix_rigid->extract("body",tmp); - double *mass_body = (double *) fix_rigid->extract("masstotal",tmp); - if (atom->nmax > nmax) { - memory->destroy(mass_rigid); - nmax = atom->nmax; - memory->create(mass_rigid,nmax,"pair:mass_rigid"); - } - int nlocal = atom->nlocal; - for (i = 0; i < nlocal; i++) - if (body[i] >= 0) mass_rigid[i] = mass_body[body[i]]; - else mass_rigid[i] = 0.0; - comm->forward_comm_pair(this); + int tmp; + int *body = (int *) fix_rigid->extract("body",tmp); + double *mass_body = (double *) fix_rigid->extract("masstotal",tmp); + if (atom->nmax > nmax) { + memory->destroy(mass_rigid); + nmax = atom->nmax; + memory->create(mass_rigid,nmax,"pair:mass_rigid"); + } + int nlocal = atom->nlocal; + for (i = 0; i < nlocal; i++) + if (body[i] >= 0) mass_rigid[i] = mass_body[body[i]]; + else mass_rigid[i] = 0.0; + comm->forward_comm_pair(this); } double **x = atom->x; @@ -158,304 +158,304 @@ void PairGranDMTRolling::compute(int eflag, int vflag) // loop over neighbors of my atoms for (ii = 0; ii < inum; ii++) { - i = ilist[ii]; - itype = type[i]; - xtmp = x[i][0]; - ytmp = x[i][1]; - ztmp = x[i][2]; - radi = radius[i]; - touch = firsttouch[i]; - allshear = firstshear[i]; - jlist = firstneigh[i]; - jnum = numneigh[i]; + i = ilist[ii]; + itype = type[i]; + xtmp = x[i][0]; + ytmp = x[i][1]; + ztmp = x[i][2]; + radi = radius[i]; + touch = firsttouch[i]; + allshear = firstshear[i]; + jlist = firstneigh[i]; + jnum = numneigh[i]; - for (jj = 0; jj < jnum; jj++) { - j = jlist[jj]; - jtype = type[j]; - j &= NEIGHMASK; + for (jj = 0; jj < jnum; jj++) { + j = jlist[jj]; + jtype = type[j]; + j &= NEIGHMASK; - delx = xtmp - x[j][0]; - dely = ytmp - x[j][1]; - delz = ztmp - x[j][2]; - rsq = delx*delx + dely*dely + delz*delz; - radj = radius[j]; - radsum = radi + radj; + delx = xtmp - x[j][0]; + dely = ytmp - x[j][1]; + delz = ztmp - x[j][2]; + rsq = delx*delx + dely*dely + delz*delz; + radj = radius[j]; + radsum = radi + radj; - if (rsq >= radsum*radsum){ - // unset non-touching neighbors - touch[jj] = 0; - shear = &allshear[size_history*jj]; - for (int k = 0; k < size_history; k++) - shear[k] = 0.0; - } else { - r = sqrt(rsq); - rinv = 1.0/r; - rsqinv = 1.0/rsq; - R = radi*radj/(radi+radj); - nx = delx*rinv; - ny = dely*rinv; - nz = delz*rinv; + if (rsq >= radsum*radsum){ + // unset non-touching neighbors + touch[jj] = 0; + shear = &allshear[size_history*jj]; + for (int k = 0; k < size_history; k++) + shear[k] = 0.0; + } else { + r = sqrt(rsq); + rinv = 1.0/r; + rsqinv = 1.0/rsq; + R = radi*radj/(radi+radj); + nx = delx*rinv; + ny = dely*rinv; + nz = delz*rinv; - // relative translational velocity + // relative translational velocity - vr1 = v[i][0] - v[j][0]; - vr2 = v[i][1] - v[j][1]; - vr3 = v[i][2] - v[j][2]; + vr1 = v[i][0] - v[j][0]; + vr2 = v[i][1] - v[j][1]; + vr3 = v[i][2] - v[j][2]; - // normal component + // normal component - vnnr = vr1*nx + vr2*ny + vr3*nz; //v_R . n - vn1 = nx*vnnr; - vn2 = ny*vnnr; - vn3 = nz*vnnr; + vnnr = vr1*nx + vr2*ny + vr3*nz; //v_R . n + vn1 = nx*vnnr; + vn2 = ny*vnnr; + vn3 = nz*vnnr; - // meff = effective mass of pair of particles - // if I or J part of rigid body, use body mass - // if I or J is frozen, meff is other particle + // meff = effective mass of pair of particles + // if I or J part of rigid body, use body mass + // if I or J is frozen, meff is other particle - mi = rmass[i]; - mj = rmass[j]; - if (fix_rigid) { - if (mass_rigid[i] > 0.0) mi = mass_rigid[i]; - if (mass_rigid[j] > 0.0) mj = mass_rigid[j]; - } + mi = rmass[i]; + mj = rmass[j]; + if (fix_rigid) { + if (mass_rigid[i] > 0.0) mi = mass_rigid[i]; + if (mass_rigid[j] > 0.0) mj = mass_rigid[j]; + } - meff = mi*mj / (mi+mj); - if (mask[i] & freeze_group_bit) meff = mj; - if (mask[j] & freeze_group_bit) meff = mi; + meff = mi*mj / (mi+mj); + if (mask[i] & freeze_group_bit) meff = mj; + if (mask[j] & freeze_group_bit) meff = mi; - //**************************************** - //Normal force = Hertzian contact + DMT + damping - //**************************************** - overlap = radsum - r; - a = sqrt(R*overlap); - kn = 4.0/3.0*E[itype][jtype]*a; - Fhz = kn*overlap; + //**************************************** + //Normal force = Hertzian contact + DMT + damping + //**************************************** + overlap = radsum - r; + a = sqrt(R*overlap); + kn = 4.0/3.0*E[itype][jtype]*a; + Fhz = kn*overlap; - //Damping (based on Tsuji et al) - if (normaldamp == BRILLIANTOV) eta_N = a*meff*gamman[itype][jtype]; - else if (normaldamp == TSUJI) eta_N=alpha[itype][jtype]*sqrt(meff*kn); + //Damping (based on Tsuji et al) + if (normaldamp == BRILLIANTOV) eta_N = a*meff*gamman[itype][jtype]; + else if (normaldamp == TSUJI) eta_N=alpha[itype][jtype]*sqrt(meff*kn); - Fdamp = -eta_N*vnnr; //F_nd eq 23 and Zhao eq 19 + Fdamp = -eta_N*vnnr; //F_nd eq 23 and Zhao eq 19 - //DMT - Fdmt = -4*MY_PI*Ecoh[itype][jtype]*R; + //DMT + Fdmt = -4*MY_PI*Ecoh[itype][jtype]*R; - Fne = Fhz + Fdmt; - Fntot = Fne + Fdamp; + Fne = Fhz + Fdmt; + Fntot = Fne + Fdamp; - //**************************************** - //Tangential force, including shear history effects - //**************************************** + //**************************************** + //Tangential force, including shear history effects + //**************************************** - // tangential component - vt1 = vr1 - vn1; - vt2 = vr2 - vn2; - vt3 = vr3 - vn3; + // tangential component + vt1 = vr1 - vn1; + vt2 = vr2 - vn2; + vt3 = vr3 - vn3; - // relative rotational velocity - //Luding Gran Matt 2008, v10,p235 suggests correcting radi and radj by subtracting - //delta/2, i.e. instead of radi, use distance to center of contact point? - wr1 = (radi*omega[i][0] + radj*omega[j][0]); - wr2 = (radi*omega[i][1] + radj*omega[j][1]); - wr3 = (radi*omega[i][2] + radj*omega[j][2]); + // relative rotational velocity + //Luding Gran Matt 2008, v10,p235 suggests correcting radi and radj by subtracting + //delta/2, i.e. instead of radi, use distance to center of contact point? + wr1 = (radi*omega[i][0] + radj*omega[j][0]); + wr2 = (radi*omega[i][1] + radj*omega[j][1]); + wr3 = (radi*omega[i][2] + radj*omega[j][2]); - // relative tangential velocities - vtr1 = vt1 - (nz*wr2-ny*wr3); - vtr2 = vt2 - (nx*wr3-nz*wr1); - vtr3 = vt3 - (ny*wr1-nx*wr2); - vrel = vtr1*vtr1 + vtr2*vtr2 + vtr3*vtr3; - vrel = sqrt(vrel); + // relative tangential velocities + vtr1 = vt1 - (nz*wr2-ny*wr3); + vtr2 = vt2 - (nx*wr3-nz*wr1); + vtr3 = vt3 - (ny*wr1-nx*wr2); + vrel = vtr1*vtr1 + vtr2*vtr2 + vtr3*vtr3; + vrel = sqrt(vrel); - // shear history effects - touch[jj] = 1; - shear = &allshear[size_history*jj]; - shrmag = sqrt(shear[0]*shear[0] + shear[1]*shear[1] + - shear[2]*shear[2]); + // shear history effects + touch[jj] = 1; + shear = &allshear[size_history*jj]; + shrmag = sqrt(shear[0]*shear[0] + shear[1]*shear[1] + + shear[2]*shear[2]); - // Rotate and update shear displacements. - // See e.g. eq. 17 of Luding, Gran. Matter 2008, v10,p235 - if (shearupdate) { - rsht = shear[0]*nx + shear[1]*ny + shear[2]*nz; - if (fabs(rsht) < EPSILON) rsht = 0; - if (rsht > 0){ - scalefac = shrmag/(shrmag - rsht); //if rhst == shrmag, contacting pair has rotated 90 deg. in one step, in which case you deserve a crash! - shear[0] -= rsht*nx; - shear[1] -= rsht*ny; - shear[2] -= rsht*nz; - //Also rescale to preserve magnitude - shear[0] *= scalefac; - shear[1] *= scalefac; - shear[2] *= scalefac; - } - //Update shear history - shear[0] += vtr1*dt; - shear[1] += vtr2*dt; - shear[2] += vtr3*dt; - } + // Rotate and update shear displacements. + // See e.g. eq. 17 of Luding, Gran. Matter 2008, v10,p235 + if (shearupdate) { + rsht = shear[0]*nx + shear[1]*ny + shear[2]*nz; + if (fabs(rsht) < EPSILON) rsht = 0; + if (rsht > 0){ + scalefac = shrmag/(shrmag - rsht); //if rhst == shrmag, contacting pair has rotated 90 deg. in one step, in which case you deserve a crash! + shear[0] -= rsht*nx; + shear[1] -= rsht*ny; + shear[2] -= rsht*nz; + //Also rescale to preserve magnitude + shear[0] *= scalefac; + shear[1] *= scalefac; + shear[2] *= scalefac; + } + //Update shear history + shear[0] += vtr1*dt; + shear[1] += vtr2*dt; + shear[2] += vtr3*dt; + } - // tangential forces = shear + tangential velocity damping - // following Zhao and Marshall Phys Fluids v20, p043302 (2008) - kt=8.0*G[itype][jtype]*a; + // tangential forces = shear + tangential velocity damping + // following Zhao and Marshall Phys Fluids v20, p043302 (2008) + kt=8.0*G[itype][jtype]*a; - eta_T = eta_N; //Based on discussion in Marshall; eta_T can also be an independent parameter - fs1 = -kt*shear[0] - eta_T*vtr1; //eq 26 - fs2 = -kt*shear[1] - eta_T*vtr2; - fs3 = -kt*shear[2] - eta_T*vtr3; + eta_T = eta_N; //Based on discussion in Marshall; eta_T can also be an independent parameter + fs1 = -kt*shear[0] - eta_T*vtr1; //eq 26 + fs2 = -kt*shear[1] - eta_T*vtr2; + fs3 = -kt*shear[2] - eta_T*vtr3; - // rescale frictional displacements and forces if needed - Fscrit = muS[itype][jtype] * fabs(Fne); - // For JKR, use eq 43 of Marshall. For DMT, use Fne instead - shrmag = sqrt(shear[0]*shear[0] + shear[1]*shear[1] + - shear[2]*shear[2]); - fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); - if (fs > Fscrit) { - if (shrmag != 0.0) { - //shear[0] = (Fcrit/fs) * (shear[0] + eta_T*vtr1/kt) - eta_T*vtr1/kt; - //shear[1] = (Fcrit/fs) * (shear[1] + eta_T*vtr1/kt) - eta_T*vtr1/kt; - //shear[2] = (Fcrit/fs) * (shear[2] + eta_T*vtr1/kt) - eta_T*vtr1/kt; - shear[0] = -1.0/kt*(Fscrit*fs1/fs + eta_T*vtr1); //Same as above, but simpler (check!) - shear[1] = -1.0/kt*(Fscrit*fs2/fs + eta_T*vtr2); - shear[2] = -1.0/kt*(Fscrit*fs3/fs + eta_T*vtr3); - fs1 *= Fscrit/fs; - fs2 *= Fscrit/fs; - fs3 *= Fscrit/fs; - } else fs1 = fs2 = fs3 = 0.0; - } + // rescale frictional displacements and forces if needed + Fscrit = muS[itype][jtype] * fabs(Fne); + // For JKR, use eq 43 of Marshall. For DMT, use Fne instead + shrmag = sqrt(shear[0]*shear[0] + shear[1]*shear[1] + + shear[2]*shear[2]); + fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); + if (fs > Fscrit) { + if (shrmag != 0.0) { + //shear[0] = (Fcrit/fs) * (shear[0] + eta_T*vtr1/kt) - eta_T*vtr1/kt; + //shear[1] = (Fcrit/fs) * (shear[1] + eta_T*vtr1/kt) - eta_T*vtr1/kt; + //shear[2] = (Fcrit/fs) * (shear[2] + eta_T*vtr1/kt) - eta_T*vtr1/kt; + shear[0] = -1.0/kt*(Fscrit*fs1/fs + eta_T*vtr1); //Same as above, but simpler (check!) + shear[1] = -1.0/kt*(Fscrit*fs2/fs + eta_T*vtr2); + shear[2] = -1.0/kt*(Fscrit*fs3/fs + eta_T*vtr3); + fs1 *= Fscrit/fs; + fs2 *= Fscrit/fs; + fs3 *= Fscrit/fs; + } else fs1 = fs2 = fs3 = 0.0; + } - //**************************************** - // Rolling force, including shear history effects - //**************************************** + //**************************************** + // Rolling force, including shear history effects + //**************************************** - relrot1 = omega[i][0] - omega[j][0]; - relrot2 = omega[i][1] - omega[j][1]; - relrot3 = omega[i][2] - omega[j][2]; + relrot1 = omega[i][0] - omega[j][0]; + relrot2 = omega[i][1] - omega[j][1]; + relrot3 = omega[i][2] - omega[j][2]; - // rolling velocity, see eq. 31 of Wang et al, Particuology v 23, p 49 (2015) - // This is different from the Marshall papers, which use the Bagi/Kuhn formulation - // for rolling velocity (see Wang et al for why the latter is wrong) - vrl1 = R*(relrot2*nz - relrot3*ny); //- 0.5*((radj-radi)/radsum)*vtr1; - vrl2 = R*(relrot3*nx - relrot1*nz); //- 0.5*((radj-radi)/radsum)*vtr2; - vrl3 = R*(relrot1*ny - relrot2*nx); //- 0.5*((radj-radi)/radsum)*vtr3; - vrlmag = sqrt(vrl1*vrl1+vrl2*vrl2+vrl3*vrl3); - if (vrlmag != 0.0) vrlmaginv = 1.0/vrlmag; - else vrlmaginv = 0.0; + // rolling velocity, see eq. 31 of Wang et al, Particuology v 23, p 49 (2015) + // This is different from the Marshall papers, which use the Bagi/Kuhn formulation + // for rolling velocity (see Wang et al for why the latter is wrong) + vrl1 = R*(relrot2*nz - relrot3*ny); //- 0.5*((radj-radi)/radsum)*vtr1; + vrl2 = R*(relrot3*nx - relrot1*nz); //- 0.5*((radj-radi)/radsum)*vtr2; + vrl3 = R*(relrot1*ny - relrot2*nx); //- 0.5*((radj-radi)/radsum)*vtr3; + vrlmag = sqrt(vrl1*vrl1+vrl2*vrl2+vrl3*vrl3); + if (vrlmag != 0.0) vrlmaginv = 1.0/vrlmag; + else vrlmaginv = 0.0; - // Rolling displacement - rollmag = sqrt(shear[3]*shear[3] + shear[4]*shear[4] + shear[5]*shear[5]); - rolldotn = shear[3]*nx + shear[4]*ny + shear[5]*nz; + // Rolling displacement + rollmag = sqrt(shear[3]*shear[3] + shear[4]*shear[4] + shear[5]*shear[5]); + rolldotn = shear[3]*nx + shear[4]*ny + shear[5]*nz; - if (shearupdate) { - if (fabs(rolldotn) < EPSILON) rolldotn = 0; - if (rolldotn > 0){ //Rotate into tangential plane - scalefac = rollmag/(rollmag - rolldotn); - shear[3] -= rolldotn*nx; - shear[4] -= rolldotn*ny; - shear[5] -= rolldotn*nz; - //Also rescale to preserve magnitude - shear[3] *= scalefac; - shear[4] *= scalefac; - shear[5] *= scalefac; - } - shear[3] += vrl1*dt; - shear[4] += vrl2*dt; - shear[5] += vrl3*dt; - } + if (shearupdate) { + if (fabs(rolldotn) < EPSILON) rolldotn = 0; + if (rolldotn > 0){ //Rotate into tangential plane + scalefac = rollmag/(rollmag - rolldotn); + shear[3] -= rolldotn*nx; + shear[4] -= rolldotn*ny; + shear[5] -= rolldotn*nz; + //Also rescale to preserve magnitude + shear[3] *= scalefac; + shear[4] *= scalefac; + shear[5] *= scalefac; + } + shear[3] += vrl1*dt; + shear[4] += vrl2*dt; + shear[5] += vrl3*dt; + } - k_R = kR[itype][jtype]; - if (rollingdamp == INDEP) eta_R = etaR[itype][jtype]; - else if (rollingdamp == BRILLROLL) eta_R = muR[itype][jtype]*fabs(Fne); - fr1 = -k_R*shear[3] - eta_R*vrl1; - fr2 = -k_R*shear[4] - eta_R*vrl2; - fr3 = -k_R*shear[5] - eta_R*vrl3; + k_R = kR[itype][jtype]; + if (rollingdamp == INDEP) eta_R = etaR[itype][jtype]; + else if (rollingdamp == BRILLROLL) eta_R = muR[itype][jtype]*fabs(Fne); + fr1 = -k_R*shear[3] - eta_R*vrl1; + fr2 = -k_R*shear[4] - eta_R*vrl2; + fr3 = -k_R*shear[5] - eta_R*vrl3; - // rescale frictional displacements and forces if needed - Frcrit = muR[itype][jtype] * fabs(Fne); + // rescale frictional displacements and forces if needed + Frcrit = muR[itype][jtype] * fabs(Fne); - fr = sqrt(fr1*fr1 + fr2*fr2 + fr3*fr3); - if (fr > Frcrit) { - if (rollmag != 0.0) { - shear[3] = -1.0/k_R*(Frcrit*fr1/fr + eta_R*vrl1); - shear[4] = -1.0/k_R*(Frcrit*fr2/fr + eta_R*vrl2); - shear[5] = -1.0/k_R*(Frcrit*fr3/fr + eta_R*vrl3); - fr1 *= Frcrit/fr; - fr2 *= Frcrit/fr; - fr3 *= Frcrit/fr; - } else fr1 = fr2 = fr3 = 0.0; - } + fr = sqrt(fr1*fr1 + fr2*fr2 + fr3*fr3); + if (fr > Frcrit) { + if (rollmag != 0.0) { + shear[3] = -1.0/k_R*(Frcrit*fr1/fr + eta_R*vrl1); + shear[4] = -1.0/k_R*(Frcrit*fr2/fr + eta_R*vrl2); + shear[5] = -1.0/k_R*(Frcrit*fr3/fr + eta_R*vrl3); + fr1 *= Frcrit/fr; + fr2 *= Frcrit/fr; + fr3 *= Frcrit/fr; + } else fr1 = fr2 = fr3 = 0.0; + } - //**************************************** - // Twisting torque, including shear history effects - //**************************************** - magtwist = relrot1*nx + relrot2*ny + relrot3*nz; //Omega_T (eq 29 of Marshall) - shear[6] += magtwist*dt; - k_Q = 0.5*kt*a*a;; //eq 32 - eta_Q = 0.5*eta_T*a*a; - magtortwist = -k_Q*shear[6] - eta_Q*magtwist;//M_t torque (eq 30) + //**************************************** + // Twisting torque, including shear history effects + //**************************************** + magtwist = relrot1*nx + relrot2*ny + relrot3*nz; //Omega_T (eq 29 of Marshall) + shear[6] += magtwist*dt; + k_Q = 0.5*kt*a*a;; //eq 32 + eta_Q = 0.5*eta_T*a*a; + magtortwist = -k_Q*shear[6] - eta_Q*magtwist;//M_t torque (eq 30) - signtwist = (magtwist > 0) - (magtwist < 0); - Mtcrit=TWOTHIRDS*a*Fscrit;//critical torque (eq 44) - if (fabs(magtortwist) > Mtcrit){ - shear[6] = 1.0/k_Q*(Mtcrit*signtwist - eta_Q*magtwist); - magtortwist = -Mtcrit * signtwist; //eq 34 - } + signtwist = (magtwist > 0) - (magtwist < 0); + Mtcrit=TWOTHIRDS*a*Fscrit;//critical torque (eq 44) + if (fabs(magtortwist) > Mtcrit){ + shear[6] = 1.0/k_Q*(Mtcrit*signtwist - eta_Q*magtwist); + magtortwist = -Mtcrit * signtwist; //eq 34 + } - // Apply forces & torques + // Apply forces & torques - fx = nx*Fntot + fs1; - fy = ny*Fntot + fs2; - fz = nz*Fntot + fs3; + fx = nx*Fntot + fs1; + fy = ny*Fntot + fs2; + fz = nz*Fntot + fs3; - f[i][0] += fx; - f[i][1] += fy; - f[i][2] += fz; + f[i][0] += fx; + f[i][1] += fy; + f[i][2] += fz; - tor1 = ny*fs3 - nz*fs2; - tor2 = nz*fs1 - nx*fs3; - tor3 = nx*fs2 - ny*fs1; + tor1 = ny*fs3 - nz*fs2; + tor2 = nz*fs1 - nx*fs3; + tor3 = nx*fs2 - ny*fs1; - torque[i][0] -= radi*tor1; - torque[i][1] -= radi*tor2; - torque[i][2] -= radi*tor3; + torque[i][0] -= radi*tor1; + torque[i][1] -= radi*tor2; + torque[i][2] -= radi*tor3; - tortwist1 = magtortwist * nx; - tortwist2 = magtortwist * ny; - tortwist3 = magtortwist * nz; + tortwist1 = magtortwist * nx; + tortwist2 = magtortwist * ny; + tortwist3 = magtortwist * nz; - torque[i][0] += tortwist1; - torque[i][1] += tortwist2; - torque[i][2] += tortwist3; + torque[i][0] += tortwist1; + torque[i][1] += tortwist2; + torque[i][2] += tortwist3; - torroll1 = R*(ny*fr3 - nz*fr2); //n cross fr - torroll2 = R*(nz*fr1 - nx*fr3); - torroll3 = R*(nx*fr2 - ny*fr1); + torroll1 = R*(ny*fr3 - nz*fr2); //n cross fr + torroll2 = R*(nz*fr1 - nx*fr3); + torroll3 = R*(nx*fr2 - ny*fr1); - torque[i][0] += torroll1; - torque[i][1] += torroll2; - torque[i][2] += torroll3; + torque[i][0] += torroll1; + torque[i][1] += torroll2; + torque[i][2] += torroll3; - if (force->newton_pair || j < nlocal) { - f[j][0] -= fx; - f[j][1] -= fy; - f[j][2] -= fz; + if (force->newton_pair || j < nlocal) { + f[j][0] -= fx; + f[j][1] -= fy; + f[j][2] -= fz; - torque[j][0] -= radj*tor1; - torque[j][1] -= radj*tor2; - torque[j][2] -= radj*tor3; + torque[j][0] -= radj*tor1; + torque[j][1] -= radj*tor2; + torque[j][2] -= radj*tor3; - torque[j][0] -= tortwist1; - torque[j][1] -= tortwist2; - torque[j][2] -= tortwist3; + torque[j][0] -= tortwist1; + torque[j][1] -= tortwist2; + torque[j][2] -= tortwist3; - torque[j][0] -= torroll1; - torque[j][1] -= torroll2; - torque[j][2] -= torroll3; - } - if (evflag) ev_tally_xyz(i,j,nlocal,0, - 0.0,0.0,fx,fy,fz,delx,dely,delz); - } + torque[j][0] -= torroll1; + torque[j][1] -= torroll2; + torque[j][2] -= torroll3; + } + if (evflag) ev_tally_xyz(i,j,nlocal,0, + 0.0,0.0,fx,fy,fz,delx,dely,delz); } + } } } @@ -483,14 +483,14 @@ void PairGranDMTRolling::settings(int narg, char **arg) etaR_one = new double[ntypes+1]; for (int i=0; i < ntypes;i++){ - E_one[i+1] = force->numeric(FLERR, arg[i]); - G_one[i+1] = force->numeric(FLERR, arg[ntypes+i]); - muS_one[i+1] = force->numeric(FLERR, arg[2*ntypes+i]); - cor[i+1] = force->numeric(FLERR, arg[3*ntypes+i]); - Ecoh_one[i+1] = force->numeric(FLERR, arg[4*ntypes+i]); - kR_one[i+1] = force->numeric(FLERR, arg[5*ntypes+i]); - muR_one[i+1] = force->numeric(FLERR, arg[6*ntypes+i]); - etaR_one[i+1] = force->numeric(FLERR, arg[7*ntypes+i]); + E_one[i+1] = force->numeric(FLERR, arg[i]); + G_one[i+1] = force->numeric(FLERR, arg[ntypes+i]); + muS_one[i+1] = force->numeric(FLERR, arg[2*ntypes+i]); + cor[i+1] = force->numeric(FLERR, arg[3*ntypes+i]); + Ecoh_one[i+1] = force->numeric(FLERR, arg[4*ntypes+i]); + kR_one[i+1] = force->numeric(FLERR, arg[5*ntypes+i]); + muR_one[i+1] = force->numeric(FLERR, arg[6*ntypes+i]); + etaR_one[i+1] = force->numeric(FLERR, arg[7*ntypes+i]); } //Defaults @@ -499,53 +499,53 @@ void PairGranDMTRolling::settings(int narg, char **arg) int iarg = 8*ntypes; while (iarg < narg){ - if (strcmp(arg[iarg],"normaldamp") == 0){ - if (iarg+2 > narg) error->all(FLERR, "Invalid pair/gran/dmt/rolling entry"); - if (strcmp(arg[iarg+1],"tsuji") == 0) normaldamp = TSUJI; - else if (strcmp(arg[iarg+1],"brilliantov") == 0) normaldamp = BRILLIANTOV; - else error->all(FLERR, "Invalid normal damping model for pair/gran/dmt/rolling"); - iarg += 2; - } - else if (strcmp(arg[iarg],"rollingdamp") == 0){ - if (iarg+2 > narg) error->all(FLERR, "Invalid pair/gran/dmt/rolling entry"); - if (strcmp(arg[iarg+1],"independent") == 0) rollingdamp = INDEP; - else if (strcmp(arg[iarg+1],"brilliantov") == 0) rollingdamp = BRILLROLL; - else error->all(FLERR, "Invalid rolling damping model for pair/gran/dmt/rolling"); - iarg += 2; - } - else{ - iarg +=1; - } + if (strcmp(arg[iarg],"normaldamp") == 0){ + if (iarg+2 > narg) error->all(FLERR, "Invalid pair/gran/dmt/rolling entry"); + if (strcmp(arg[iarg+1],"tsuji") == 0) normaldamp = TSUJI; + else if (strcmp(arg[iarg+1],"brilliantov") == 0) normaldamp = BRILLIANTOV; + else error->all(FLERR, "Invalid normal damping model for pair/gran/dmt/rolling"); + iarg += 2; + } + else if (strcmp(arg[iarg],"rollingdamp") == 0){ + if (iarg+2 > narg) error->all(FLERR, "Invalid pair/gran/dmt/rolling entry"); + if (strcmp(arg[iarg+1],"independent") == 0) rollingdamp = INDEP; + else if (strcmp(arg[iarg+1],"brilliantov") == 0) rollingdamp = BRILLROLL; + else error->all(FLERR, "Invalid rolling damping model for pair/gran/dmt/rolling"); + iarg += 2; + } + else{ + iarg +=1; + } } //Derived from inputs for (int i=1; i <= ntypes; i++){ - pois[i] = E_one[i]/(2.0*G_one[i]) - 1.0; - alpha_one[i] = 1.2728-4.2783*cor[i]+11.087*cor[i]*cor[i]-22.348*cor[i]*cor[i]*cor[i]+27.467*cor[i]*cor[i]*cor[i]*cor[i]-18.022*cor[i]*cor[i]*cor[i]*cor[i]*cor[i]+4.8218*cor[i]*cor[i]*cor[i]*cor[i]*cor[i]*cor[i]; - for (int j=i; j <= ntypes; j++){ - E[i][j] = E[j][i] = 1/((1-pois[i]*pois[i])/E_one[i]+(1-pois[j]*pois[j])/E_one[j]); - G[i][j] = G[j][i] = 1/((2-pois[i])/G_one[i]+(2-pois[j])/G_one[j]); - if (normaldamp == TSUJI){ - alpha[i][j] = alpha[j][i] = sqrt(alpha_one[i]*alpha_one[j]); - } - else if (normaldamp == BRILLIANTOV){ - gamman[i][j] = gamman[j][i] = sqrt(cor[i]*cor[j]); - } - muS[i][j] = muS[j][i] = sqrt(muS_one[i]*muS_one[j]); - Ecoh[i][j] = Ecoh[j][i] = sqrt(Ecoh_one[i]*Ecoh_one[j]); - kR[i][j] = kR[j][i] = sqrt(kR_one[i]*kR_one[j]); - etaR[i][j] = etaR[j][i] = sqrt(etaR_one[i]*etaR_one[j]); - muR[i][j] = muR[j][i] = sqrt(muR_one[i]*muR_one[j]); + pois[i] = E_one[i]/(2.0*G_one[i]) - 1.0; + alpha_one[i] = 1.2728-4.2783*cor[i]+11.087*cor[i]*cor[i]-22.348*cor[i]*cor[i]*cor[i]+27.467*cor[i]*cor[i]*cor[i]*cor[i]-18.022*cor[i]*cor[i]*cor[i]*cor[i]*cor[i]+4.8218*cor[i]*cor[i]*cor[i]*cor[i]*cor[i]*cor[i]; + for (int j=i; j <= ntypes; j++){ + E[i][j] = E[j][i] = 1/((1-pois[i]*pois[i])/E_one[i]+(1-pois[j]*pois[j])/E_one[j]); + G[i][j] = G[j][i] = 1/((2-pois[i])/G_one[i]+(2-pois[j])/G_one[j]); + if (normaldamp == TSUJI){ + alpha[i][j] = alpha[j][i] = sqrt(alpha_one[i]*alpha_one[j]); } + else if (normaldamp == BRILLIANTOV){ + gamman[i][j] = gamman[j][i] = sqrt(cor[i]*cor[j]); + } + muS[i][j] = muS[j][i] = sqrt(muS_one[i]*muS_one[j]); + Ecoh[i][j] = Ecoh[j][i] = sqrt(Ecoh_one[i]*Ecoh_one[j]); + kR[i][j] = kR[j][i] = sqrt(kR_one[i]*kR_one[j]); + etaR[i][j] = etaR[j][i] = sqrt(etaR_one[i]*etaR_one[j]); + muR[i][j] = muR[j][i] = sqrt(muR_one[i]*muR_one[j]); + } } } /* ---------------------------------------------------------------------- */ double PairGranDMTRolling::single(int i, int j, int itype, int jtype, - double rsq, - double factor_coul, double factor_lj, - double &fforce) + double rsq, + double factor_coul, double factor_lj, + double &fforce) { double radi,radj,radsum; double r,rinv,rsqinv,delx,dely,delz, nx, ny, nz, R; @@ -565,9 +565,9 @@ double PairGranDMTRolling::single(int i, int j, int itype, int jtype, radsum = radi + radj; if (rsq >= radsum*radsum) { - fforce = 0.0; - svector[0] = svector[1] = svector[2] = svector[3] = 0.0; - return 0.0; + fforce = 0.0; + svector[0] = svector[1] = svector[2] = svector[3] = 0.0; + return 0.0; } r = sqrt(rsq); @@ -623,9 +623,9 @@ double PairGranDMTRolling::single(int i, int j, int itype, int jtype, mi = rmass[i]; mj = rmass[j]; if (fix_rigid) { - // NOTE: ensure mass_rigid is current for owned+ghost atoms? - if (mass_rigid[i] > 0.0) mi = mass_rigid[i]; - if (mass_rigid[j] > 0.0) mj = mass_rigid[j]; + // NOTE: ensure mass_rigid is current for owned+ghost atoms? + if (mass_rigid[i] > 0.0) mi = mass_rigid[i]; + if (mass_rigid[j] > 0.0) mj = mass_rigid[j]; } meff = mi*mj / (mi+mj); @@ -669,14 +669,14 @@ double PairGranDMTRolling::single(int i, int j, int itype, int jtype, double *allshear = fix_history->firstvalue[i]; for (int jj = 0; jj < jnum; jj++) { - neighprev++; - if (neighprev >= jnum) neighprev = 0; - if (jlist[neighprev] == j) break; + neighprev++; + if (neighprev >= jnum) neighprev = 0; + if (jlist[neighprev] == j) break; } double *shear = &allshear[size_history*neighprev]; shrmag = sqrt(shear[0]*shear[0] + shear[1]*shear[1] + - shear[2]*shear[2]); + shear[2]*shear[2]); // tangential forces = shear + tangential velocity damping kt=8.0*G[itype][jtype]*a; @@ -692,12 +692,12 @@ double PairGranDMTRolling::single(int i, int j, int itype, int jtype, Fscrit= muS[itype][jtype] * fabs(Fne); if (fs > Fscrit) { - if (shrmag != 0.0) { - fs1 *= Fscrit/fs; - fs2 *= Fscrit/fs; - fs3 *= Fscrit/fs; - fs *= Fscrit/fs; - } else fs1 = fs2 = fs3 = fs = 0.0; + if (shrmag != 0.0) { + fs1 *= Fscrit/fs; + fs2 *= Fscrit/fs; + fs3 *= Fscrit/fs; + fs *= Fscrit/fs; + } else fs1 = fs2 = fs3 = fs = 0.0; } // set all forces and return no energy From 5dafd03d1f261950ec0522e23cc9f6374a0a8549 Mon Sep 17 00:00:00 2001 From: Dan Stefan Bolintineanu Date: Thu, 10 May 2018 13:56:02 -0600 Subject: [PATCH 04/44] Various fixes to fix/wall/gran DMT --- src/GRANULAR/fix_wall_gran.cpp | 13 ++++++------- src/GRANULAR/fix_wall_gran_region.cpp | 6 ++---- src/GRANULAR/pair_gran_dmt_rolling.cpp | 1 + src/GRANULAR/pair_gran_hooke_history.cpp | 2 ++ src/GRANULAR/pair_gran_hooke_history.h | 1 + src/MAKE/Makefile.mpi | 2 +- 6 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/GRANULAR/fix_wall_gran.cpp b/src/GRANULAR/fix_wall_gran.cpp index 0c2aaed403..0cf1dde90b 100644 --- a/src/GRANULAR/fix_wall_gran.cpp +++ b/src/GRANULAR/fix_wall_gran.cpp @@ -879,7 +879,6 @@ void FixWallGran::dmt_rolling(double rsq, double dx, double dy, double dz, double tortwist1, tortwist2, tortwist3; double shrmag,rsht; - r = sqrt(rsq); rinv = 1.0/r; rsqinv = 1.0/rsq; @@ -888,9 +887,9 @@ void FixWallGran::dmt_rolling(double rsq, double dx, double dy, double dz, if (rwall == 0) R = radius; else R = radius*rwall/(radius+rwall); - nx = delx*rinv; - ny = dely*rinv; - nz = delz*rinv; + nx = dx*rinv; + ny = dy*rinv; + nz = dz*rinv; // relative translational velocity @@ -986,9 +985,8 @@ void FixWallGran::dmt_rolling(double rsq, double dx, double dy, double dz, Fscrit = xmu * fabs(Fne); // For JKR, use eq 43 of Marshall. For DMT, use Fne instead - //Redundant, should be same as above? - shrmag = sqrt(shear[0]*shear[0] + shear[1]*shear[1] + - shear[2]*shear[2]); + shrmag = sqrt(shear[0]*shear[0] + shear[1]*shear[1] + shear[2]*shear[2]); + fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); if (fs > Fscrit) { if (shrmag != 0.0) { @@ -1050,6 +1048,7 @@ void FixWallGran::dmt_rolling(double rsq, double dx, double dy, double dz, // rescale frictional displacements and forces if needed Frcrit = muR * fabs(Fne); + rollmag = sqrt(shear[3]*shear[3] + shear[4]*shear[4] + shear[5]*shear[5]); fr = sqrt(fr1*fr1 + fr2*fr2 + fr3*fr3); if (fr > Frcrit) { diff --git a/src/GRANULAR/fix_wall_gran_region.cpp b/src/GRANULAR/fix_wall_gran_region.cpp index 71b6503f36..2f415a0bc6 100644 --- a/src/GRANULAR/fix_wall_gran_region.cpp +++ b/src/GRANULAR/fix_wall_gran_region.cpp @@ -217,7 +217,6 @@ void FixWallGranRegion::post_force(int vflag) } // process current contacts - for (int ic = 0; ic < nc; ic++) { // rsq = squared contact distance @@ -266,9 +265,8 @@ void FixWallGranRegion::post_force(int vflag) v[i],f[i],omega[i],torque[i], radius[i],meff,shearmany[i][c2r[ic]], contact); else if (pairstyle == DMT_ROLLING) - dmt_rolling(rsq,dx,dy,dz,vwall,region->contact[ic].radius, - v[i],f[i],omega[i],torque[i], - radius[i],meff,shearmany[i][c2r[ic]], contact); + dmt_rolling(rsq,dx,dy,dz,vwall,region->contact[ic].radius, v[i],f[i],omega[i],torque[i], radius[i],meff,shearmany[i][c2r[ic]], contact); + } } } diff --git a/src/GRANULAR/pair_gran_dmt_rolling.cpp b/src/GRANULAR/pair_gran_dmt_rolling.cpp index 7a71fc7200..f293998e92 100644 --- a/src/GRANULAR/pair_gran_dmt_rolling.cpp +++ b/src/GRANULAR/pair_gran_dmt_rolling.cpp @@ -372,6 +372,7 @@ void PairGranDMTRolling::compute(int eflag, int vflag) // rescale frictional displacements and forces if needed Frcrit = muR[itype][jtype] * fabs(Fne); + rollmag = sqrt(shear[3]*shear[3] + shear[4]*shear[4] + shear[5]*shear[5]); fr = sqrt(fr1*fr1 + fr2*fr2 + fr3*fr3); if (fr > Frcrit) { if (rollmag != 0.0) { diff --git a/src/GRANULAR/pair_gran_hooke_history.cpp b/src/GRANULAR/pair_gran_hooke_history.cpp index f1a155f2e4..2f56b53736 100644 --- a/src/GRANULAR/pair_gran_hooke_history.cpp +++ b/src/GRANULAR/pair_gran_hooke_history.cpp @@ -58,6 +58,8 @@ PairGranHookeHistory::PairGranHookeHistory(LAMMPS *lmp, int _size_history) : Pai // set comm size needed by this Pair if used with fix rigid comm_forward = 1; + + nondefault_history_transfer = 0; //keep default behavior of history[i][j] = -history[j][i] } /* ---------------------------------------------------------------------- */ diff --git a/src/GRANULAR/pair_gran_hooke_history.h b/src/GRANULAR/pair_gran_hooke_history.h index c35de04109..6d9980919b 100644 --- a/src/GRANULAR/pair_gran_hooke_history.h +++ b/src/GRANULAR/pair_gran_hooke_history.h @@ -42,6 +42,7 @@ class PairGranHookeHistory : public Pair { int pack_forward_comm(int, int *, double *, int, int *); void unpack_forward_comm(int, int, double *); double memory_usage(); + int nondefault_history_transfer; protected: double kn,kt,gamman,gammat,xmu; diff --git a/src/MAKE/Makefile.mpi b/src/MAKE/Makefile.mpi index aebb465454..f30220da3d 100644 --- a/src/MAKE/Makefile.mpi +++ b/src/MAKE/Makefile.mpi @@ -12,7 +12,7 @@ SHFLAGS = -fPIC DEPFLAGS = -M LINK = mpicxx -LINKFLAGS = -g -O +LINKFLAGS = -g -O3 LIB = SIZE = size From 67782d71a8126512ced150224b96aea3cea67817 Mon Sep 17 00:00:00 2001 From: Dan Stefan Bolintineanu Date: Tue, 18 Dec 2018 21:23:04 -0700 Subject: [PATCH 05/44] Granular pair style files added --- src/GRANULAR/pair_gran_dmt_rolling2.cpp | 719 ++++++++++ src/GRANULAR/pair_gran_hooke_history.cpp | 3 +- src/GRANULAR/pair_gran_hooke_history.h | 2 +- .../pair_gran_hooke_history_multi.cpp | 915 +++++++++++++ src/GRANULAR/pair_gran_hooke_history_multi.h | 109 ++ src/GRANULAR/pair_gran_jkr_rolling_multi.cpp | 1181 ++++++++++++++++ src/GRANULAR/pair_gran_jkr_rolling_multi.h | 87 ++ src/GRANULAR/pair_granular.cpp | 1187 +++++++++++++++++ src/GRANULAR/pair_granular.h | 89 ++ 9 files changed, 4289 insertions(+), 3 deletions(-) create mode 100644 src/GRANULAR/pair_gran_dmt_rolling2.cpp create mode 100644 src/GRANULAR/pair_gran_hooke_history_multi.cpp create mode 100644 src/GRANULAR/pair_gran_hooke_history_multi.h create mode 100644 src/GRANULAR/pair_gran_jkr_rolling_multi.cpp create mode 100644 src/GRANULAR/pair_gran_jkr_rolling_multi.h create mode 100644 src/GRANULAR/pair_granular.cpp create mode 100644 src/GRANULAR/pair_granular.h diff --git a/src/GRANULAR/pair_gran_dmt_rolling2.cpp b/src/GRANULAR/pair_gran_dmt_rolling2.cpp new file mode 100644 index 0000000000..5c1211cbc5 --- /dev/null +++ b/src/GRANULAR/pair_gran_dmt_rolling2.cpp @@ -0,0 +1,719 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. + ------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Contributing authors: Leo Silbert (SNL), Gary Grest (SNL) + ------------------------------------------------------------------------- */ + +#include +#include +#include +#include +#include "pair_gran_dmt_rolling.h" +#include "atom.h" +#include "update.h" +#include "force.h" +#include "fix.h" +#include "neighbor.h" +#include "neigh_list.h" +#include "comm.h" +#include "memory.h" +#include "error.h" +#include "math_const.h" + +using namespace LAMMPS_NS; +using namespace MathConst; + +#define TWOTHIRDS 0.6666666666666666 +#define EPSILON 1e-10 + +enum {TSUJI, BRILLIANTOV}; +enum {INDEP, BRILLROLL}; + +/* ---------------------------------------------------------------------- */ + +PairGranDMTRolling::PairGranDMTRolling(LAMMPS *lmp) : + PairGranHookeHistory(lmp, 7), + E_one(0), G_one(0), pois(0), muS_one(0), cor(0), alpha_one(0), + Ecoh_one(0), kR_one(0), muR_one(0), etaR_one(0) +{ + int ntypes = atom->ntypes; + memory->create(E,ntypes+1,ntypes+1,"pair:E"); + memory->create(G,ntypes+1,ntypes+1,"pair:G"); + memory->create(alpha,ntypes+1,ntypes+1,"pair:alpha"); + memory->create(gamman,ntypes+1,ntypes+1,"pair:gamman"); + memory->create(muS,ntypes+1,ntypes+1,"pair:muS"); + memory->create(Ecoh,ntypes+1,ntypes+1,"pair:Ecoh"); + memory->create(kR,ntypes+1,ntypes+1,"pair:kR"); + memory->create(muR,ntypes+1,ntypes+1,"pair:muR"); + memory->create(etaR,ntypes+1,ntypes+1,"pair:etaR"); +} + +/* ---------------------------------------------------------------------- */ +PairGranDMTRolling::~PairGranDMTRolling() +{ + delete [] E_one; + delete [] G_one; + delete [] pois; + delete [] muS_one; + delete [] cor; + delete [] alpha_one; + delete [] Ecoh_one; + delete [] kR_one; + delete [] muR_one; + delete [] etaR_one; + //TODO: Make all this work with standard pair coeff type commands. + //Also these should not be in the destructor. + memory->destroy(E); + memory->destroy(G); + memory->destroy(alpha); + memory->destroy(gamman); + memory->destroy(muS); + memory->destroy(Ecoh); + memory->destroy(kR); + memory->destroy(muR); + memory->destroy(etaR); +} +/* ---------------------------------------------------------------------- */ + +void PairGranDMTRolling::compute(int eflag, int vflag) +{ + int i,j,ii,jj,inum,jnum; + int itype,jtype; + double xtmp,ytmp,ztmp,delx,dely,delz,fx,fy,fz,nx,ny,nz; + double radi,radj,radsum,rsq,r,rinv,rsqinv,R,a; + double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3; + double wr1,wr2,wr3; + double vtr1,vtr2,vtr3,vrel; + double kn, kt, k_Q, k_R, eta_N, eta_T, eta_Q, eta_R; + double Fhz, Fdamp, Fdmt, Fne, Fntot, Fscrit, Frcrit; + double overlap; + double mi,mj,meff,damp,ccel,tor1,tor2,tor3; + double relrot1,relrot2,relrot3,vrl1,vrl2,vrl3,vrlmag,vrlmaginv; + double rollmag, rolldotn, scalefac; + double fr, fr1, fr2, fr3; + double signtwist, magtwist, magtortwist, Mtcrit; + double fs,fs1,fs2,fs3,roll1,roll2,roll3,torroll1,torroll2,torroll3; + double tortwist1, tortwist2, tortwist3; + double shrmag,rsht; + int *ilist,*jlist,*numneigh,**firstneigh; + int *touch,**firsttouch; + double *shear,*allshear,**firstshear; + + if (eflag || vflag) ev_setup(eflag,vflag); + else evflag = vflag_fdotr = 0; + + int shearupdate = 1; + if (update->setupflag) shearupdate = 0; + + // update rigid body info for owned & ghost atoms if using FixRigid masses + // body[i] = which body atom I is in, -1 if none + // mass_body = mass of each rigid body + + if (fix_rigid && neighbor->ago == 0){ + int tmp; + int *body = (int *) fix_rigid->extract("body",tmp); + double *mass_body = (double *) fix_rigid->extract("masstotal",tmp); + if (atom->nmax > nmax) { + memory->destroy(mass_rigid); + nmax = atom->nmax; + memory->create(mass_rigid,nmax,"pair:mass_rigid"); + } + int nlocal = atom->nlocal; + for (i = 0; i < nlocal; i++) + if (body[i] >= 0) mass_rigid[i] = mass_body[body[i]]; + else mass_rigid[i] = 0.0; + comm->forward_comm_pair(this); + } + + double **x = atom->x; + double **v = atom->v; + double **f = atom->f; + double **omega = atom->omega; + double **torque = atom->torque; + double *radius = atom->radius; + double *rmass = atom->rmass; + int *type = atom->type; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + inum = list->inum; + ilist = list->ilist; + numneigh = list->numneigh; + firstneigh = list->firstneigh; + firsttouch = list->listhistory->firstneigh; + firstshear = list->listhistory->firstdouble; + + // loop over neighbors of my atoms + + for (ii = 0; ii < inum; ii++) { + i = ilist[ii]; + itype = type[i]; + xtmp = x[i][0]; + ytmp = x[i][1]; + ztmp = x[i][2]; + radi = radius[i]; + touch = firsttouch[i]; + allshear = firstshear[i]; + jlist = firstneigh[i]; + jnum = numneigh[i]; + + for (jj = 0; jj < jnum; jj++) { + j = jlist[jj]; + jtype = type[j]; + j &= NEIGHMASK; + + delx = xtmp - x[j][0]; + dely = ytmp - x[j][1]; + delz = ztmp - x[j][2]; + rsq = delx*delx + dely*dely + delz*delz; + radj = radius[j]; + radsum = radi + radj; + + if (rsq >= radsum*radsum){ + // unset non-touching neighbors + touch[jj] = 0; + shear = &allshear[nsheardim*jj]; + for (int k = 0; k < nsheardim; k++) + shear[k] = 0.0; + } else { + r = sqrt(rsq); + rinv = 1.0/r; + rsqinv = 1.0/rsq; + R = radi*radj/(radi+radj); + nx = delx*rinv; + ny = dely*rinv; + nz = delz*rinv; + + // relative translational velocity + + vr1 = v[i][0] - v[j][0]; + vr2 = v[i][1] - v[j][1]; + vr3 = v[i][2] - v[j][2]; + + // normal component + + vnnr = vr1*nx + vr2*ny + vr3*nz; //v_R . n + vn1 = nx*vnnr; + vn2 = ny*vnnr; + vn3 = nz*vnnr; + + // meff = effective mass of pair of particles + // if I or J part of rigid body, use body mass + // if I or J is frozen, meff is other particle + + mi = rmass[i]; + mj = rmass[j]; + if (fix_rigid) { + if (mass_rigid[i] > 0.0) mi = mass_rigid[i]; + if (mass_rigid[j] > 0.0) mj = mass_rigid[j]; + } + + meff = mi*mj / (mi+mj); + if (mask[i] & freeze_group_bit) meff = mj; + if (mask[j] & freeze_group_bit) meff = mi; + + //**************************************** + //Normal force = Hertzian contact + DMT + damping + //**************************************** + overlap = radsum - r; + a = sqrt(R*overlap); + kn = 4.0/3.0*E[itype][jtype]*a; + Fhz = kn*overlap; + + //Damping (based on Tsuji et al) + if (normaldamp == BRILLIANTOV) eta_N = a*meff*gamman[itype][jtype]; + else if (normaldamp == TSUJI) eta_N=alpha[itype][jtype]*sqrt(meff*kn); + + Fdamp = -eta_N*vnnr; //F_nd eq 23 and Zhao eq 19 + + //DMT + Fdmt = -4*MY_PI*Ecoh[itype][jtype]*R; + + Fne = Fhz + Fdmt; + Fntot = Fne + Fdamp; + + //**************************************** + //Tangential force, including shear history effects + //**************************************** + + // tangential component + vt1 = vr1 - vn1; + vt2 = vr2 - vn2; + vt3 = vr3 - vn3; + + // relative rotational velocity + //Luding Gran Matt 2008, v10,p235 suggests correcting radi and radj by subtracting + //delta/2, i.e. instead of radi, use distance to center of contact point? + wr1 = (radi*omega[i][0] + radj*omega[j][0]); + wr2 = (radi*omega[i][1] + radj*omega[j][1]); + wr3 = (radi*omega[i][2] + radj*omega[j][2]); + + // relative tangential velocities + vtr1 = vt1 - (nz*wr2-ny*wr3); + vtr2 = vt2 - (nx*wr3-nz*wr1); + vtr3 = vt3 - (ny*wr1-nx*wr2); + vrel = vtr1*vtr1 + vtr2*vtr2 + vtr3*vtr3; + vrel = sqrt(vrel); + + // shear history effects + touch[jj] = 1; + shear = &allshear[nsheardim*jj]; + shrmag = sqrt(shear[0]*shear[0] + shear[1]*shear[1] + + shear[2]*shear[2]); + + // Rotate and update shear displacements. + // See e.g. eq. 17 of Luding, Gran. Matter 2008, v10,p235 + if (shearupdate) { + rsht = shear[0]*nx + shear[1]*ny + shear[2]*nz; + if (fabs(rsht) < EPSILON) rsht = 0; + if (rsht > 0){ + scalefac = shrmag/(shrmag - rsht); //if rhst == shrmag, contacting pair has rotated 90 deg. in one step, in which case you deserve a crash! + shear[0] -= rsht*nx; + shear[1] -= rsht*ny; + shear[2] -= rsht*nz; + //Also rescale to preserve magnitude + shear[0] *= scalefac; + shear[1] *= scalefac; + shear[2] *= scalefac; + } + //Update shear history + shear[0] += vtr1*dt; + shear[1] += vtr2*dt; + shear[2] += vtr3*dt; + } + + // tangential forces = shear + tangential velocity damping + // following Zhao and Marshall Phys Fluids v20, p043302 (2008) + kt=8.0*G[itype][jtype]*a; + + eta_T = eta_N; //Based on discussion in Marshall; eta_T can also be an independent parameter + fs1 = -kt*shear[0] - eta_T*vtr1; //eq 26 + fs2 = -kt*shear[1] - eta_T*vtr2; + fs3 = -kt*shear[2] - eta_T*vtr3; + + // rescale frictional displacements and forces if needed + Fscrit = muS[itype][jtype] * fabs(Fne); + // For JKR, use eq 43 of Marshall. For DMT, use Fne instead + shrmag = sqrt(shear[0]*shear[0] + shear[1]*shear[1] + + shear[2]*shear[2]); + fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); + if (fs > Fscrit) { + if (shrmag != 0.0) { + //shear[0] = (Fcrit/fs) * (shear[0] + eta_T*vtr1/kt) - eta_T*vtr1/kt; + //shear[1] = (Fcrit/fs) * (shear[1] + eta_T*vtr1/kt) - eta_T*vtr1/kt; + //shear[2] = (Fcrit/fs) * (shear[2] + eta_T*vtr1/kt) - eta_T*vtr1/kt; + shear[0] = -1.0/kt*(Fscrit*fs1/fs + eta_T*vtr1); //Same as above, but simpler (check!) + shear[1] = -1.0/kt*(Fscrit*fs2/fs + eta_T*vtr2); + shear[2] = -1.0/kt*(Fscrit*fs3/fs + eta_T*vtr3); + fs1 *= Fscrit/fs; + fs2 *= Fscrit/fs; + fs3 *= Fscrit/fs; + } else fs1 = fs2 = fs3 = 0.0; + } + + //**************************************** + // Rolling force, including shear history effects + //**************************************** + + relrot1 = omega[i][0] - omega[j][0]; + relrot2 = omega[i][1] - omega[j][1]; + relrot3 = omega[i][2] - omega[j][2]; + + // rolling velocity, see eq. 31 of Wang et al, Particuology v 23, p 49 (2015) + // This is different from the Marshall papers, which use the Bagi/Kuhn formulation + // for rolling velocity (see Wang et al for why the latter is wrong) + vrl1 = R*(relrot2*nz - relrot3*ny); //- 0.5*((radj-radi)/radsum)*vtr1; + vrl2 = R*(relrot3*nx - relrot1*nz); //- 0.5*((radj-radi)/radsum)*vtr2; + vrl3 = R*(relrot1*ny - relrot2*nx); //- 0.5*((radj-radi)/radsum)*vtr3; + vrlmag = sqrt(vrl1*vrl1+vrl2*vrl2+vrl3*vrl3); + if (vrlmag != 0.0) vrlmaginv = 1.0/vrlmag; + else vrlmaginv = 0.0; + + // Rolling displacement + rollmag = sqrt(shear[3]*shear[3] + shear[4]*shear[4] + shear[5]*shear[5]); + rolldotn = shear[3]*nx + shear[4]*ny + shear[5]*nz; + + if (shearupdate) { + if (fabs(rolldotn) < EPSILON) rolldotn = 0; + if (rolldotn > 0){ //Rotate into tangential plane + scalefac = rollmag/(rollmag - rolldotn); + shear[3] -= rolldotn*nx; + shear[4] -= rolldotn*ny; + shear[5] -= rolldotn*nz; + //Also rescale to preserve magnitude + shear[3] *= scalefac; + shear[4] *= scalefac; + shear[5] *= scalefac; + } + shear[3] += vrl1*dt; + shear[4] += vrl2*dt; + shear[5] += vrl3*dt; + } + + k_R = kR[itype][jtype]; + if (rollingdamp == INDEP) eta_R = etaR[itype][jtype]; + else if (rollingdamp == BRILLROLL) eta_R = muR[itype][jtype]*fabs(Fne); + fr1 = -k_R*shear[3] - eta_R*vrl1; + fr2 = -k_R*shear[4] - eta_R*vrl2; + fr3 = -k_R*shear[5] - eta_R*vrl3; + + // rescale frictional displacements and forces if needed + Frcrit = muR[itype][jtype] * fabs(Fne); + + fr = sqrt(fr1*fr1 + fr2*fr2 + fr3*fr3); + if (fr > Frcrit) { + if (rollmag != 0.0) { + shear[3] = -1.0/k_R*(Frcrit*fr1/fr + eta_R*vrl1); + shear[4] = -1.0/k_R*(Frcrit*fr2/fr + eta_R*vrl2); + shear[5] = -1.0/k_R*(Frcrit*fr3/fr + eta_R*vrl3); + fr1 *= Frcrit/fr; + fr2 *= Frcrit/fr; + fr3 *= Frcrit/fr; + } else fr1 = fr2 = fr3 = 0.0; + } + + + //**************************************** + // Twisting torque, including shear history effects + //**************************************** + magtwist = relrot1*nx + relrot2*ny + relrot3*nz; //Omega_T (eq 29 of Marshall) + shear[6] += magtwist*dt; + k_Q = 0.5*kt*a*a;; //eq 32 + eta_Q = 0.5*eta_T*a*a; + magtortwist = -k_Q*shear[6] - eta_Q*magtwist;//M_t torque (eq 30) + + signtwist = (magtwist > 0) - (magtwist < 0); + Mtcrit=TWOTHIRDS*a*Fscrit;//critical torque (eq 44) + if (fabs(magtortwist) > Mtcrit){ + shear[6] = 1.0/k_Q*(Mtcrit*signtwist - eta_Q*magtwist); + magtortwist = -Mtcrit * signtwist; //eq 34 + } + + // Apply forces & torques + + fx = nx*Fntot + fs1; + fy = ny*Fntot + fs2; + fz = nz*Fntot + fs3; + + f[i][0] += fx; + f[i][1] += fy; + f[i][2] += fz; + + tor1 = ny*fs3 - nz*fs2; + tor2 = nz*fs1 - nx*fs3; + tor3 = nx*fs2 - ny*fs1; + + torque[i][0] -= radi*tor1; + torque[i][1] -= radi*tor2; + torque[i][2] -= radi*tor3; + + tortwist1 = magtortwist * nx; + tortwist2 = magtortwist * ny; + tortwist3 = magtortwist * nz; + + torque[i][0] += tortwist1; + torque[i][1] += tortwist2; + torque[i][2] += tortwist3; + + torroll1 = R*(ny*fr3 - nz*fr2); //n cross fr + torroll2 = R*(nz*fr1 - nx*fr3); + torroll3 = R*(nx*fr2 - ny*fr1); + + torque[i][0] += torroll1; + torque[i][1] += torroll2; + torque[i][2] += torroll3; + + if (force->newton_pair || j < nlocal) { + f[j][0] -= fx; + f[j][1] -= fy; + f[j][2] -= fz; + + torque[j][0] -= radj*tor1; + torque[j][1] -= radj*tor2; + torque[j][2] -= radj*tor3; + + torque[j][0] -= tortwist1; + torque[j][1] -= tortwist2; + torque[j][2] -= tortwist3; + + torque[j][0] -= torroll1; + torque[j][1] -= torroll2; + torque[j][2] -= torroll3; + } + if (evflag) ev_tally_xyz(i,j,nlocal,0, + 0.0,0.0,fx,fy,fz,delx,dely,delz); + } + } + } +} + +/* ---------------------------------------------------------------------- + global settings + ------------------------------------------------------------------------- */ + +void PairGranDMTRolling::settings(int narg, char **arg) +{ + if (narg < 6) error->all(FLERR,"Illegal pair_style command"); + + int ntypes = atom->ntypes; + + if (narg < 8*ntypes) error->all(FLERR,"Illegal pair_style command"); + + E_one = new double[ntypes+1]; + G_one = new double[ntypes+1]; + pois = new double[ntypes+1]; + muS_one = new double[ntypes+1]; + cor = new double[ntypes+1]; + alpha_one = new double[ntypes+1]; + Ecoh_one = new double[ntypes+1]; + kR_one = new double[ntypes+1]; + muR_one = new double[ntypes+1]; + etaR_one = new double[ntypes+1]; + + for (int i=0; i < ntypes;i++){ + E_one[i+1] = force->numeric(FLERR, arg[i]); + G_one[i+1] = force->numeric(FLERR, arg[ntypes+i]); + muS_one[i+1] = force->numeric(FLERR, arg[2*ntypes+i]); + cor[i+1] = force->numeric(FLERR, arg[3*ntypes+i]); + Ecoh_one[i+1] = force->numeric(FLERR, arg[4*ntypes+i]); + kR_one[i+1] = force->numeric(FLERR, arg[5*ntypes+i]); + muR_one[i+1] = force->numeric(FLERR, arg[6*ntypes+i]); + etaR_one[i+1] = force->numeric(FLERR, arg[7*ntypes+i]); + } + + //Defaults + normaldamp = TSUJI; + rollingdamp = INDEP; + + int iarg = 8*ntypes; + while (iarg < narg){ + if (strcmp(arg[iarg],"normaldamp") == 0){ + if (iarg+2 > narg) error->all(FLERR, "Invalid pair/gran/dmt/rolling entry"); + if (strcmp(arg[iarg+1],"tsuji") == 0) normaldamp = TSUJI; + else if (strcmp(arg[iarg+1],"brilliantov") == 0) normaldamp = BRILLIANTOV; + else error->all(FLERR, "Invalid normal damping model for pair/gran/dmt/rolling"); + iarg += 2; + } + else if (strcmp(arg[iarg],"rollingdamp") == 0){ + if (iarg+2 > narg) error->all(FLERR, "Invalid pair/gran/dmt/rolling entry"); + if (strcmp(arg[iarg+1],"independent") == 0) rollingdamp = INDEP; + else if (strcmp(arg[iarg+1],"brilliantov") == 0) rollingdamp = BRILLROLL; + else error->all(FLERR, "Invalid rolling damping model for pair/gran/dmt/rolling"); + iarg += 2; + } + else{ + iarg +=1; + } + } + + //Derived from inputs + for (int i=1; i <= ntypes; i++){ + pois[i] = E_one[i]/(2.0*G_one[i]) - 1.0; + alpha_one[i] = 1.2728-4.2783*cor[i]+11.087*cor[i]*cor[i]-22.348*cor[i]*cor[i]*cor[i]+27.467*cor[i]*cor[i]*cor[i]*cor[i]-18.022*cor[i]*cor[i]*cor[i]*cor[i]*cor[i]+4.8218*cor[i]*cor[i]*cor[i]*cor[i]*cor[i]*cor[i]; + for (int j=i; j <= ntypes; j++){ + E[i][j] = E[j][i] = 1/((1-pois[i]*pois[i])/E_one[i]+(1-pois[j]*pois[j])/E_one[j]); + G[i][j] = G[j][i] = 1/((2-pois[i])/G_one[i]+(2-pois[j])/G_one[j]); + if (normaldamp == TSUJI){ + alpha[i][j] = alpha[j][i] = sqrt(alpha_one[i]*alpha_one[j]); + } + else if (normaldamp == BRILLIANTOV){ + gamman[i][j] = gamman[j][i] = sqrt(cor[i]*cor[j]); + } + muS[i][j] = muS[j][i] = sqrt(muS_one[i]*muS_one[j]); + Ecoh[i][j] = Ecoh[j][i] = sqrt(Ecoh_one[i]*Ecoh_one[j]); + kR[i][j] = kR[j][i] = sqrt(kR_one[i]*kR_one[j]); + etaR[i][j] = etaR[j][i] = sqrt(etaR_one[i]*etaR_one[j]); + muR[i][j] = muR[j][i] = sqrt(muR_one[i]*muR_one[j]); + } + } +} + +/* ---------------------------------------------------------------------- */ + +double PairGranDMTRolling::single(int i, int j, int itype, int jtype, + double rsq, + double factor_coul, double factor_lj, + double &fforce) +{ + double radi,radj,radsum; + double r,rinv,rsqinv,delx,dely,delz, nx, ny, nz, R; + double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3,wr1,wr2,wr3; + double overlap, a; + double mi,mj,meff,damp,kn,kt; + double Fhz,Fdamp,Fdmt,Fne,Fntot,Fscrit; + double eta_N,eta_T; + double vtr1,vtr2,vtr3,vrel; + double fs1,fs2,fs3,fs; + double shrmag; + + + double *radius = atom->radius; + radi = radius[i]; + radj = radius[j]; + radsum = radi + radj; + + if (rsq >= radsum*radsum) { + fforce = 0.0; + svector[0] = svector[1] = svector[2] = svector[3] = 0.0; + return 0.0; + } + + r = sqrt(rsq); + rinv = 1.0/r; + rsqinv = 1.0/rsq; + R = radi*radj/radsum; + + // relative translational velocity + + double **v = atom->v; + vr1 = v[i][0] - v[j][0]; + vr2 = v[i][1] - v[j][1]; + vr3 = v[i][2] - v[j][2]; + + // normal component + + double **x = atom->x; + delx = x[i][0] - x[j][0]; + dely = x[i][1] - x[j][1]; + delz = x[i][2] - x[j][2]; + + nx = delx*rinv; + ny = dely*rinv; + nz = delz*rinv; + + + vnnr = vr1*nx + vr2*ny + vr3*nz; + vn1 = nx*vnnr; + vn2 = ny*vnnr; + vn3 = nz*vnnr; + + // tangential component + + vt1 = vr1 - vn1; + vt2 = vr2 - vn2; + vt3 = vr3 - vn3; + + // relative rotational velocity + + double **omega = atom->omega; + wr1 = (radi*omega[i][0] + radj*omega[j][0]); + wr2 = (radi*omega[i][1] + radj*omega[j][1]); + wr3 = (radi*omega[i][2] + radj*omega[j][2]); + + // meff = effective mass of pair of particles + // if I or J part of rigid body, use body mass + // if I or J is frozen, meff is other particle + + double *rmass = atom->rmass; + int *type = atom->type; + int *mask = atom->mask; + + mi = rmass[i]; + mj = rmass[j]; + if (fix_rigid) { + // NOTE: ensure mass_rigid is current for owned+ghost atoms? + if (mass_rigid[i] > 0.0) mi = mass_rigid[i]; + if (mass_rigid[j] > 0.0) mj = mass_rigid[j]; + } + + meff = mi*mj / (mi+mj); + if (mask[i] & freeze_group_bit) meff = mj; + if (mask[j] & freeze_group_bit) meff = mi; + + + // normal force = Hertzian contact + normal velocity damping + overlap = radsum - r; + a = sqrt(R*overlap); + kn = 4.0/3.0*E[itype][jtype]*a; + Fhz = kn*overlap; + + //Damping (based on Tsuji et al) + + eta_N=alpha[itype][jtype]*sqrt(meff*kn); + Fdamp = -eta_N*vnnr; //F_nd eq 23 and Zhao eq 19 + + //DMT + Fdmt = -4*MY_PI*Ecoh[itype][jtype]*R; + + Fne = Fhz + Fdmt; + Fntot = Fne + Fdamp; + + // relative velocities + + vtr1 = vt1 - (nz*wr2-ny*wr3); + vtr2 = vt2 - (nx*wr3-nz*wr1); + vtr3 = vt3 - (ny*wr1-nx*wr2); + vrel = vtr1*vtr1 + vtr2*vtr2 + vtr3*vtr3; + vrel = sqrt(vrel); + + // shear history effects + // neighprev = index of found neigh on previous call + // search entire jnum list of neighbors of I for neighbor J + // start from neighprev, since will typically be next neighbor + // reset neighprev to 0 as necessary + + int jnum = list->numneigh[i]; + int *jlist = list->firstneigh[i]; + double *allshear = list->listhistory->firstdouble[i]; + + for (int jj = 0; jj < jnum; jj++) { + neighprev++; + if (neighprev >= jnum) neighprev = 0; + if (jlist[neighprev] == j) break; + } + + double *shear = &allshear[nsheardim*neighprev]; + shrmag = sqrt(shear[0]*shear[0] + shear[1]*shear[1] + + shear[2]*shear[2]); + + // tangential forces = shear + tangential velocity damping + kt=8.0*G[itype][jtype]*a; + + eta_T = eta_N; + fs1 = -kt*shear[0] - eta_T*vtr1; + fs2 = -kt*shear[1] - eta_T*vtr2; + fs3 = -kt*shear[2] - eta_T*vtr3; + + // rescale frictional displacements and forces if needed + + fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); + Fscrit= muS[itype][jtype] * fabs(Fne); + + if (fs > Fscrit) { + if (shrmag != 0.0) { + fs1 *= Fscrit/fs; + fs2 *= Fscrit/fs; + fs3 *= Fscrit/fs; + fs *= Fscrit/fs; + } else fs1 = fs2 = fs3 = fs = 0.0; + } + + // set all forces and return no energy + + fforce = Fntot; + + // set single_extra quantities + + svector[0] = fs1; + svector[1] = fs2; + svector[2] = fs3; + svector[3] = fs; + svector[4] = vn1; + svector[5] = vn2; + svector[6] = vn3; + svector[7] = vt1; + svector[8] = vt2; + svector[9] = vt3; + return 0.0; +} diff --git a/src/GRANULAR/pair_gran_hooke_history.cpp b/src/GRANULAR/pair_gran_hooke_history.cpp index 4bc867e426..cf30e77ccb 100644 --- a/src/GRANULAR/pair_gran_hooke_history.cpp +++ b/src/GRANULAR/pair_gran_hooke_history.cpp @@ -39,8 +39,7 @@ using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ -PairGranHookeHistory::PairGranHookeHistory(LAMMPS *lmp, int _size_history) : Pair(lmp), - size_history(_size_history) +PairGranHookeHistory::PairGranHookeHistory(LAMMPS *lmp) : Pair(lmp) { single_enable = 1; no_virial_fdotr_compute = 1; diff --git a/src/GRANULAR/pair_gran_hooke_history.h b/src/GRANULAR/pair_gran_hooke_history.h index 6d9980919b..2cb609fd82 100644 --- a/src/GRANULAR/pair_gran_hooke_history.h +++ b/src/GRANULAR/pair_gran_hooke_history.h @@ -26,7 +26,7 @@ namespace LAMMPS_NS { class PairGranHookeHistory : public Pair { public: - PairGranHookeHistory(class LAMMPS *, int size_history = 3); + PairGranHookeHistory(class LAMMPS *); virtual ~PairGranHookeHistory(); virtual void compute(int, int); virtual void settings(int, char **); diff --git a/src/GRANULAR/pair_gran_hooke_history_multi.cpp b/src/GRANULAR/pair_gran_hooke_history_multi.cpp new file mode 100644 index 0000000000..48e793bbb3 --- /dev/null +++ b/src/GRANULAR/pair_gran_hooke_history_multi.cpp @@ -0,0 +1,915 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Contributing authors: Leo Silbert (SNL), Gary Grest (SNL) +------------------------------------------------------------------------- */ + +#include +#include +#include +#include +#include "pair_gran_hooke_history_multi.h" +#include "atom.h" +#include "atom_vec.h" +#include "domain.h" +#include "force.h" +#include "update.h" +#include "modify.h" +#include "fix.h" +#include "fix_neigh_history.h" +#include "comm.h" +#include "neighbor.h" +#include "neigh_list.h" +#include "neigh_request.h" +#include "memory.h" +#include "error.h" + +using namespace LAMMPS_NS; + +#define BIG 1.0e20 + +/* ---------------------------------------------------------------------- */ + +PairGranHookeHistoryMulti::PairGranHookeHistoryMulti(LAMMPS *lmp) : Pair(lmp) +{ + single_enable = 1; + no_virial_fdotr_compute = 1; + history = 1; + fix_history = NULL; + + single_extra = 10; + svector = new double[10]; + + neighprev = 0; + + nmax = 0; + mass_rigid = NULL; + + // set comm size needed by this Pair if used with fix rigid + + comm_forward = 1; +} + +/* ---------------------------------------------------------------------- */ + +PairGranHookeHistoryMulti::~PairGranHookeHistoryMulti() +{ + delete [] svector; + if (fix_history) modify->delete_fix("NEIGH_HISTORY"); + + if (allocated) { + memory->destroy(setflag); + memory->destroy(cutsq); + + memory->destroy(cut); + memory->destroy(kn); + memory->destroy(kt); + memory->destroy(gamman); + memory->destroy(gammat); + memory->destroy(xmu); + memory->destroy(dampflag); + + delete [] onerad_dynamic; + delete [] onerad_frozen; + delete [] maxrad_dynamic; + delete [] maxrad_frozen; + } + memory->destroy(mass_rigid); +} + +/* ---------------------------------------------------------------------- */ + +void PairGranHookeHistoryMulti::compute(int eflag, int vflag) +{ + int i,j,ii,jj,inum,jnum,itype,jtype; + double xtmp,ytmp,ztmp,delx,dely,delz,fx,fy,fz; + double radi,radj,radsum,rsq,r,rinv,rsqinv; + double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3; + double wr1,wr2,wr3; + double vtr1,vtr2,vtr3,vrel; + double mi,mj,meff,damp,ccel,tor1,tor2,tor3; + double fn,fs,fs1,fs2,fs3; + double shrmag,rsht; + int *ilist,*jlist,*numneigh,**firstneigh; + int *touch,**firsttouch; + double *shear,*allshear,**firstshear; + + if (eflag || vflag) ev_setup(eflag,vflag); + else evflag = vflag_fdotr = 0; + + int shearupdate = 1; + if (update->setupflag) shearupdate = 0; + + // update rigid body info for owned & ghost atoms if using FixRigid masses + // body[i] = which body atom I is in, -1 if none + // mass_body = mass of each rigid body + + if (fix_rigid && neighbor->ago == 0) { + int tmp; + int *body = (int *) fix_rigid->extract("body",tmp); + double *mass_body = (double *) fix_rigid->extract("masstotal",tmp); + if (atom->nmax > nmax) { + memory->destroy(mass_rigid); + nmax = atom->nmax; + memory->create(mass_rigid,nmax,"pair:mass_rigid"); + } + int nlocal = atom->nlocal; + for (i = 0; i < nlocal; i++) + if (body[i] >= 0) mass_rigid[i] = mass_body[body[i]]; + else mass_rigid[i] = 0.0; + comm->forward_comm_pair(this); + } + + double **x = atom->x; + double **v = atom->v; + double **f = atom->f; + int *type = atom->type; + double **omega = atom->omega; + double **torque = atom->torque; + double *radius = atom->radius; + double *rmass = atom->rmass; + int *mask = atom->mask; + int nlocal = atom->nlocal; + int newton_pair = force->newton_pair; + + inum = list->inum; + ilist = list->ilist; + numneigh = list->numneigh; + firstneigh = list->firstneigh; + firsttouch = fix_history->firstflag; + firstshear = fix_history->firstvalue; + + // loop over neighbors of my atoms + + for (ii = 0; ii < inum; ii++) { + i = ilist[ii]; + xtmp = x[i][0]; + ytmp = x[i][1]; + ztmp = x[i][2]; + itype = type[i]; + radi = radius[i]; + touch = firsttouch[i]; + allshear = firstshear[i]; + jlist = firstneigh[i]; + jnum = numneigh[i]; + + for (jj = 0; jj < jnum; jj++) { + j = jlist[jj]; + j &= NEIGHMASK; + + delx = xtmp - x[j][0]; + dely = ytmp - x[j][1]; + delz = ztmp - x[j][2]; + rsq = delx*delx + dely*dely + delz*delz; + jtype = type[j]; + radj = radius[j]; + radsum = radi + radj; + + if (rsq >= radsum*radsum) { + + // unset non-touching neighbors + + touch[jj] = 0; + shear = &allshear[3*jj]; + shear[0] = 0.0; + shear[1] = 0.0; + shear[2] = 0.0; + + } else { + r = sqrt(rsq); + rinv = 1.0/r; + rsqinv = 1.0/rsq; + + // relative translational velocity + + vr1 = v[i][0] - v[j][0]; + vr2 = v[i][1] - v[j][1]; + vr3 = v[i][2] - v[j][2]; + + // normal component + + vnnr = vr1*delx + vr2*dely + vr3*delz; + vn1 = delx*vnnr * rsqinv; + vn2 = dely*vnnr * rsqinv; + vn3 = delz*vnnr * rsqinv; + + // tangential component + + vt1 = vr1 - vn1; + vt2 = vr2 - vn2; + vt3 = vr3 - vn3; + + // relative rotational velocity + + wr1 = (radi*omega[i][0] + radj*omega[j][0]) * rinv; + wr2 = (radi*omega[i][1] + radj*omega[j][1]) * rinv; + wr3 = (radi*omega[i][2] + radj*omega[j][2]) * rinv; + + // meff = effective mass of pair of particles + // if I or J part of rigid body, use body mass + // if I or J is frozen, meff is other particle + + mi = rmass[i]; + mj = rmass[j]; + if (fix_rigid) { + if (mass_rigid[i] > 0.0) mi = mass_rigid[i]; + if (mass_rigid[j] > 0.0) mj = mass_rigid[j]; + } + + meff = mi*mj / (mi+mj); + if (mask[i] & freeze_group_bit) meff = mj; + if (mask[j] & freeze_group_bit) meff = mi; + + // normal forces = Hookian contact + normal velocity damping + + damp = meff*gamman[itype][jtype]*vnnr*rsqinv; + ccel = kn[itype][jtype]*(radsum-r)*rinv - damp; + + // relative velocities + + vtr1 = vt1 - (delz*wr2-dely*wr3); + vtr2 = vt2 - (delx*wr3-delz*wr1); + vtr3 = vt3 - (dely*wr1-delx*wr2); + vrel = vtr1*vtr1 + vtr2*vtr2 + vtr3*vtr3; + vrel = sqrt(vrel); + + // shear history effects + + touch[jj] = 1; + shear = &allshear[3*jj]; + + if (shearupdate) { + shear[0] += vtr1*dt; + shear[1] += vtr2*dt; + shear[2] += vtr3*dt; + } + shrmag = sqrt(shear[0]*shear[0] + shear[1]*shear[1] + + shear[2]*shear[2]); + + // rotate shear displacements + + rsht = shear[0]*delx + shear[1]*dely + shear[2]*delz; + rsht *= rsqinv; + if (shearupdate) { + shear[0] -= rsht*delx; + shear[1] -= rsht*dely; + shear[2] -= rsht*delz; + } + + // tangential forces = shear + tangential velocity damping + + fs1 = - (kt[itype][jtype]*shear[0] + meff*gammat[itype][jtype]*vtr1); + fs2 = - (kt[itype][jtype]*shear[1] + meff*gammat[itype][jtype]*vtr2); + fs3 = - (kt[itype][jtype]*shear[2] + meff*gammat[itype][jtype]*vtr3); + + // rescale frictional displacements and forces if needed + + fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); + fn = xmu[itype][jtype] * fabs(ccel*r); + + if (fs > fn) { + if (shrmag != 0.0) { + shear[0] = (fn/fs) * (shear[0] + + meff*gammat[itype][jtype]*vtr1/kt[itype][jtype]) - + meff*gammat[itype][jtype]*vtr1/kt[itype][jtype]; + shear[1] = (fn/fs) * (shear[1] + + meff*gammat[itype][jtype]*vtr2/kt[itype][jtype]) - + meff*gammat[itype][jtype]*vtr2/kt[itype][jtype]; + shear[2] = (fn/fs) * (shear[2] + + meff*gammat[itype][jtype]*vtr3/kt[itype][jtype]) - + meff*gammat[itype][jtype]*vtr3/kt[itype][jtype]; + fs1 *= fn/fs; + fs2 *= fn/fs; + fs3 *= fn/fs; + } else fs1 = fs2 = fs3 = 0.0; + } + + // forces & torques + + fx = delx*ccel + fs1; + fy = dely*ccel + fs2; + fz = delz*ccel + fs3; + f[i][0] += fx; + f[i][1] += fy; + f[i][2] += fz; + + tor1 = rinv * (dely*fs3 - delz*fs2); + tor2 = rinv * (delz*fs1 - delx*fs3); + tor3 = rinv * (delx*fs2 - dely*fs1); + torque[i][0] -= radi*tor1; + torque[i][1] -= radi*tor2; + torque[i][2] -= radi*tor3; + + if (newton_pair || j < nlocal) { + f[j][0] -= fx; + f[j][1] -= fy; + f[j][2] -= fz; + torque[j][0] -= radj*tor1; + torque[j][1] -= radj*tor2; + torque[j][2] -= radj*tor3; + } + + if (evflag) ev_tally_xyz(i,j,nlocal,newton_pair, + 0.0,0.0,fx,fy,fz,delx,dely,delz); + } + } + } + + if (vflag_fdotr) virial_fdotr_compute(); +} + +/* ---------------------------------------------------------------------- + allocate all arrays +------------------------------------------------------------------------- */ + +void PairGranHookeHistoryMulti::allocate() +{ + allocated = 1; + int n = atom->ntypes; + + memory->create(setflag,n+1,n+1,"pair:setflag"); + for (int i = 1; i <= n; i++) + for (int j = i; j <= n; j++) + setflag[i][j] = 0; + + memory->create(cutsq,n+1,n+1,"pair:cutsq"); + memory->create(cut,n+1,n+1,"pair:cut"); + memory->create(kn,n+1,n+1,"pair:kn"); + memory->create(kt,n+1,n+1,"pair:kt"); + memory->create(gamman,n+1,n+1,"pair:gamman"); + memory->create(gammat,n+1,n+1,"pair:gammat"); + memory->create(xmu,n+1,n+1,"pair:xmu"); + memory->create(dampflag,n+1,n+1,"pair:dampflag"); + + onerad_dynamic = new double[n+1]; + onerad_frozen = new double[n+1]; + maxrad_dynamic = new double[n+1]; + maxrad_frozen = new double[n+1]; +} + +/* ---------------------------------------------------------------------- + global settings +------------------------------------------------------------------------- */ + +void PairGranHookeHistoryMulti::settings(int narg, char **arg) +{ + if (narg != 1) error->all(FLERR,"Illegal pair_style command"); + + if (strcmp(arg[0],"NULL") == 0 ) cut_global = -1.0; + else cut_global = force->numeric(FLERR,arg[0]); + + // reset cutoffs that have been explicitly set + if (allocated) { + int i,j; + for (i = 1; i <= atom->ntypes; i++) + for (j = i; j <= atom->ntypes; j++) + if (setflag[i][j]) cut[i][j] = cut_global; + } +} + +/* ---------------------------------------------------------------------- + set coeffs for one or more type pairs +------------------------------------------------------------------------- */ + +void PairGranHookeHistoryMulti::coeff(int narg, char **arg) +{ + if (narg < 8 || narg > 9) + error->all(FLERR,"Incorrect args for pair coefficients"); + + if (!allocated) allocate(); + + int ilo,ihi,jlo,jhi; + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); + + double kn_one = force->numeric(FLERR,arg[2]); + double kt_one; + if (strcmp(arg[3],"NULL") == 0) kt_one = kn_one * 2.0/7.0; + else kt_one = force->numeric(FLERR,arg[3]); + + double gamman_one = force->numeric(FLERR,arg[4]); + double gammat_one; + if (strcmp(arg[5],"NULL") == 0) gammat_one = 0.5 * gamman_one; + else gammat_one = force->numeric(FLERR,arg[5]); + + double xmu_one = force->numeric(FLERR,arg[6]); + int dampflag_one = force->inumeric(FLERR,arg[7]); + if (dampflag_one == 0) gammat_one = 0.0; + + if (kn_one < 0.0 || kt_one < 0.0 || gamman_one < 0.0 || gammat_one < 0.0 || + xmu_one < 0.0 || xmu_one > 10000.0 || dampflag_one < 0 || dampflag_one > 1) + error->all(FLERR,"Illegal pair_style command"); + + // convert Kn and Kt from pressure units to force/distance^2 + kn_one /= force->nktv2p; + kt_one /= force->nktv2p; + + double cut_one = cut_global; + if (narg==9) { + if (strcmp(arg[8],"NULL") == 0) cut_one = -1.0; + else cut_one = force->numeric(FLERR,arg[8]); + } + + int count = 0; + for (int i = ilo; i <= ihi; i++) { + for (int j = MAX(jlo,i); j <= jhi; j++) { + kn[i][j] = kn_one; + kt[i][j] = kt_one; + gamman[i][j] = gamman_one; + gammat[i][j] = gammat_one; + xmu[i][j] = xmu_one; + dampflag[i][j] = dampflag_one; + cut[i][j] = cut_one; + setflag[i][j] = 1; + count++; + } + } + + if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); +} + +/* ---------------------------------------------------------------------- + init specific to this pair style +------------------------------------------------------------------------- */ + +void PairGranHookeHistoryMulti::init_style() +{ + int i; + + // error and warning checks + + if (!atom->radius_flag || !atom->rmass_flag) + error->all(FLERR,"Pair granular requires atom attributes radius, rmass"); + if (comm->ghost_velocity == 0) + error->all(FLERR,"Pair granular requires ghost atoms store velocity"); + + // need a granular neigh list + + int irequest = neighbor->request(this,instance_me); + neighbor->requests[irequest]->size = 1; + if (history) neighbor->requests[irequest]->history = 1; + + dt = update->dt; + + // if shear history is stored: + // if first init, create Fix needed for storing shear history + + if (history && fix_history == NULL) { + char dnumstr[16]; + sprintf(dnumstr,"%d",3); + char **fixarg = new char*[4]; + fixarg[0] = (char *) "NEIGH_HISTORY"; + fixarg[1] = (char *) "all"; + fixarg[2] = (char *) "NEIGH_HISTORY"; + fixarg[3] = dnumstr; + modify->add_fix(4,fixarg,1); + delete [] fixarg; + fix_history = (FixNeighHistory *) modify->fix[modify->nfix-1]; + fix_history->pair = this; + } + + // check for FixFreeze and set freeze_group_bit + + for (i = 0; i < modify->nfix; i++) + if (strcmp(modify->fix[i]->style,"freeze") == 0) break; + if (i < modify->nfix) freeze_group_bit = modify->fix[i]->groupbit; + else freeze_group_bit = 0; + + // check for FixRigid so can extract rigid body masses + + fix_rigid = NULL; + for (i = 0; i < modify->nfix; i++) + if (modify->fix[i]->rigid_flag) break; + if (i < modify->nfix) fix_rigid = modify->fix[i]; + + // check for FixPour and FixDeposit so can extract particle radii + + int ipour; + for (ipour = 0; ipour < modify->nfix; ipour++) + if (strcmp(modify->fix[ipour]->style,"pour") == 0) break; + if (ipour == modify->nfix) ipour = -1; + + int idep; + for (idep = 0; idep < modify->nfix; idep++) + if (strcmp(modify->fix[idep]->style,"deposit") == 0) break; + if (idep == modify->nfix) idep = -1; + + // set maxrad_dynamic and maxrad_frozen for each type + // include future FixPour and FixDeposit particles as dynamic + + int itype; + for (i = 1; i <= atom->ntypes; i++) { + onerad_dynamic[i] = onerad_frozen[i] = 0.0; + if (ipour >= 0) { + itype = i; + onerad_dynamic[i] = + *((double *) modify->fix[ipour]->extract("radius",itype)); + } + if (idep >= 0) { + itype = i; + onerad_dynamic[i] = + *((double *) modify->fix[idep]->extract("radius",itype)); + } + } + + double *radius = atom->radius; + int *mask = atom->mask; + int *type = atom->type; + int nlocal = atom->nlocal; + + for (i = 0; i < nlocal; i++) + if (mask[i] & freeze_group_bit) + onerad_frozen[type[i]] = MAX(onerad_frozen[type[i]],radius[i]); + else + onerad_dynamic[type[i]] = MAX(onerad_dynamic[type[i]],radius[i]); + + MPI_Allreduce(&onerad_dynamic[1],&maxrad_dynamic[1],atom->ntypes, + MPI_DOUBLE,MPI_MAX,world); + MPI_Allreduce(&onerad_frozen[1],&maxrad_frozen[1],atom->ntypes, + MPI_DOUBLE,MPI_MAX,world); + + // set fix which stores history info + + if (history) { + int ifix = modify->find_fix("NEIGH_HISTORY"); + if (ifix < 0) error->all(FLERR,"Could not find pair fix neigh history ID"); + fix_history = (FixNeighHistory *) modify->fix[ifix]; + } +} + +/* ---------------------------------------------------------------------- + init for one type pair i,j and corresponding j,i +------------------------------------------------------------------------- */ + +double PairGranHookeHistoryMulti::init_one(int i, int j) +{ + if (setflag[i][j] == 0) { + kn[i][j] = mix_stiffness(kn[i][i],kn[j][j]); + kt[i][j] = mix_stiffness(kt[i][i],kt[j][j]); + gamman[i][j] = mix_damping(gamman[i][i],gamman[j][j]); + gammat[i][j] = mix_damping(gammat[i][i],gammat[j][j]); + xmu[i][j] = mix_friction(xmu[i][i],xmu[j][j]); + + dampflag[i][j] = 0; + if (dampflag[i][i] || dampflag[j][j]) dampflag[i][j] = 1; + + } + + kn[j][i] = kn[i][j]; + kt[j][i] = kt[i][j]; + gamman[j][i] = gamman[i][j]; + gammat[j][i] = gammat[i][j]; + xmu[j][i] = xmu[i][j]; + dampflag[j][i] = dampflag[i][j]; + + double cutoff = cut[i][j]; + + // It is likely that cut[i][j] at this point is still 0.0. This can happen when + // there is a future fix_pour after the current run. A cut[i][j] = 0.0 creates + // problems because neighbor.cpp uses min(cut[i][j]) to decide on the bin size + // To avoid this issue,for cases involving cut[i][j] = 0.0 (possible only + // if there is no current information about radius/cutoff of type i and j). + // we assign cutoff = min(cut[i][j]) for i,j such that cut[i][j] > 0.0. + + if (cut[i][j] < 0.0) { + if (((maxrad_dynamic[i] > 0.0) && (maxrad_dynamic[j] > 0.0)) || ((maxrad_dynamic[i] > 0.0) && (maxrad_frozen[j] > 0.0)) || + ((maxrad_frozen[i] > 0.0) && (maxrad_dynamic[j] > 0.0))) { // radius info about both i and j exist + cutoff = maxrad_dynamic[i]+maxrad_dynamic[j]; + cutoff = MAX(cutoff,maxrad_frozen[i]+maxrad_dynamic[j]); + cutoff = MAX(cutoff,maxrad_dynamic[i]+maxrad_frozen[j]); + } + else { // radius info about either i or j does not exist (i.e. not present and not about to get poured; set to largest value to not interfere with neighbor list) + double cutmax = 0.0; + for (int k = 1; k <= atom->ntypes; k++) { + cutmax = MAX(cutmax,2.0*maxrad_dynamic[k]); + cutmax = MAX(cutmax,2.0*maxrad_frozen[k]); + } + cutoff = cutmax; + } + } + return cutoff; +} + +/* ---------------------------------------------------------------------- + proc 0 writes to restart file +------------------------------------------------------------------------- */ + +void PairGranHookeHistoryMulti::write_restart(FILE *fp) +{ + write_restart_settings(fp); + + int i,j; + for (i = 1; i <= atom->ntypes; i++) { + for (j = i; j <= atom->ntypes; j++) { + fwrite(&setflag[i][j],sizeof(int),1,fp); + if (setflag[i][j]) { + fwrite(&kn[i][j],sizeof(double),1,fp); + fwrite(&kt[i][j],sizeof(double),1,fp); + fwrite(&gamman[i][j],sizeof(double),1,fp); + fwrite(&gammat[i][j],sizeof(double),1,fp); + fwrite(&xmu[i][j],sizeof(double),1,fp); + fwrite(&dampflag[i][j],sizeof(int),1,fp); + fwrite(&cut[i][j],sizeof(double),1,fp); + } + } + } +} + +/* ---------------------------------------------------------------------- + proc 0 reads from restart file, bcasts +------------------------------------------------------------------------- */ + +void PairGranHookeHistoryMulti::read_restart(FILE *fp) +{ + read_restart_settings(fp); + allocate(); + + int i,j; + int me = comm->me; + for (i = 1; i <= atom->ntypes; i++) { + for (j = i; j <= atom->ntypes; j++) { + if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp); + MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world); + if (setflag[i][j]) { + if (me == 0) { + fread(&kn[i][j],sizeof(double),1,fp); + fread(&kt[i][j],sizeof(double),1,fp); + fread(&gamman[i][j],sizeof(double),1,fp); + fread(&gammat[i][j],sizeof(double),1,fp); + fread(&xmu[i][j],sizeof(double),1,fp); + fread(&dampflag[i][j],sizeof(int),1,fp); + fread(&cut[i][j],sizeof(double),1,fp); + } + MPI_Bcast(&kn[i][j],1,MPI_DOUBLE,0,world); + MPI_Bcast(&kt[i][j],1,MPI_DOUBLE,0,world); + MPI_Bcast(&gamman[i][j],1,MPI_DOUBLE,0,world); + MPI_Bcast(&gammat[i][j],1,MPI_DOUBLE,0,world); + MPI_Bcast(&xmu[i][j],1,MPI_DOUBLE,0,world); + MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); + MPI_Bcast(&dampflag[i][j],1,MPI_INT,0,world); + } + } + } +} + +/* ---------------------------------------------------------------------- + proc 0 writes to restart file +------------------------------------------------------------------------- */ + +void PairGranHookeHistoryMulti::write_restart_settings(FILE *fp) +{ + fwrite(&cut_global,sizeof(double),1,fp); +} + +/* ---------------------------------------------------------------------- + proc 0 reads from restart file, bcasts +------------------------------------------------------------------------- */ + +void PairGranHookeHistoryMulti::read_restart_settings(FILE *fp) +{ + if (comm->me == 0) { + fread(&cut_global,sizeof(double),1,fp); + } + MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world); +} + +/* ---------------------------------------------------------------------- */ + +void PairGranHookeHistoryMulti::reset_dt() +{ + dt = update->dt; +} + +/* ---------------------------------------------------------------------- */ + +double PairGranHookeHistoryMulti::single(int i, int j, int itype, int jtype, + double rsq, + double factor_coul, double factor_lj, + double &fforce) +{ + double radi,radj,radsum; + double r,rinv,rsqinv,delx,dely,delz; + double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3,wr1,wr2,wr3; + double mi,mj,meff,damp,ccel; + double vtr1,vtr2,vtr3,vrel,shrmag,rsht; + double fs1,fs2,fs3,fs,fn; + + double *radius = atom->radius; + radi = radius[i]; + radj = radius[j]; + radsum = radi + radj; + + if (rsq >= radsum*radsum) { + fforce = 0.0; + for (int m = 0; m < single_extra; m++) svector[m] = 0.0; + return 0.0; + } + + r = sqrt(rsq); + rinv = 1.0/r; + rsqinv = 1.0/rsq; + + // relative translational velocity + + double **v = atom->v; + vr1 = v[i][0] - v[j][0]; + vr2 = v[i][1] - v[j][1]; + vr3 = v[i][2] - v[j][2]; + + // normal component + + double **x = atom->x; + delx = x[i][0] - x[j][0]; + dely = x[i][1] - x[j][1]; + delz = x[i][2] - x[j][2]; + + vnnr = vr1*delx + vr2*dely + vr3*delz; + vn1 = delx*vnnr * rsqinv; + vn2 = dely*vnnr * rsqinv; + vn3 = delz*vnnr * rsqinv; + + // tangential component + + vt1 = vr1 - vn1; + vt2 = vr2 - vn2; + vt3 = vr3 - vn3; + + // relative rotational velocity + + double **omega = atom->omega; + wr1 = (radi*omega[i][0] + radj*omega[j][0]) * rinv; + wr2 = (radi*omega[i][1] + radj*omega[j][1]) * rinv; + wr3 = (radi*omega[i][2] + radj*omega[j][2]) * rinv; + + // meff = effective mass of pair of particles + // if I or J part of rigid body, use body mass + // if I or J is frozen, meff is other particle + + double *rmass = atom->rmass; + int *mask = atom->mask; + + mi = rmass[i]; + mj = rmass[j]; + if (fix_rigid) { + // NOTE: insure mass_rigid is current for owned+ghost atoms? + if (mass_rigid[i] > 0.0) mi = mass_rigid[i]; + if (mass_rigid[j] > 0.0) mj = mass_rigid[j]; + } + + meff = mi*mj / (mi+mj); + if (mask[i] & freeze_group_bit) meff = mj; + if (mask[j] & freeze_group_bit) meff = mi; + + // normal forces = Hookian contact + normal velocity damping + + damp = meff*gamman[itype][jtype]*vnnr*rsqinv; + ccel = kn[itype][jtype]*(radsum-r)*rinv - damp; + + // relative velocities + + vtr1 = vt1 - (delz*wr2-dely*wr3); + vtr2 = vt2 - (delx*wr3-delz*wr1); + vtr3 = vt3 - (dely*wr1-delx*wr2); + vrel = vtr1*vtr1 + vtr2*vtr2 + vtr3*vtr3; + vrel = sqrt(vrel); + + // shear history effects + // neighprev = index of found neigh on previous call + // search entire jnum list of neighbors of I for neighbor J + // start from neighprev, since will typically be next neighbor + // reset neighprev to 0 as necessary + + int jnum = list->numneigh[i]; + int *jlist = list->firstneigh[i]; + double *allshear = fix_history->firstvalue[i]; + + for (int jj = 0; jj < jnum; jj++) { + neighprev++; + if (neighprev >= jnum) neighprev = 0; + if (jlist[neighprev] == j) break; + } + + double *shear = &allshear[3*neighprev]; + shrmag = sqrt(shear[0]*shear[0] + shear[1]*shear[1] + + shear[2]*shear[2]); + + // rotate shear displacements + + rsht = shear[0]*delx + shear[1]*dely + shear[2]*delz; + rsht *= rsqinv; + + // tangential forces = shear + tangential velocity damping + + fs1 = - (kt[itype][jtype]*shear[0] + meff*gammat[itype][jtype]*vtr1); + fs2 = - (kt[itype][jtype]*shear[1] + meff*gammat[itype][jtype]*vtr2); + fs3 = - (kt[itype][jtype]*shear[2] + meff*gammat[itype][jtype]*vtr3); + + // rescale frictional displacements and forces if needed + + fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); + fn = xmu[itype][jtype] * fabs(ccel*r); + + if (fs > fn) { + if (shrmag != 0.0) { + fs1 *= fn/fs; + fs2 *= fn/fs; + fs3 *= fn/fs; + fs *= fn/fs; + } else fs1 = fs2 = fs3 = fs = 0.0; + } + + // set force and return no energy + + fforce = ccel; + + // set single_extra quantities + + svector[0] = fs1; + svector[1] = fs2; + svector[2] = fs3; + svector[3] = fs; + svector[4] = vn1; + svector[5] = vn2; + svector[6] = vn3; + svector[7] = vt1; + svector[8] = vt2; + svector[9] = vt3; + + return 0.0; +} + +/* ---------------------------------------------------------------------- */ + +int PairGranHookeHistoryMulti::pack_forward_comm(int n, int *list, double *buf, + int pbc_flag, int *pbc) +{ + int i,j,m; + + m = 0; + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = mass_rigid[j]; + } + return m; +} + +/* ---------------------------------------------------------------------- */ + +void PairGranHookeHistoryMulti::unpack_forward_comm(int n, int first, double *buf) +{ + int i,m,last; + + m = 0; + last = first + n; + for (i = first; i < last; i++) + mass_rigid[i] = buf[m++]; +} + +/* ---------------------------------------------------------------------- + memory usage of local atom-based arrays +------------------------------------------------------------------------- */ + +double PairGranHookeHistoryMulti::memory_usage() +{ + double bytes = nmax * sizeof(double); + return bytes; +} + +/* ---------------------------------------------------------------------- + mixing of stiffness +------------------------------------------------------------------------- */ + +double PairGranHookeHistoryMulti::mix_stiffness(double kii, double kjj) +{ + return kii*kjj/(kii + kjj); +} + +/* ---------------------------------------------------------------------- + mixing of damping +------------------------------------------------------------------------- */ + +double PairGranHookeHistoryMulti::mix_damping(double gammaii, double gammajj) +{ + return sqrt(gammaii*gammajj); +} + +/* ---------------------------------------------------------------------- + mixing of friction +------------------------------------------------------------------------- */ + +double PairGranHookeHistoryMulti::mix_friction(double xmuii, double xmujj) +{ + return MAX(xmuii,xmujj); +} + diff --git a/src/GRANULAR/pair_gran_hooke_history_multi.h b/src/GRANULAR/pair_gran_hooke_history_multi.h new file mode 100644 index 0000000000..f302ede96c --- /dev/null +++ b/src/GRANULAR/pair_gran_hooke_history_multi.h @@ -0,0 +1,109 @@ +/* -*- 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. +------------------------------------------------------------------------- */ + +#ifdef PAIR_CLASS + +PairStyle(gran/hooke/history/multi,PairGranHookeHistoryMulti) + +#else + +#ifndef LMP_PAIR_GRAN_HOOKE_HISTORY_MULTI_H +#define LMP_PAIR_GRAN_HOOKE_HISTORY_MULTI_H + +#include "pair.h" + +namespace LAMMPS_NS { + +class PairGranHookeHistoryMulti : public Pair { + public: + PairGranHookeHistoryMulti(class LAMMPS *); + virtual ~PairGranHookeHistoryMulti(); + virtual void compute(int, int); + virtual void settings(int, char **); + virtual void coeff(int, char **); // Made Virtual by IS Oct 7 2017 + void init_style(); + double init_one(int, int); + void write_restart(FILE *); + void read_restart(FILE *); + void write_restart_settings(FILE *); + void read_restart_settings(FILE *); + void reset_dt(); + virtual double single(int, int, int, int, double, double, double, double &); + int pack_forward_comm(int, int *, double *, int, int *); + void unpack_forward_comm(int, int, double *); + double memory_usage(); + + protected: + double cut_global; + double **kn,**kt,**gamman,**gammat,**xmu,**cut; + int **dampflag; + double dt; + int freeze_group_bit; + int history; + + int neighprev; + double *onerad_dynamic,*onerad_frozen; + double *maxrad_dynamic,*maxrad_frozen; + + class FixNeighHistory *fix_history; + + // storage of rigid body masses for use in granular interactions + + class Fix *fix_rigid; // ptr to rigid body fix, NULL if none + double *mass_rigid; // rigid mass for owned+ghost atoms + int nmax; // allocated size of mass_rigid + + virtual void allocate(); // Made Virtual by IS Oct 7 2017 + +private: + double mix_stiffness(double kii, double kjj); + double mix_damping(double gammaii, double gammajj); + double mix_friction(double xmuii, double xmujj); +}; + +} + +#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 granular requires atom attributes radius, rmass + +The atom style defined does not have these attributes. + +E: Pair granular requires ghost atoms store velocity + +Use the comm_modify vel yes command to enable this. + +E: Pair granular with shear history requires newton pair off + +This is a current restriction of the implementation of pair +granular styles with history. + +E: Could not find pair fix ID + +A fix is created internally by the pair style to store shear +history information. You cannot delete it. + +*/ diff --git a/src/GRANULAR/pair_gran_jkr_rolling_multi.cpp b/src/GRANULAR/pair_gran_jkr_rolling_multi.cpp new file mode 100644 index 0000000000..a9156390e5 --- /dev/null +++ b/src/GRANULAR/pair_gran_jkr_rolling_multi.cpp @@ -0,0 +1,1181 @@ +/* ---------------------------------------------------------------------- +http://lammps.sandia.gov, Sandia National Laboratories +Steve Plimpton, sjplimp@sandia.gov + +Copyright (2003) Sandia Corporation. Under the terms of Contract +DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains +certain rights in this software. This software is distributed under +the GNU General Public License. + +See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Contributing authors: Leo Silbert (SNL), Gary Grest (SNL) + ------------------------------------------------------------------------- */ + +#include +#include +#include +#include +#include "pair_gran_jkr_rolling_multi.h" +#include "atom.h" +#include "atom_vec.h" +#include "domain.h" +#include "force.h" +#include "update.h" +#include "modify.h" +#include "fix.h" +#include "fix_neigh_history.h" +#include "comm.h" +#include "neighbor.h" +#include "neigh_list.h" +#include "neigh_request.h" +#include "memory.h" +#include "error.h" +#include "math_const.h" +//#include + +using namespace LAMMPS_NS; +using namespace MathConst; + +#define ONETHIRD 0.33333333333333333 +#define TWOTHIRDS 0.66666666666666666 +#define POW6ONE 0.550321208149104 //6^(-1/3) +#define POW6TWO 0.30285343213869 //6^(-2/3) + +#define EPSILON 1e-10 + +enum {TSUJI, BRILLIANTOV}; +enum {INDEP, BRILLROLL}; + +/* ---------------------------------------------------------------------- */ + +PairGranJKRRollingMulti::PairGranJKRRollingMulti(LAMMPS *lmp) : Pair(lmp) +{ + single_enable = 1; + no_virial_fdotr_compute = 1; + history = 1; + fix_history = NULL; + + single_extra = 10; + svector = new double[10]; + + neighprev = 0; + + nmax = 0; + mass_rigid = NULL; + + // set comm size needed by this Pair if used with fix rigid + + comm_forward = 1; +} + +/* ---------------------------------------------------------------------- */ +PairGranJKRRollingMulti::~PairGranJKRRollingMulti() +{ + delete [] svector; + if (fix_history) modify->delete_fix("NEIGH_HISTORY"); + + if (allocated) { + memory->destroy(setflag); + memory->destroy(cutsq); + + memory->destroy(cut); + memory->destroy(E); + memory->destroy(G); + memory->destroy(normaldamp); + memory->destroy(rollingdamp); + memory->destroy(alpha); + memory->destroy(gamman); + memory->destroy(muS); + memory->destroy(Ecoh); + memory->destroy(kR); + memory->destroy(muR); + memory->destroy(etaR); + + delete [] onerad_dynamic; + delete [] onerad_frozen; + delete [] maxrad_dynamic; + delete [] maxrad_frozen; + } + memory->destroy(mass_rigid); +} +/* ---------------------------------------------------------------------- */ + +void PairGranJKRRollingMulti::compute(int eflag, int vflag) +{ +// feenableexcept(FE_INVALID | FE_OVERFLOW); + int i,j,ii,jj,inum,jnum,itype,jtype; + double xtmp,ytmp,ztmp,delx,dely,delz,fx,fy,fz,nx,ny,nz; + double radi,radj,radsum,rsq,r,rinv,rsqinv,R,a; + double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3; + double wr1,wr2,wr3; + double vtr1,vtr2,vtr3,vrel; + double kn, kt, k_Q, k_R, eta_N, eta_T, eta_Q, eta_R; + double Fne, Fdamp, Fntot, Fscrit, Frcrit, F_C, delta_C, delta_Cinv; + double overlap, olapsq, olapcubed, sqrtterm, tmp, a0; + double keyterm, keyterm2, keyterm3, aovera0, foverFc; + double mi,mj,meff,damp,ccel,tor1,tor2,tor3; + double relrot1,relrot2,relrot3,vrl1,vrl2,vrl3,vrlmag,vrlmaginv; + double rollmag, rolldotn, scalefac; + double fr, fr1, fr2, fr3; + double signtwist, magtwist, magtortwist, Mtcrit; + double fs,fs1,fs2,fs3,roll1,roll2,roll3,torroll1,torroll2,torroll3; + double tortwist1, tortwist2, tortwist3; + double shrmag,rsht; + int *ilist,*jlist,*numneigh,**firstneigh; + int *touch,**firsttouch; + double *shear,*allshear,**firstshear; + + if (eflag || vflag) ev_setup(eflag,vflag); + else evflag = vflag_fdotr = 0; + + int shearupdate = 1; + if (update->setupflag) shearupdate = 0; + + // update rigid body info for owned & ghost atoms if using FixRigid masses + // body[i] = which body atom I is in, -1 if none + // mass_body = mass of each rigid body + + if (fix_rigid && neighbor->ago == 0){ + int tmp; + int *body = (int *) fix_rigid->extract("body",tmp); + double *mass_body = (double *) fix_rigid->extract("masstotal",tmp); + if (atom->nmax > nmax) { + memory->destroy(mass_rigid); + nmax = atom->nmax; + memory->create(mass_rigid,nmax,"pair:mass_rigid"); + } + int nlocal = atom->nlocal; + for (i = 0; i < nlocal; i++) + if (body[i] >= 0) mass_rigid[i] = mass_body[body[i]]; + else mass_rigid[i] = 0.0; + comm->forward_comm_pair(this); + } + + double **x = atom->x; + double **v = atom->v; + double **f = atom->f; + int *type = atom->type; + double **omega = atom->omega; + double **torque = atom->torque; + double *radius = atom->radius; + double *rmass = atom->rmass; + int *mask = atom->mask; + int nlocal = atom->nlocal; + int newton_pair = force->newton_pair; + + inum = list->inum; + ilist = list->ilist; + numneigh = list->numneigh; + firstneigh = list->firstneigh; + firsttouch = fix_history->firstflag; + firstshear = fix_history->firstvalue; + + // loop over neighbors of my atoms + + for (ii = 0; ii < inum; ii++) { + i = ilist[ii]; + xtmp = x[i][0]; + ytmp = x[i][1]; + ztmp = x[i][2]; + itype = type[i]; + radi = radius[i]; + touch = firsttouch[i]; + allshear = firstshear[i]; + jlist = firstneigh[i]; + jnum = numneigh[i]; + + for (jj = 0; jj < jnum; jj++) { + j = jlist[jj]; + j &= NEIGHMASK; + + delx = xtmp - x[j][0]; + dely = ytmp - x[j][1]; + delz = ztmp - x[j][2]; + jtype = type[j]; + rsq = delx*delx + dely*dely + delz*delz; + radj = radius[j]; + radsum = radi + radj; + R = radi*radj/(radi+radj); + a0 = pow(9.0*M_PI*Ecoh[itype][jtype]*R*R/E[itype][jtype],ONETHIRD); + delta_C = 0.5*a0*a0*POW6ONE/R; + + if ((rsq >= radsum*radsum && touch[jj] == 0) || + (rsq >= (radsum+delta_C)*(radsum+delta_C))) { + + // unset non-touching neighbors + + touch[jj] = 0; + shear = &allshear[3*jj]; + shear[0] = 0.0; + shear[1] = 0.0; + shear[2] = 0.0; + + } else { + F_C = 3.0*R*M_PI*Ecoh[itype][jtype]; + r = sqrt(rsq); + rinv = 1.0/r; + rsqinv = 1.0/rsq; + + nx = delx*rinv; + ny = dely*rinv; + nz = delz*rinv; + + // relative translational velocity + + vr1 = v[i][0] - v[j][0]; + vr2 = v[i][1] - v[j][1]; + vr3 = v[i][2] - v[j][2]; + + // normal component + + vnnr = vr1*nx + vr2*ny + vr3*nz; //v_R . n + vn1 = nx*vnnr; + vn2 = ny*vnnr; + vn3 = nz*vnnr; + + // meff = effective mass of pair of particles + // if I or J part of rigid body, use body mass + // if I or J is frozen, meff is other particle + + mi = rmass[i]; + mj = rmass[j]; + if (fix_rigid) { + if (mass_rigid[i] > 0.0) mi = mass_rigid[i]; + if (mass_rigid[j] > 0.0) mj = mass_rigid[j]; + } + + meff = mi*mj / (mi+mj); + if (mask[i] & freeze_group_bit) meff = mj; + if (mask[j] & freeze_group_bit) meff = mi; + + //**************************************** + //Normal force = JKR-adjusted Hertzian contact + damping + //**************************************** + if (Ecoh[itype][jtype] != 0.0) delta_Cinv = 1.0/delta_C; + else delta_Cinv = 1.0; + overlap = (radsum - r)*delta_Cinv; + olapsq = overlap*overlap; + olapcubed = olapsq*overlap; + sqrtterm = sqrt(1.0 + olapcubed); + tmp = 2.0 + olapcubed + 2.0*sqrtterm; + keyterm = pow(tmp,ONETHIRD); + keyterm2 = olapsq/keyterm; + keyterm3 = sqrt(overlap + keyterm2 + keyterm); + aovera0 = POW6TWO * (keyterm3 + + sqrt(2.0*overlap - keyterm2 - keyterm + 4.0/keyterm3));// eq 41 + a = aovera0*a0; + foverFc = 4.0*((aovera0*aovera0*aovera0) - pow(aovera0,1.5));//F_ne/F_C (eq 40) + + Fne = F_C*foverFc; + + //Damping + kn = 4.0/3.0*E[itype][jtype]*a; + if (normaldamp[itype][jtype] == BRILLIANTOV) eta_N = a*meff*gamman[itype][jtype]; + else if (normaldamp[itype][jtype] == TSUJI) eta_N=alpha[itype][jtype]*sqrt(meff*kn); + + Fdamp = -eta_N*vnnr; //F_nd eq 23 and Zhao eq 19 + + Fntot = Fne + Fdamp; + //if (screen) fprintf(screen,"%d %d %16.16g %16.16g \n",itype,jtype,Ecoh[itype][jtype],E[itype][jtype]); + //if (logfile) fprintf(logfile,"%d %d %16.16g %16.16g \n",itype,jtype,Ecoh[itype][jtype],E[itype][jtype]); + + //**************************************** + //Tangential force, including shear history effects + //**************************************** + + // tangential component + vt1 = vr1 - vn1; + vt2 = vr2 - vn2; + vt3 = vr3 - vn3; + + // relative rotational velocity + // Luding Gran Matt 2008, v10,p235 suggests correcting radi and radj by subtracting + // delta/2, i.e. instead of radi, use distance to center of contact point? + wr1 = (radi*omega[i][0] + radj*omega[j][0]); + wr2 = (radi*omega[i][1] + radj*omega[j][1]); + wr3 = (radi*omega[i][2] + radj*omega[j][2]); + + // relative tangential velocities + vtr1 = vt1 - (nz*wr2-ny*wr3); + vtr2 = vt2 - (nx*wr3-nz*wr1); + vtr3 = vt3 - (ny*wr1-nx*wr2); + vrel = vtr1*vtr1 + vtr2*vtr2 + vtr3*vtr3; + vrel = sqrt(vrel); + + // shear history effects + touch[jj] = 1; + shear = &allshear[3*jj]; + shrmag = sqrt(shear[0]*shear[0] + shear[1]*shear[1] + + shear[2]*shear[2]); + + // Rotate and update shear displacements. + // See e.g. eq. 17 of Luding, Gran. Matter 2008, v10,p235 + if (shearupdate) { + rsht = shear[0]*nx + shear[1]*ny + shear[2]*nz; + if (fabs(rsht) < EPSILON) rsht = 0; + if (rsht > 0){ + scalefac = shrmag/(shrmag - rsht); //if rhst == shrmag, contacting pair has rotated 90 deg. in one step, in which case you deserve a crash! + shear[0] -= rsht*nx; + shear[1] -= rsht*ny; + shear[2] -= rsht*nz; + //Also rescale to preserve magnitude + shear[0] *= scalefac; + shear[1] *= scalefac; + shear[2] *= scalefac; + } + //Update shear history + shear[0] += vtr1*dt; + shear[1] += vtr2*dt; + shear[2] += vtr3*dt; + } + + // tangential forces = shear + tangential velocity damping + // following Zhao and Marshall Phys Fluids v20, p043302 (2008) + kt=8.0*G[itype][jtype]*a; + + eta_T = eta_N; //Based on discussion in Marshall; eta_T can also be an independent parameter + fs1 = -kt*shear[0] - eta_T*vtr1; //eq 26 + fs2 = -kt*shear[1] - eta_T*vtr2; + fs3 = -kt*shear[2] - eta_T*vtr3; + + // rescale frictional displacements and forces if needed + Fscrit = muS[itype][jtype] * fabs(Fne + 2*F_C); + // For JKR, use eq 43 of Marshall. For DMT, use Fne instead + + fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); + if (fs > Fscrit) { + if (shrmag != 0.0) { + //shear[0] = (Fcrit/fs) * (shear[0] + eta_T*vtr1/kt) - eta_T*vtr1/kt; + //shear[1] = (Fcrit/fs) * (shear[1] + eta_T*vtr1/kt) - eta_T*vtr1/kt; + //shear[2] = (Fcrit/fs) * (shear[2] + eta_T*vtr1/kt) - eta_T*vtr1/kt; + shear[0] = -1.0/kt*(Fscrit*fs1/fs + eta_T*vtr1); //Same as above, but simpler (check!) + shear[1] = -1.0/kt*(Fscrit*fs2/fs + eta_T*vtr2); + shear[2] = -1.0/kt*(Fscrit*fs3/fs + eta_T*vtr3); + fs1 *= Fscrit/fs; + fs2 *= Fscrit/fs; + fs3 *= Fscrit/fs; + } else fs1 = fs2 = fs3 = 0.0; + } + + //**************************************** + // Rolling force, including shear history effects + //**************************************** + + relrot1 = omega[i][0] - omega[j][0]; + relrot2 = omega[i][1] - omega[j][1]; + relrot3 = omega[i][2] - omega[j][2]; + + // rolling velocity, see eq. 31 of Wang et al, Particuology v 23, p 49 (2015) + // This is different from the Marshall papers, which use the Bagi/Kuhn formulation + // for rolling velocity (see Wang et al for why the latter is wrong) + vrl1 = R*(relrot2*nz - relrot3*ny); //- 0.5*((radj-radi)/radsum)*vtr1; + vrl2 = R*(relrot3*nx - relrot1*nz); //- 0.5*((radj-radi)/radsum)*vtr2; + vrl3 = R*(relrot1*ny - relrot2*nx); //- 0.5*((radj-radi)/radsum)*vtr3; + vrlmag = sqrt(vrl1*vrl1+vrl2*vrl2+vrl3*vrl3); + if (vrlmag != 0.0) vrlmaginv = 1.0/vrlmag; + else vrlmaginv = 0.0; + + // Rolling displacement + rollmag = sqrt(shear[3]*shear[3] + shear[4]*shear[4] + shear[5]*shear[5]); + rolldotn = shear[3]*nx + shear[4]*ny + shear[5]*nz; + + if (shearupdate) { + if (fabs(rolldotn) < EPSILON) rolldotn = 0; + if (rolldotn > 0){ //Rotate into tangential plane + scalefac = rollmag/(rollmag - rolldotn); + shear[3] -= rolldotn*nx; + shear[4] -= rolldotn*ny; + shear[5] -= rolldotn*nz; + //Also rescale to preserve magnitude + shear[3] *= scalefac; + shear[4] *= scalefac; + shear[5] *= scalefac; + } + shear[3] += vrl1*dt; + shear[4] += vrl2*dt; + shear[5] += vrl3*dt; + } + + k_R = kR[itype][jtype]*4.0*F_C*pow(aovera0,1.5); + if (rollingdamp[itype][jtype] == INDEP) eta_R = etaR[itype][jtype]; + else if (rollingdamp[itype][jtype] == BRILLROLL) eta_R = muR[itype][jtype]*fabs(Fne); + fr1 = -k_R*shear[3] - eta_R*vrl1; + fr2 = -k_R*shear[4] - eta_R*vrl2; + fr3 = -k_R*shear[5] - eta_R*vrl3; + + // rescale frictional displacements and forces if needed + Frcrit = muR[itype][jtype] * fabs(Fne + 2*F_C); + + fr = sqrt(fr1*fr1 + fr2*fr2 + fr3*fr3); + if (fr > Frcrit) { + if (rollmag != 0.0) { + shear[3] = -1.0/k_R*(Frcrit*fr1/fr + eta_R*vrl1); + shear[4] = -1.0/k_R*(Frcrit*fr2/fr + eta_R*vrl2); + shear[5] = -1.0/k_R*(Frcrit*fr3/fr + eta_R*vrl3); + fr1 *= Frcrit/fr; + fr2 *= Frcrit/fr; + fr3 *= Frcrit/fr; + } else fr1 = fr2 = fr3 = 0.0; + } + + + //**************************************** + // Twisting torque, including shear history effects + //**************************************** + magtwist = relrot1*nx + relrot2*ny + relrot3*nz; //Omega_T (eq 29 of Marshall) + shear[6] += magtwist*dt; + k_Q = 0.5*kt*a*a;; //eq 32 + eta_Q = 0.5*eta_T*a*a; + magtortwist = -k_Q*shear[6] - eta_Q*magtwist;//M_t torque (eq 30) + + signtwist = (magtwist > 0) - (magtwist < 0); + Mtcrit=TWOTHIRDS*a*Fscrit;//critical torque (eq 44) + if (fabs(magtortwist) > Mtcrit) { + //shear[6] = Mtcrit/k_Q*magtwist/fabs(magtwist); + shear[6] = 1.0/k_Q*(Mtcrit*signtwist - eta_Q*magtwist); + magtortwist = -Mtcrit * signtwist; //eq 34 + } + + // Apply forces & torques + + fx = nx*Fntot + fs1; + fy = ny*Fntot + fs2; + fz = nz*Fntot + fs3; + + //if (screen) fprintf(screen,"%16.16g %16.16g %16.16g %16.16g %16.16g %16.16g %16.16g \n",fs1,fs2,fs3,Fntot,nx,ny,nz); + //if (logfile) fprintf(logfile,"%16.16g %16.16g %16.16g %16.16g %16.16g %16.16g %16.16g \n",fs1,fs2,fs3,Fntot,nx,ny,nz); + + f[i][0] += fx; + f[i][1] += fy; + f[i][2] += fz; + + tor1 = ny*fs3 - nz*fs2; + tor2 = nz*fs1 - nx*fs3; + tor3 = nx*fs2 - ny*fs1; + + torque[i][0] -= radi*tor1; + torque[i][1] -= radi*tor2; + torque[i][2] -= radi*tor3; + + tortwist1 = magtortwist * nx; + tortwist2 = magtortwist * ny; + tortwist3 = magtortwist * nz; + + torque[i][0] += tortwist1; + torque[i][1] += tortwist2; + torque[i][2] += tortwist3; + + torroll1 = R*(ny*fr3 - nz*fr2); //n cross fr + torroll2 = R*(nz*fr1 - nx*fr3); + torroll3 = R*(nx*fr2 - ny*fr1); + + torque[i][0] += torroll1; + torque[i][1] += torroll2; + torque[i][2] += torroll3; + + if (force->newton_pair || j < nlocal) { + f[j][0] -= fx; + f[j][1] -= fy; + f[j][2] -= fz; + + torque[j][0] -= radj*tor1; + torque[j][1] -= radj*tor2; + torque[j][2] -= radj*tor3; + + torque[j][0] -= tortwist1; + torque[j][1] -= tortwist2; + torque[j][2] -= tortwist3; + + torque[j][0] -= torroll1; + torque[j][1] -= torroll2; + torque[j][2] -= torroll3; + } + if (evflag) ev_tally_xyz(i,j,nlocal,0, + 0.0,0.0,fx,fy,fz,delx,dely,delz); + } + } + } +} + + +/* ---------------------------------------------------------------------- + allocate all arrays + ------------------------------------------------------------------------- */ + +void PairGranJKRRollingMulti::allocate() +{ + allocated = 1; + int n = atom->ntypes; + + memory->create(setflag,n+1,n+1,"pair:setflag"); + for (int i = 1; i <= n; i++) + for (int j = i; j <= n; j++) + setflag[i][j] = 0; + + memory->create(cutsq,n+1,n+1,"pair:cutsq"); + memory->create(cut,n+1,n+1,"pair:cut"); + memory->create(E,n+1,n+1,"pair:E"); + memory->create(G,n+1,n+1,"pair:G"); + memory->create(normaldamp,n+1,n+1,"pair:normaldamp"); + memory->create(rollingdamp,n+1,n+1,"pair:rollingdamp"); + memory->create(alpha,n+1,n+1,"pair:alpha"); + memory->create(gamman,n+1,n+1,"pair:gamman"); + memory->create(muS,n+1,n+1,"pair:muS"); + memory->create(Ecoh,n+1,n+1,"pair:Ecoh"); + memory->create(kR,n+1,n+1,"pair:kR"); + memory->create(muR,n+1,n+1,"pair:muR"); + memory->create(etaR,n+1,n+1,"pair:etaR"); + + onerad_dynamic = new double[n+1]; + onerad_frozen = new double[n+1]; + maxrad_dynamic = new double[n+1]; + maxrad_frozen = new double[n+1]; +} + +/* ---------------------------------------------------------------------- + global settings + ------------------------------------------------------------------------- */ + +void PairGranJKRRollingMulti::settings(int narg, char **arg) +{ + if (narg != 1) error->all(FLERR,"Illegal pair_style command"); + + if (strcmp(arg[0],"NULL") == 0 ) cut_global = -1.0; + else cut_global = force->numeric(FLERR,arg[0]); + + // reset cutoffs that have been explicitly set + if (allocated) { + int i,j; + for (i = 1; i <= atom->ntypes; i++) + for (j = i; j <= atom->ntypes; j++) + if (setflag[i][j]) cut[i][j] = cut_global; + } +} + +/* ---------------------------------------------------------------------- + set coeffs for one or more type pairs + ------------------------------------------------------------------------- */ + +void PairGranJKRRollingMulti::coeff(int narg, char **arg) +{ + if (narg < 10 || narg > 15) + error->all(FLERR,"Incorrect args for pair coefficients2"); + + if (!allocated) allocate(); + + int ilo,ihi,jlo,jhi; + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); + + double E_one = force->numeric(FLERR,arg[2]); + double G_one = force->numeric(FLERR,arg[3]); + double muS_one = force->numeric(FLERR,arg[4]); + double cor_one = force->numeric(FLERR,arg[5]); + double Ecoh_one = force->numeric(FLERR,arg[6]); + double kR_one = force->numeric(FLERR,arg[7]); + double muR_one = force->numeric(FLERR,arg[8]); + double etaR_one = force->numeric(FLERR,arg[9]); + + //Defaults + int normaldamp_one = TSUJI; + int rollingdamp_one = INDEP; + double cut_one = cut_global; + + int iarg = 10; + while (iarg < narg) { + if (strcmp(arg[iarg],"normaldamp") == 0){ + if (iarg+2 > narg) error->all(FLERR, "Invalid pair/gran/dmt/rolling entry"); + if (strcmp(arg[iarg+1],"tsuji") == 0) normaldamp_one = TSUJI; + else if (strcmp(arg[iarg+1],"brilliantov") == 0) normaldamp_one = BRILLIANTOV; + else error->all(FLERR, "Invalid normal damping model for pair/gran/dmt/rolling"); + iarg += 2; + } + else if (strcmp(arg[iarg],"rollingdamp") == 0){ + if (iarg+2 > narg) error->all(FLERR, "Invalid pair/gran/dmt/rolling entry"); + if (strcmp(arg[iarg+1],"independent") == 0) rollingdamp_one = INDEP; + else if (strcmp(arg[iarg+1],"brilliantov") == 0) rollingdamp_one = BRILLROLL; + else error->all(FLERR, "Invalid rolling damping model for pair/gran/dmt/rolling"); + iarg +=2; + } + else { + if (strcmp(arg[iarg],"NULL") == 0) cut_one = -1.0; + else cut_one = force->numeric(FLERR,arg[iarg]); + iarg += 1; + } + } + + int count = 0; + for (int i = ilo; i <= ihi; i++) { + double pois = E_one/(2.0*G_one) - 1.0; + double alpha_one = 1.2728-4.2783*cor_one+11.087*cor_one*cor_one-22.348*cor_one*cor_one*cor_one+27.467*cor_one*cor_one*cor_one*cor_one-18.022*cor_one*cor_one*cor_one*cor_one*cor_one+4.8218*cor_one*cor_one*cor_one*cor_one*cor_one*cor_one; + + for (int j = MAX(jlo,i); j <= jhi; j++) { + E[i][j] = E_one; + G[i][j] = G_one; + if (normaldamp_one == TSUJI) { + normaldamp[i][j] = TSUJI; + alpha[i][j] = alpha_one; + } + else if (normaldamp_one == BRILLIANTOV) { + normaldamp[i][j] = BRILLIANTOV; + gamman[i][j] = cor_one; + } + if (rollingdamp_one == INDEP) { + rollingdamp[i][j] = INDEP; + } + else if (rollingdamp_one == BRILLROLL) { + rollingdamp[i][j] = BRILLROLL; + } + muS[i][j] = muS_one; + Ecoh[i][j] = Ecoh_one; + kR[i][j] = kR_one; + etaR[i][j] = etaR_one; + muR[i][j] = muR_one; + cut[i][j] = cut_one; + setflag[i][j] = 1; + count++; + } + } + + if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients1"); +} + +/* ---------------------------------------------------------------------- + init specific to this pair style + ------------------------------------------------------------------------- */ + +void PairGranJKRRollingMulti::init_style() +{ + int i; + + // error and warning checks + + if (!atom->radius_flag || !atom->rmass_flag) + error->all(FLERR,"Pair granular requires atom attributes radius, rmass"); + if (comm->ghost_velocity == 0) + error->all(FLERR,"Pair granular requires ghost atoms store velocity"); + + // need a granular neigh list + + int irequest = neighbor->request(this,instance_me); + neighbor->requests[irequest]->size = 1; + if (history) neighbor->requests[irequest]->history = 1; + + dt = update->dt; + + // if shear history is stored: + // if first init, create Fix needed for storing shear history + + if (history && fix_history == NULL) { + char dnumstr[16]; + sprintf(dnumstr,"%d",3); + char **fixarg = new char*[4]; + fixarg[0] = (char *) "NEIGH_HISTORY"; + fixarg[1] = (char *) "all"; + fixarg[2] = (char *) "NEIGH_HISTORY"; + fixarg[3] = dnumstr; + modify->add_fix(4,fixarg,1); + delete [] fixarg; + fix_history = (FixNeighHistory *) modify->fix[modify->nfix-1]; + fix_history->pair = this; + } + + // check for FixFreeze and set freeze_group_bit + + for (i = 0; i < modify->nfix; i++) + if (strcmp(modify->fix[i]->style,"freeze") == 0) break; + if (i < modify->nfix) freeze_group_bit = modify->fix[i]->groupbit; + else freeze_group_bit = 0; + + // check for FixRigid so can extract rigid body masses + + fix_rigid = NULL; + for (i = 0; i < modify->nfix; i++) + if (modify->fix[i]->rigid_flag) break; + if (i < modify->nfix) fix_rigid = modify->fix[i]; + + // check for FixPour and FixDeposit so can extract particle radii + + int ipour; + for (ipour = 0; ipour < modify->nfix; ipour++) + if (strcmp(modify->fix[ipour]->style,"pour") == 0) break; + if (ipour == modify->nfix) ipour = -1; + + int idep; + for (idep = 0; idep < modify->nfix; idep++) + if (strcmp(modify->fix[idep]->style,"deposit") == 0) break; + if (idep == modify->nfix) idep = -1; + + // set maxrad_dynamic and maxrad_frozen for each type + // include future FixPour and FixDeposit particles as dynamic + + int itype; + for (i = 1; i <= atom->ntypes; i++) { + onerad_dynamic[i] = onerad_frozen[i] = 0.0; + if (ipour >= 0) { + itype = i; + onerad_dynamic[i] = + *((double *) modify->fix[ipour]->extract("radius",itype)); + } + if (idep >= 0) { + itype = i; + onerad_dynamic[i] = + *((double *) modify->fix[idep]->extract("radius",itype)); + } + } + + double *radius = atom->radius; + int *mask = atom->mask; + int *type = atom->type; + int nlocal = atom->nlocal; + + for (i = 0; i < nlocal; i++) + if (mask[i] & freeze_group_bit) + onerad_frozen[type[i]] = MAX(onerad_frozen[type[i]],radius[i]); + else + onerad_dynamic[type[i]] = MAX(onerad_dynamic[type[i]],radius[i]); + + MPI_Allreduce(&onerad_dynamic[1],&maxrad_dynamic[1],atom->ntypes, + MPI_DOUBLE,MPI_MAX,world); + MPI_Allreduce(&onerad_frozen[1],&maxrad_frozen[1],atom->ntypes, + MPI_DOUBLE,MPI_MAX,world); + + // set fix which stores history info + + if (history) { + int ifix = modify->find_fix("NEIGH_HISTORY"); + if (ifix < 0) error->all(FLERR,"Could not find pair fix neigh history ID"); + fix_history = (FixNeighHistory *) modify->fix[ifix]; + } +} + +/* ---------------------------------------------------------------------- + init for one type pair i,j and corresponding j,i + ------------------------------------------------------------------------- */ + +double PairGranJKRRollingMulti::init_one(int i, int j) +{ + if (setflag[i][j] == 0) { + E[i][j] = mix_stiffnessE(E[i][i],E[j][j],G[i][i],G[j][j]); + G[i][j] = mix_stiffnessG(G[i][i],E[j][j],G[i][i],G[j][j]); + if (normaldamp[i][j] == TSUJI) { + alpha[i][j] = mix_geom(alpha[i][i],alpha[j][j]); + } + else if (normaldamp[i][j] == BRILLIANTOV) { + gamman[i][j] = mix_geom(gamman[i][i],gamman[j][j]); + } + muS[i][j] = mix_geom(muS[i][i],muS[j][j]); + Ecoh[i][j] = mix_geom(Ecoh[i][i],Ecoh[j][j]); + kR[i][j] = mix_geom(kR[i][i],kR[j][j]); + etaR[i][j] = mix_geom(etaR[i][i],etaR[j][j]); + muR[i][j] = mix_geom(muR[i][i],muR[j][j]); + } + + E[j][i] = E[i][j]; + G[j][i] = G[i][j]; + normaldamp[j][i] = normaldamp[i][j]; + alpha[j][i] = alpha[i][j]; + gamman[j][i] = gamman[i][j]; + rollingdamp[j][i] = rollingdamp[i][j]; + muS[j][i] = muS[i][j]; + Ecoh[j][i] = Ecoh[i][j]; + kR[j][i] = kR[i][j]; + etaR[j][i] = etaR[i][j]; + muR[j][i] = muR[i][j]; + + double cutoff = cut[i][j]; + + // It is likely that cut[i][j] at this point is still 0.0. This can happen when + // there is a future fix_pour after the current run. A cut[i][j] = 0.0 creates + // problems because neighbor.cpp uses min(cut[i][j]) to decide on the bin size + // To avoid this issue,for cases involving cut[i][j] = 0.0 (possible only + // if there is no current information about radius/cutoff of type i and j). + // we assign cutoff = min(cut[i][j]) for i,j such that cut[i][j] > 0.0. + + if (cut[i][j] < 0.0) { + if (((maxrad_dynamic[i] > 0.0) && (maxrad_dynamic[j] > 0.0)) || ((maxrad_dynamic[i] > 0.0) && (maxrad_frozen[j] > 0.0)) || + ((maxrad_frozen[i] > 0.0) && (maxrad_dynamic[j] > 0.0))) { // radius info about both i and j exist + cutoff = maxrad_dynamic[i]+maxrad_dynamic[j]; + cutoff = MAX(cutoff,maxrad_frozen[i]+maxrad_dynamic[j]); + cutoff = MAX(cutoff,maxrad_dynamic[i]+maxrad_frozen[j]); + } + else { // radius info about either i or j does not exist (i.e. not present and not about to get poured; set to largest value to not interfere with neighbor list) + double cutmax = 0.0; + for (int k = 1; k <= atom->ntypes; k++) { + cutmax = MAX(cutmax,2.0*maxrad_dynamic[k]); + cutmax = MAX(cutmax,2.0*maxrad_frozen[k]); + } + cutoff = cutmax; + } + } + return cutoff; +} + + +/* ---------------------------------------------------------------------- + proc 0 writes to restart file + ------------------------------------------------------------------------- */ + +void PairGranJKRRollingMulti::write_restart(FILE *fp) +{ + write_restart_settings(fp); + + int i,j; + for (i = 1; i <= atom->ntypes; i++) { + for (j = i; j <= atom->ntypes; j++) { + fwrite(&setflag[i][j],sizeof(int),1,fp); + if (setflag[i][j]) { + fwrite(&E[i][j],sizeof(double),1,fp); + fwrite(&G[i][j],sizeof(double),1,fp); + fwrite(&normaldamp[i][j],sizeof(int),1,fp); + fwrite(&rollingdamp[i][j],sizeof(int),1,fp); + fwrite(&alpha[i][j],sizeof(double),1,fp); + fwrite(&gamman[i][j],sizeof(double),1,fp); + fwrite(&muS[i][j],sizeof(double),1,fp); + fwrite(&Ecoh[i][j],sizeof(double),1,fp); + fwrite(&kR[i][j],sizeof(double),1,fp); + fwrite(&muR[i][j],sizeof(double),1,fp); + fwrite(&etaR[i][j],sizeof(double),1,fp); + fwrite(&cut[i][j],sizeof(double),1,fp); + } + } + } +} + +/* ---------------------------------------------------------------------- + proc 0 reads from restart file, bcasts + ------------------------------------------------------------------------- */ + +void PairGranJKRRollingMulti::read_restart(FILE *fp) +{ + read_restart_settings(fp); + allocate(); + + int i,j; + int me = comm->me; + for (i = 1; i <= atom->ntypes; i++) { + for (j = i; j <= atom->ntypes; j++) { + if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp); + MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world); + if (setflag[i][j]) { + if (me == 0) { + fread(&E[i][j],sizeof(double),1,fp); + fread(&G[i][j],sizeof(double),1,fp); + fread(&normaldamp[i][j],sizeof(int),1,fp); + fread(&rollingdamp[i][j],sizeof(int),1,fp); + fread(&alpha[i][j],sizeof(double),1,fp); + fread(&gamman[i][j],sizeof(double),1,fp); + fread(&muS[i][j],sizeof(double),1,fp); + fread(&Ecoh[i][j],sizeof(double),1,fp); + fread(&kR[i][j],sizeof(double),1,fp); + fread(&muR[i][j],sizeof(double),1,fp); + fread(&etaR[i][j],sizeof(double),1,fp); + fread(&cut[i][j],sizeof(double),1,fp); + } + MPI_Bcast(&E[i][j],1,MPI_DOUBLE,0,world); + MPI_Bcast(&G[i][j],1,MPI_DOUBLE,0,world); + MPI_Bcast(&normaldamp[i][j],1,MPI_INT,0,world); + MPI_Bcast(&rollingdamp[i][j],1,MPI_INT,0,world); + MPI_Bcast(&alpha[i][j],1,MPI_DOUBLE,0,world); + MPI_Bcast(&gamman[i][j],1,MPI_DOUBLE,0,world); + MPI_Bcast(&muS[i][j],1,MPI_DOUBLE,0,world); + MPI_Bcast(&Ecoh[i][j],1,MPI_DOUBLE,0,world); + MPI_Bcast(&kR[i][j],1,MPI_DOUBLE,0,world); + MPI_Bcast(&muR[i][j],1,MPI_DOUBLE,0,world); + MPI_Bcast(&etaR[i][j],1,MPI_DOUBLE,0,world); + MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); + } + } + } +} + +/* ---------------------------------------------------------------------- + proc 0 writes to restart file + ------------------------------------------------------------------------- */ + +void PairGranJKRRollingMulti::write_restart_settings(FILE *fp) +{ + fwrite(&cut_global,sizeof(double),1,fp); +} + +/* ---------------------------------------------------------------------- + proc 0 reads from restart file, bcasts + ------------------------------------------------------------------------- */ + +void PairGranJKRRollingMulti::read_restart_settings(FILE *fp) +{ + if (comm->me == 0) { + fread(&cut_global,sizeof(double),1,fp); + } + MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world); +} + +/* ---------------------------------------------------------------------- */ + +void PairGranJKRRollingMulti::reset_dt() +{ + dt = update->dt; +} + +/* ---------------------------------------------------------------------- */ + +double PairGranJKRRollingMulti::single(int i, int j, int itype, int jtype, + double rsq, double factor_coul, double factor_lj, double &fforce) +{ +// feenableexcept(FE_INVALID | FE_OVERFLOW); + double radi,radj,radsum; + double r,rinv,rsqinv,delx,dely,delz, nx, ny, nz, R; + double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3,wr1,wr2,wr3; + double overlap, a; + double mi,mj,meff,damp,kn,kt; + double Fdamp,Fne,Fntot,Fscrit; + double eta_N,eta_T; + double vtr1,vtr2,vtr3,vrel; + double fs1,fs2,fs3,fs; + double shrmag; + double F_C, delta_C, olapsq, olapcubed, sqrtterm, tmp, a0; + double keyterm, keyterm2, keyterm3, aovera0, foverFc; + + double *radius = atom->radius; + radi = radius[i]; + radj = radius[j]; + radsum = radi + radj; + + r = sqrt(rsq); + rinv = 1.0/r; + rsqinv = 1.0/rsq; + R = radi*radj/(radi+radj); + a0 = pow(9.0*M_PI*Ecoh[itype][jtype]*R*R/E[itype][jtype],ONETHIRD); + delta_C = 0.5*a0*a0*POW6ONE/R; + + int *touch = fix_history->firstflag[i]; + if ((rsq >= (radsum+delta_C)*(radsum+delta_C) )|| + (rsq >= radsum*radsum && touch[j])){ + fforce = 0.0; + svector[0] = svector[1] = svector[2] = svector[3] = 0.0; + return 0.0; + } + + // relative translational velocity + + double **v = atom->v; + vr1 = v[i][0] - v[j][0]; + vr2 = v[i][1] - v[j][1]; + vr3 = v[i][2] - v[j][2]; + + // normal component + + double **x = atom->x; + delx = x[i][0] - x[j][0]; + dely = x[i][1] - x[j][1]; + delz = x[i][2] - x[j][2]; + + nx = delx*rinv; + ny = dely*rinv; + nz = delz*rinv; + + + vnnr = vr1*nx + vr2*ny + vr3*nz; + vn1 = nx*vnnr; + vn2 = ny*vnnr; + vn3 = nz*vnnr; + + // tangential component + + vt1 = vr1 - vn1; + vt2 = vr2 - vn2; + vt3 = vr3 - vn3; + + // relative rotational velocity + + double **omega = atom->omega; + wr1 = (radi*omega[i][0] + radj*omega[j][0]); + wr2 = (radi*omega[i][1] + radj*omega[j][1]); + wr3 = (radi*omega[i][2] + radj*omega[j][2]); + + // meff = effective mass of pair of particles + // if I or J part of rigid body, use body mass + // if I or J is frozen, meff is other particle + + double *rmass = atom->rmass; + int *type = atom->type; + int *mask = atom->mask; + + mi = rmass[i]; + mj = rmass[j]; + if (fix_rigid) { + // NOTE: ensure mass_rigid is current for owned+ghost atoms? + if (mass_rigid[i] > 0.0) mi = mass_rigid[i]; + if (mass_rigid[j] > 0.0) mj = mass_rigid[j]; + } + + meff = mi*mj / (mi+mj); + if (mask[i] & freeze_group_bit) meff = mj; + if (mask[j] & freeze_group_bit) meff = mi; + + + // normal force = JKR + F_C = 3.0*R*M_PI*Ecoh[itype][jtype]; + overlap = radsum - r; + olapsq = overlap*overlap; + olapcubed = olapsq*olapsq; + sqrtterm = sqrt(1.0 + olapcubed); + tmp = 2.0 + olapcubed + 2.0*sqrtterm; + keyterm = pow(tmp,ONETHIRD); + keyterm2 = olapsq/keyterm; + keyterm3 = sqrt(overlap + keyterm2 + keyterm); + aovera0 = POW6TWO * (keyterm3 + + sqrt(2.0*overlap - keyterm2 - keyterm + 4.0/keyterm3));// eq 41 + a = aovera0*a0; + foverFc = 4.0*((aovera0*aovera0*aovera0) - pow(aovera0,1.5));//F_ne/F_C (eq 40) + + Fne = F_C*foverFc; + + //Damping + kn = 4.0/3.0*E[itype][jtype]*a; + if (normaldamp[itype][jtype] == BRILLIANTOV) eta_N = a*meff*gamman[itype][jtype]; + else if (normaldamp[itype][jtype] == TSUJI) eta_N=alpha[itype][jtype]*sqrt(meff*kn); + + Fdamp = -eta_N*vnnr; //F_nd eq 23 and Zhao eq 19 + + Fntot = Fne + Fdamp; + + // relative velocities + + vtr1 = vt1 - (nz*wr2-ny*wr3); + vtr2 = vt2 - (nx*wr3-nz*wr1); + vtr3 = vt3 - (ny*wr1-nx*wr2); + vrel = vtr1*vtr1 + vtr2*vtr2 + vtr3*vtr3; + vrel = sqrt(vrel); + + // shear history effects + // neighprev = index of found neigh on previous call + // search entire jnum list of neighbors of I for neighbor J + // start from neighprev, since will typically be next neighbor + // reset neighprev to 0 as necessary + + int jnum = list->numneigh[i]; + int *jlist = list->firstneigh[i]; + double *allshear = fix_history->firstvalue[i]; + + for (int jj = 0; jj < jnum; jj++) { + neighprev++; + if (neighprev >= jnum) neighprev = 0; + if (jlist[neighprev] == j) break; + } + + double *shear = &allshear[3*neighprev]; + shrmag = sqrt(shear[0]*shear[0] + shear[1]*shear[1] + + shear[2]*shear[2]); + + // tangential forces = shear + tangential velocity damping + kt=8.0*G[itype][jtype]*a; + + eta_T = eta_N; + fs1 = -kt*shear[0] - eta_T*vtr1; + fs2 = -kt*shear[1] - eta_T*vtr2; + fs3 = -kt*shear[2] - eta_T*vtr3; + + // rescale frictional displacements and forces if needed + + fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); + Fscrit= muS[itype][jtype] * fabs(Fne + 2*F_C); + + if (fs > Fscrit) { + if (shrmag != 0.0) { + fs1 *= Fscrit/fs; + fs2 *= Fscrit/fs; + fs3 *= Fscrit/fs; + fs *= Fscrit/fs; + } else fs1 = fs2 = fs3 = fs = 0.0; + } + + // set all forces and return no energy + + fforce = Fntot; + + // set single_extra quantities + + svector[0] = fs1; + svector[1] = fs2; + svector[2] = fs3; + svector[3] = fs; + svector[4] = vn1; + svector[5] = vn2; + svector[6] = vn3; + svector[7] = vt1; + svector[8] = vt2; + svector[9] = vt3; + return 0.0; +} + +/* ---------------------------------------------------------------------- */ + +int PairGranJKRRollingMulti::pack_forward_comm(int n, int *list, double *buf, + int pbc_flag, int *pbc) +{ + int i,j,m; + + m = 0; + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = mass_rigid[j]; + } + return m; +} + +/* ---------------------------------------------------------------------- */ + +void PairGranJKRRollingMulti::unpack_forward_comm(int n, int first, double *buf) +{ + int i,m,last; + + m = 0; + last = first + n; + for (i = first; i < last; i++) + mass_rigid[i] = buf[m++]; +} + +/* ---------------------------------------------------------------------- + memory usage of local atom-based arrays + ------------------------------------------------------------------------- */ + +double PairGranJKRRollingMulti::memory_usage() +{ + double bytes = nmax * sizeof(double); + return bytes; +} + +/* ---------------------------------------------------------------------- + mixing of stiffness (E) + ------------------------------------------------------------------------- */ + +double PairGranJKRRollingMulti::mix_stiffnessE(double Eii, double Ejj, double Gii, double Gjj) +{ + double poisii = Eii/(2.0*Gii) - 1.0; + double poisjj = Ejj/(2.0*Gjj) - 1.0; + return 1/((1-poisii*poisjj)/Eii+(1-poisjj*poisjj)/Ejj); +} + +/* ---------------------------------------------------------------------- + mixing of stiffness (G) + ------------------------------------------------------------------------- */ + +double PairGranJKRRollingMulti::mix_stiffnessG(double Eii, double Ejj, double Gii, double Gjj) +{ + double poisii = Eii/(2.0*Gii) - 1.0; + double poisjj = Ejj/(2.0*Gjj) - 1.0; + return 1/((2.0 -poisjj)/Gii+(2.0-poisjj)/Gjj); +} + +/* ---------------------------------------------------------------------- + mixing of everything else + ------------------------------------------------------------------------- */ + +double PairGranJKRRollingMulti::mix_geom(double valii, double valjj) +{ + return sqrt(valii*valjj); +} diff --git a/src/GRANULAR/pair_gran_jkr_rolling_multi.h b/src/GRANULAR/pair_gran_jkr_rolling_multi.h new file mode 100644 index 0000000000..c9c75de9a6 --- /dev/null +++ b/src/GRANULAR/pair_gran_jkr_rolling_multi.h @@ -0,0 +1,87 @@ +/* -*- 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. +------------------------------------------------------------------------- */ + +#ifdef PAIR_CLASS + +PairStyle(gran/jkr/rolling/multi,PairGranJKRRollingMulti) + +#else + +#ifndef LMP_PAIR_GRAN_JKR_ROLLING_MULTI_H +#define LMP_PAIR_GRAN_JKR_ROLLING_MULTI_H + +#include "pair.h" + +namespace LAMMPS_NS { + +class PairGranJKRRollingMulti : public Pair { +public: + PairGranJKRRollingMulti(class LAMMPS *); + virtual ~PairGranJKRRollingMulti(); + virtual void compute(int, int); + virtual void settings(int, char **); + virtual void coeff(int, char **); // Made Virtual by IS Oct 7 2017 + void init_style(); + double init_one(int, int); + void write_restart(FILE *); + void read_restart(FILE *); + void write_restart_settings(FILE *); + void read_restart_settings(FILE *); + void reset_dt(); + virtual double single(int, int, int, int, double, double, double, double &); + int pack_forward_comm(int, int *, double *, int, int *); + void unpack_forward_comm(int, int, double *); + double memory_usage(); + + protected: + double cut_global; + double **E,**G,**alpha,**gamman,**muS,**Ecoh,**kR,**muR,**etaR,**cut; + int **normaldamp, **rollingdamp; + double dt; + int freeze_group_bit; + int history; + + int neighprev; + double *onerad_dynamic,*onerad_frozen; + double *maxrad_dynamic,*maxrad_frozen; + + class FixNeighHistory *fix_history; + + // storage of rigid body masses for use in granular interactions + + class Fix *fix_rigid; // ptr to rigid body fix, NULL if none + double *mass_rigid; // rigid mass for owned+ghost atoms + int nmax; // allocated size of mass_rigid + + virtual void allocate(); // Made Virtual by IS Oct 7 2017 + +private: + double mix_stiffnessE(double Eii, double Ejj, double Gii, double Gjj); + double mix_stiffnessG(double Eii, double Ejj, double Gii, double Gjj); + double mix_geom(double valii, double valjj); +}; + +} + +#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. + + */ diff --git a/src/GRANULAR/pair_granular.cpp b/src/GRANULAR/pair_granular.cpp new file mode 100644 index 0000000000..9b693c74b5 --- /dev/null +++ b/src/GRANULAR/pair_granular.cpp @@ -0,0 +1,1187 @@ +/* ---------------------------------------------------------------------- +http://lammps.sandia.gov, Sandia National Laboratories +Steve Plimpton, sjplimp@sandia.gov + +Copyright (2003) Sandia Corporation. Under the terms of Contract +DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains +certain rights in this software. This software is distributed under +the GNU General Public License. + +See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- +Contributing authors: Leo Silbert (SNL), Gary Grest (SNL), + Jeremy Lechman (SNL), Dan Bolintineanu (SNL), Ishan Srivastava (SNL) +----------------------------------------------------------------------- */ + +#include +#include +#include +#include +#include "pair_granular.h" +#include "atom.h" +#include "atom_vec.h" +#include "domain.h" +#include "force.h" +#include "update.h" +#include "modify.h" +#include "fix.h" +#include "fix_neigh_history.h" +#include "comm.h" +#include "neighbor.h" +#include "neigh_list.h" +#include "neigh_request.h" +#include "memory.h" +#include "error.h" +#include "math_const.h" + +using namespace LAMMPS_NS; +using namespace MathConst; + +#define ONETHIRD 0.33333333333333333 +#define TWOTHIRDS 0.66666666666666666 +#define POW6ONE 0.550321208149104 //6^(-1/3) +#define POW6TWO 0.30285343213869 //6^(-2/3) + +#define EPSILON 1e-10 + +enum {TSUJI, BRILLIANTOV}; +enum {INDEP, BRILLROLL}; + +/* ---------------------------------------------------------------------- */ + +PairGranular::PairGranular(LAMMPS *lmp) : Pair(lmp) +{ + single_enable = 1; + no_virial_fdotr_compute = 1; + history = 1; + fix_history = NULL; + + single_extra = 10; + svector = new double[10]; + + neighprev = 0; + + nmax = 0; + mass_rigid = NULL; + + onerad_dynamic = NULL; + onerad_frozen = NULL; + maxrad_dynamic = NULL; + maxrad_frozen = NULL; + + dt = update->dt; + + // set comm size needed by this Pair if used with fix rigid + + comm_forward = 1; +} + +/* ---------------------------------------------------------------------- */ +PairGranular::~PairGranular() +{ + delete [] svector; + if (fix_history) modify->delete_fix("NEIGH_HISTORY"); + + if (allocated) { + memory->destroy(setflag); + memory->destroy(cutsq); + + memory->destroy(cut); + memory->destroy(E); + memory->destroy(G); + memory->destroy(normaldamp); + memory->destroy(rollingdamp); + memory->destroy(alpha); + memory->destroy(gamman); + memory->destroy(muS); + memory->destroy(Ecoh); + memory->destroy(kR); + memory->destroy(muR); + memory->destroy(etaR); + + delete [] onerad_dynamic; + delete [] onerad_frozen; + delete [] maxrad_dynamic; + delete [] maxrad_frozen; + } + memory->destroy(mass_rigid); +} +/* ---------------------------------------------------------------------- */ + +void PairGranular::compute(int eflag, int vflag) +{ + int i,j,ii,jj,inum,jnum,itype,jtype; + double xtmp,ytmp,ztmp,delx,dely,delz,fx,fy,fz,nx,ny,nz; + double radi,radj,radsum,rsq,r,rinv,rsqinv,R,a; + double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3; + double wr1,wr2,wr3; + double vtr1,vtr2,vtr3,vrel; + double kn, kt, k_Q, k_R, eta_N, eta_T, eta_Q, eta_R; + double Fne, Fdamp, Fntot, Fscrit, Frcrit, F_C, delta_C, delta_Cinv; + double overlap, olapsq, olapcubed, sqrtterm, tmp, a0; + double keyterm, keyterm2, keyterm3, aovera0, foverFc; + double mi,mj,meff,damp,ccel,tor1,tor2,tor3; + double relrot1,relrot2,relrot3,vrl1,vrl2,vrl3,vrlmag,vrlmaginv; + double rollmag, rolldotn, scalefac; + double fr, fr1, fr2, fr3; + double signtwist, magtwist, magtortwist, Mtcrit; + double fs,fs1,fs2,fs3,roll1,roll2,roll3,torroll1,torroll2,torroll3; + double tortwist1, tortwist2, tortwist3; + double shrmag,rsht; + int *ilist,*jlist,*numneigh,**firstneigh; + int *touch,**firsttouch; + double *history,*allhistory,**firsthistory; + + if (eflag || vflag) ev_setup(eflag,vflag); + else evflag = vflag_fdotr = 0; + + int historyupdate = 1; + if (update->setupflag) historyupdate = 0; + + // update rigid body info for owned & ghost atoms if using FixRigid masses + // body[i] = which body atom I is in, -1 if none + // mass_body = mass of each rigid body + + if (fix_rigid && neighbor->ago == 0){ + int tmp; + int *body = (int *) fix_rigid->extract("body",tmp); + double *mass_body = (double *) fix_rigid->extract("masstotal",tmp); + if (atom->nmax > nmax) { + memory->destroy(mass_rigid); + nmax = atom->nmax; + memory->create(mass_rigid,nmax,"pair:mass_rigid"); + } + int nlocal = atom->nlocal; + for (i = 0; i < nlocal; i++) + if (body[i] >= 0) mass_rigid[i] = mass_body[body[i]]; + else mass_rigid[i] = 0.0; + comm->forward_comm_pair(this); + } + + double **x = atom->x; + double **v = atom->v; + double **f = atom->f; + int *type = atom->type; + double **omega = atom->omega; + double **torque = atom->torque; + double *radius = atom->radius; + double *rmass = atom->rmass; + int *mask = atom->mask; + int nlocal = atom->nlocal; + int newton_pair = force->newton_pair; + + inum = list->inum; + ilist = list->ilist; + numneigh = list->numneigh; + firstneigh = list->firstneigh; + firsttouch = fix_history->firstflag; + firsthistory = fix_history->firstvalue; + + // loop over neighbors of my atoms + + for (ii = 0; ii < inum; ii++) { + i = ilist[ii]; + xtmp = x[i][0]; + ytmp = x[i][1]; + ztmp = x[i][2]; + itype = type[i]; + radi = radius[i]; + touch = firsttouch[i]; + allhistory = firsthistory[i]; + jlist = firstneigh[i]; + jnum = numneigh[i]; + + for (jj = 0; jj < jnum; jj++) { + j = jlist[jj]; + j &= NEIGHMASK; + + delx = xtmp - x[j][0]; + dely = ytmp - x[j][1]; + delz = ztmp - x[j][2]; + jtype = type[j]; + rsq = delx*delx + dely*dely + delz*delz; + radj = radius[j]; + radsum = radi + radj; + R = radi*radj/(radi+radj); + a0 = pow(9.0*M_PI*Ecoh[itype][jtype]*R*R/E[itype][jtype],ONETHIRD); + delta_C = 0.5*a0*a0*POW6ONE/R; + + if ((rsq >= radsum*radsum && touch[jj] == 0) || + (rsq >= (radsum+delta_C)*(radsum+delta_C))) { + + // unset non-touching neighbors + + touch[jj] = 0; + history = &allhistory[3*jj]; + history[0] = 0.0; + history[1] = 0.0; + history[2] = 0.0; + + } else { + F_C = 3.0*R*M_PI*Ecoh[itype][jtype]; + r = sqrt(rsq); + rinv = 1.0/r; + rsqinv = 1.0/rsq; + + nx = delx*rinv; + ny = dely*rinv; + nz = delz*rinv; + + // relative translational velocity + + vr1 = v[i][0] - v[j][0]; + vr2 = v[i][1] - v[j][1]; + vr3 = v[i][2] - v[j][2]; + + // normal component + + vnnr = vr1*nx + vr2*ny + vr3*nz; //v_R . n + vn1 = nx*vnnr; + vn2 = ny*vnnr; + vn3 = nz*vnnr; + + // meff = effective mass of pair of particles + // if I or J part of rigid body, use body mass + // if I or J is frozen, meff is other particle + + mi = rmass[i]; + mj = rmass[j]; + if (fix_rigid) { + if (mass_rigid[i] > 0.0) mi = mass_rigid[i]; + if (mass_rigid[j] > 0.0) mj = mass_rigid[j]; + } + + meff = mi*mj / (mi+mj); + if (mask[i] & freeze_group_bit) meff = mj; + if (mask[j] & freeze_group_bit) meff = mi; + + //**************************************** + //Normal force = JKR-adjusted Hertzian contact + damping + //**************************************** + if (Ecoh[itype][jtype] != 0.0) delta_Cinv = 1.0/delta_C; + else delta_Cinv = 1.0; + overlap = (radsum - r)*delta_Cinv; + olapsq = overlap*overlap; + olapcubed = olapsq*overlap; + sqrtterm = sqrt(1.0 + olapcubed); + tmp = 2.0 + olapcubed + 2.0*sqrtterm; + keyterm = pow(tmp,ONETHIRD); + keyterm2 = olapsq/keyterm; + keyterm3 = sqrt(overlap + keyterm2 + keyterm); + aovera0 = POW6TWO * (keyterm3 + + sqrt(2.0*overlap - keyterm2 - keyterm + 4.0/keyterm3));// eq 41 + a = aovera0*a0; + foverFc = 4.0*((aovera0*aovera0*aovera0) - pow(aovera0,1.5));//F_ne/F_C (eq 40) + + Fne = F_C*foverFc; + + //Damping + kn = 4.0/3.0*E[itype][jtype]*a; + if (normaldamp[itype][jtype] == BRILLIANTOV) eta_N = a*meff*gamman[itype][jtype]; + else if (normaldamp[itype][jtype] == TSUJI) eta_N=alpha[itype][jtype]*sqrt(meff*kn); + + Fdamp = -eta_N*vnnr; //F_nd eq 23 and Zhao eq 19 + + Fntot = Fne + Fdamp; + //if (screen) fprintf(screen,"%d %d %16.16g %16.16g \n",itype,jtype,Ecoh[itype][jtype],E[itype][jtype]); + //if (logfile) fprintf(logfile,"%d %d %16.16g %16.16g \n",itype,jtype,Ecoh[itype][jtype],E[itype][jtype]); + + //**************************************** + //Tangential force, including history effects + //**************************************** + + // tangential component + vt1 = vr1 - vn1; + vt2 = vr2 - vn2; + vt3 = vr3 - vn3; + + // relative rotational velocity + // Luding Gran Matt 2008, v10,p235 suggests correcting radi and radj by subtracting + // delta/2, i.e. instead of radi, use distance to center of contact point? + wr1 = (radi*omega[i][0] + radj*omega[j][0]); + wr2 = (radi*omega[i][1] + radj*omega[j][1]); + wr3 = (radi*omega[i][2] + radj*omega[j][2]); + + // relative tangential velocities + vtr1 = vt1 - (nz*wr2-ny*wr3); + vtr2 = vt2 - (nx*wr3-nz*wr1); + vtr3 = vt3 - (ny*wr1-nx*wr2); + vrel = vtr1*vtr1 + vtr2*vtr2 + vtr3*vtr3; + vrel = sqrt(vrel); + + // history effects + touch[jj] = 1; + history = &allhistory[3*jj]; + shrmag = sqrt(history[0]*history[0] + history[1]*history[1] + + history[2]*history[2]); + + // Rotate and update displacements. + // See e.g. eq. 17 of Luding, Gran. Matter 2008, v10,p235 + if (historyupdate) { + rsht = history[0]*nx + history[1]*ny + history[2]*nz; + if (fabs(rsht) < EPSILON) rsht = 0; + if (rsht > 0){ + scalefac = shrmag/(shrmag - rsht); //if rhst == shrmag, contacting pair has rotated 90 deg. in one step, in which case you deserve a crash! + history[0] -= rsht*nx; + history[1] -= rsht*ny; + history[2] -= rsht*nz; + //Also rescale to preserve magnitude + history[0] *= scalefac; + history[1] *= scalefac; + history[2] *= scalefac; + } + //Update history + history[0] += vtr1*dt; + history[1] += vtr2*dt; + history[2] += vtr3*dt; + } + + // tangential forces = history + tangential velocity damping + // following Zhao and Marshall Phys Fluids v20, p043302 (2008) + kt=8.0*G[itype][jtype]*a; + + eta_T = eta_N; //Based on discussion in Marshall; eta_T can also be an independent parameter + fs1 = -kt*history[0] - eta_T*vtr1; //eq 26 + fs2 = -kt*history[1] - eta_T*vtr2; + fs3 = -kt*history[2] - eta_T*vtr3; + + // rescale frictional displacements and forces if needed + Fscrit = muS[itype][jtype] * fabs(Fne + 2*F_C); + // For JKR, use eq 43 of Marshall. For DMT, use Fne instead + + fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); + if (fs > Fscrit) { + if (shrmag != 0.0) { + //history[0] = (Fcrit/fs) * (history[0] + eta_T*vtr1/kt) - eta_T*vtr1/kt; + //history[1] = (Fcrit/fs) * (history[1] + eta_T*vtr1/kt) - eta_T*vtr1/kt; + //history[2] = (Fcrit/fs) * (history[2] + eta_T*vtr1/kt) - eta_T*vtr1/kt; + history[0] = -1.0/kt*(Fscrit*fs1/fs + eta_T*vtr1); //Same as above, but simpler (check!) + history[1] = -1.0/kt*(Fscrit*fs2/fs + eta_T*vtr2); + history[2] = -1.0/kt*(Fscrit*fs3/fs + eta_T*vtr3); + fs1 *= Fscrit/fs; + fs2 *= Fscrit/fs; + fs3 *= Fscrit/fs; + } else fs1 = fs2 = fs3 = 0.0; + } + + //**************************************** + // Rolling force, including history history effects + //**************************************** + + relrot1 = omega[i][0] - omega[j][0]; + relrot2 = omega[i][1] - omega[j][1]; + relrot3 = omega[i][2] - omega[j][2]; + + // rolling velocity, see eq. 31 of Wang et al, Particuology v 23, p 49 (2015) + // This is different from the Marshall papers, which use the Bagi/Kuhn formulation + // for rolling velocity (see Wang et al for why the latter is wrong) + vrl1 = R*(relrot2*nz - relrot3*ny); //- 0.5*((radj-radi)/radsum)*vtr1; + vrl2 = R*(relrot3*nx - relrot1*nz); //- 0.5*((radj-radi)/radsum)*vtr2; + vrl3 = R*(relrot1*ny - relrot2*nx); //- 0.5*((radj-radi)/radsum)*vtr3; + vrlmag = sqrt(vrl1*vrl1+vrl2*vrl2+vrl3*vrl3); + if (vrlmag != 0.0) vrlmaginv = 1.0/vrlmag; + else vrlmaginv = 0.0; + + // Rolling displacement + rollmag = sqrt(history[3]*history[3] + history[4]*history[4] + history[5]*history[5]); + rolldotn = history[3]*nx + history[4]*ny + history[5]*nz; + + if (historyupdate) { + if (fabs(rolldotn) < EPSILON) rolldotn = 0; + if (rolldotn > 0){ //Rotate into tangential plane + scalefac = rollmag/(rollmag - rolldotn); + history[3] -= rolldotn*nx; + history[4] -= rolldotn*ny; + history[5] -= rolldotn*nz; + //Also rescale to preserve magnitude + history[3] *= scalefac; + history[4] *= scalefac; + history[5] *= scalefac; + } + history[3] += vrl1*dt; + history[4] += vrl2*dt; + history[5] += vrl3*dt; + } + + k_R = kR[itype][jtype]*4.0*F_C*pow(aovera0,1.5); + if (rollingdamp[itype][jtype] == INDEP) eta_R = etaR[itype][jtype]; + else if (rollingdamp[itype][jtype] == BRILLROLL) eta_R = muR[itype][jtype]*fabs(Fne); + fr1 = -k_R*history[3] - eta_R*vrl1; + fr2 = -k_R*history[4] - eta_R*vrl2; + fr3 = -k_R*history[5] - eta_R*vrl3; + + // rescale frictional displacements and forces if needed + Frcrit = muR[itype][jtype] * fabs(Fne + 2*F_C); + + fr = sqrt(fr1*fr1 + fr2*fr2 + fr3*fr3); + if (fr > Frcrit) { + if (rollmag != 0.0) { + history[3] = -1.0/k_R*(Frcrit*fr1/fr + eta_R*vrl1); + history[4] = -1.0/k_R*(Frcrit*fr2/fr + eta_R*vrl2); + history[5] = -1.0/k_R*(Frcrit*fr3/fr + eta_R*vrl3); + fr1 *= Frcrit/fr; + fr2 *= Frcrit/fr; + fr3 *= Frcrit/fr; + } else fr1 = fr2 = fr3 = 0.0; + } + + + //**************************************** + // Twisting torque, including history effects + //**************************************** + magtwist = relrot1*nx + relrot2*ny + relrot3*nz; //Omega_T (eq 29 of Marshall) + history[6] += magtwist*dt; + k_Q = 0.5*kt*a*a;; //eq 32 + eta_Q = 0.5*eta_T*a*a; + magtortwist = -k_Q*history[6] - eta_Q*magtwist;//M_t torque (eq 30) + + signtwist = (magtwist > 0) - (magtwist < 0); + Mtcrit=TWOTHIRDS*a*Fscrit;//critical torque (eq 44) + if (fabs(magtortwist) > Mtcrit) { + //history[6] = Mtcrit/k_Q*magtwist/fabs(magtwist); + history[6] = 1.0/k_Q*(Mtcrit*signtwist - eta_Q*magtwist); + magtortwist = -Mtcrit * signtwist; //eq 34 + } + + // Apply forces & torques + + fx = nx*Fntot + fs1; + fy = ny*Fntot + fs2; + fz = nz*Fntot + fs3; + + //if (screen) fprintf(screen,"%16.16g %16.16g %16.16g %16.16g %16.16g %16.16g %16.16g \n",fs1,fs2,fs3,Fntot,nx,ny,nz); + //if (logfile) fprintf(logfile,"%16.16g %16.16g %16.16g %16.16g %16.16g %16.16g %16.16g \n",fs1,fs2,fs3,Fntot,nx,ny,nz); + + f[i][0] += fx; + f[i][1] += fy; + f[i][2] += fz; + + tor1 = ny*fs3 - nz*fs2; + tor2 = nz*fs1 - nx*fs3; + tor3 = nx*fs2 - ny*fs1; + + torque[i][0] -= radi*tor1; + torque[i][1] -= radi*tor2; + torque[i][2] -= radi*tor3; + + tortwist1 = magtortwist * nx; + tortwist2 = magtortwist * ny; + tortwist3 = magtortwist * nz; + + torque[i][0] += tortwist1; + torque[i][1] += tortwist2; + torque[i][2] += tortwist3; + + torroll1 = R*(ny*fr3 - nz*fr2); //n cross fr + torroll2 = R*(nz*fr1 - nx*fr3); + torroll3 = R*(nx*fr2 - ny*fr1); + + torque[i][0] += torroll1; + torque[i][1] += torroll2; + torque[i][2] += torroll3; + + if (force->newton_pair || j < nlocal) { + f[j][0] -= fx; + f[j][1] -= fy; + f[j][2] -= fz; + + torque[j][0] -= radj*tor1; + torque[j][1] -= radj*tor2; + torque[j][2] -= radj*tor3; + + torque[j][0] -= tortwist1; + torque[j][1] -= tortwist2; + torque[j][2] -= tortwist3; + + torque[j][0] -= torroll1; + torque[j][1] -= torroll2; + torque[j][2] -= torroll3; + } + if (evflag) ev_tally_xyz(i,j,nlocal,0, + 0.0,0.0,fx,fy,fz,delx,dely,delz); + } + } + } +} + + +/* ---------------------------------------------------------------------- +allocate all arrays +------------------------------------------------------------------------- */ + +void PairGranular::allocate() +{ + allocated = 1; + int n = atom->ntypes; + + memory->create(setflag,n+1,n+1,"pair:setflag"); + for (int i = 1; i <= n; i++) + for (int j = i; j <= n; j++) + setflag[i][j] = 0; + + memory->create(cutsq,n+1,n+1,"pair:cutsq"); + memory->create(cut,n+1,n+1,"pair:cut"); + memory->create(E,n+1,n+1,"pair:E"); + memory->create(G,n+1,n+1,"pair:G"); + memory->create(normaldamp,n+1,n+1,"pair:normaldamp"); + memory->create(rollingdamp,n+1,n+1,"pair:rollingdamp"); + memory->create(alpha,n+1,n+1,"pair:alpha"); + memory->create(gamman,n+1,n+1,"pair:gamman"); + memory->create(muS,n+1,n+1,"pair:muS"); + memory->create(Ecoh,n+1,n+1,"pair:Ecoh"); + memory->create(kR,n+1,n+1,"pair:kR"); + memory->create(muR,n+1,n+1,"pair:muR"); + memory->create(etaR,n+1,n+1,"pair:etaR"); + + onerad_dynamic = new double[n+1]; + onerad_frozen = new double[n+1]; + maxrad_dynamic = new double[n+1]; + maxrad_frozen = new double[n+1]; +} + +/* ---------------------------------------------------------------------- + global settings +------------------------------------------------------------------------- */ + +void PairGranular::settings(int narg, char **arg) +{ + if (narg != 1) error->all(FLERR,"Illegal pair_style command"); + + if (strcmp(arg[0],"NULL") == 0 ) cut_global = -1.0; + else cut_global = force->numeric(FLERR,arg[0]); + + // reset cutoffs that have been explicitly set + if (allocated) { + int i,j; + for (i = 1; i <= atom->ntypes; i++) + for (j = i; j <= atom->ntypes; j++) + if (setflag[i][j]) cut[i][j] = cut_global; + } +} + +/* ---------------------------------------------------------------------- + set coeffs for one or more type pairs +------------------------------------------------------------------------- */ + +void PairGranular::coeff(int narg, char **arg) +{ + if (narg < 10 || narg > 15) + error->all(FLERR,"Incorrect args for pair coefficients2"); + + if (!allocated) allocate(); + + int ilo,ihi,jlo,jhi; + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); + + double E_one = force->numeric(FLERR,arg[2]); + double G_one = force->numeric(FLERR,arg[3]); + double muS_one = force->numeric(FLERR,arg[4]); + double cor_one = force->numeric(FLERR,arg[5]); + double Ecoh_one = force->numeric(FLERR,arg[6]); + double kR_one = force->numeric(FLERR,arg[7]); + double muR_one = force->numeric(FLERR,arg[8]); + double etaR_one = force->numeric(FLERR,arg[9]); + + //Defaults + int normaldamp_one = TSUJI; + int rollingdamp_one = INDEP; + double cut_one = cut_global; + + int iarg = 10; + while (iarg < narg) { + if (strcmp(arg[iarg],"normaldamp") == 0){ + if (iarg+2 > narg) error->all(FLERR, "Invalid pair/gran/dmt/rolling entry"); + if (strcmp(arg[iarg+1],"tsuji") == 0) normaldamp_one = TSUJI; + else if (strcmp(arg[iarg+1],"brilliantov") == 0) normaldamp_one = BRILLIANTOV; + else error->all(FLERR, "Invalid normal damping model for pair/gran/dmt/rolling"); + iarg += 2; + } + else if (strcmp(arg[iarg],"rollingdamp") == 0){ + if (iarg+2 > narg) error->all(FLERR, "Invalid pair/gran/dmt/rolling entry"); + if (strcmp(arg[iarg+1],"independent") == 0) rollingdamp_one = INDEP; + else if (strcmp(arg[iarg+1],"brilliantov") == 0) rollingdamp_one = BRILLROLL; + else error->all(FLERR, "Invalid rolling damping model for pair/gran/dmt/rolling"); + iarg +=2; + } + else { + if (strcmp(arg[iarg],"NULL") == 0) cut_one = -1.0; + else cut_one = force->numeric(FLERR,arg[iarg]); + iarg += 1; + } + } + + int count = 0; + for (int i = ilo; i <= ihi; i++) { + double pois = E_one/(2.0*G_one) - 1.0; + double alpha_one = 1.2728-4.2783*cor_one+11.087*cor_one*cor_one-22.348*cor_one*cor_one*cor_one+27.467*cor_one*cor_one*cor_one*cor_one-18.022*cor_one*cor_one*cor_one*cor_one*cor_one+4.8218*cor_one*cor_one*cor_one*cor_one*cor_one*cor_one; + + for (int j = MAX(jlo,i); j <= jhi; j++) { + E[i][j] = E_one; + G[i][j] = G_one; + if (normaldamp_one == TSUJI) { + normaldamp[i][j] = TSUJI; + alpha[i][j] = alpha_one; + } + else if (normaldamp_one == BRILLIANTOV) { + normaldamp[i][j] = BRILLIANTOV; + gamman[i][j] = cor_one; + } + if (rollingdamp_one == INDEP) { + rollingdamp[i][j] = INDEP; + } + else if (rollingdamp_one == BRILLROLL) { + rollingdamp[i][j] = BRILLROLL; + } + muS[i][j] = muS_one; + Ecoh[i][j] = Ecoh_one; + kR[i][j] = kR_one; + etaR[i][j] = etaR_one; + muR[i][j] = muR_one; + cut[i][j] = cut_one; + setflag[i][j] = 1; + count++; + } + } + + if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients1"); +} + +/* ---------------------------------------------------------------------- + init specific to this pair style +------------------------------------------------------------------------- */ + +void PairGranular::init_style() +{ + int i; + + // error and warning checks + + if (!atom->radius_flag || !atom->rmass_flag) + error->all(FLERR,"Pair granular requires atom attributes radius, rmass"); + if (comm->ghost_velocity == 0) + error->all(FLERR,"Pair granular requires ghost atoms store velocity"); + + // need a granular neigh list + + int irequest = neighbor->request(this,instance_me); + neighbor->requests[irequest]->size = 1; + if (history) neighbor->requests[irequest]->history = 1; + + dt = update->dt; + + // if history is stored: + // if first init, create Fix needed for storing history + + if (history && fix_history == NULL) { + char dnumstr[16]; + sprintf(dnumstr,"%d",size_history); + char **fixarg = new char*[4]; + fixarg[0] = (char *) "NEIGH_HISTORY"; + fixarg[1] = (char *) "all"; + fixarg[2] = (char *) "NEIGH_HISTORY"; + fixarg[3] = dnumstr; + modify->add_fix(4,fixarg,1); + delete [] fixarg; + fix_history = (FixNeighHistory *) modify->fix[modify->nfix-1]; + fix_history->pair = this; + } + + // check for FixFreeze and set freeze_group_bit + + for (i = 0; i < modify->nfix; i++) + if (strcmp(modify->fix[i]->style,"freeze") == 0) break; + if (i < modify->nfix) freeze_group_bit = modify->fix[i]->groupbit; + else freeze_group_bit = 0; + + // check for FixRigid so can extract rigid body masses + + fix_rigid = NULL; + for (i = 0; i < modify->nfix; i++) + if (modify->fix[i]->rigid_flag) break; + if (i < modify->nfix) fix_rigid = modify->fix[i]; + + // check for FixPour and FixDeposit so can extract particle radii + + int ipour; + for (ipour = 0; ipour < modify->nfix; ipour++) + if (strcmp(modify->fix[ipour]->style,"pour") == 0) break; + if (ipour == modify->nfix) ipour = -1; + + int idep; + for (idep = 0; idep < modify->nfix; idep++) + if (strcmp(modify->fix[idep]->style,"deposit") == 0) break; + if (idep == modify->nfix) idep = -1; + + // set maxrad_dynamic and maxrad_frozen for each type + // include future FixPour and FixDeposit particles as dynamic + + int itype; + for (i = 1; i <= atom->ntypes; i++) { + onerad_dynamic[i] = onerad_frozen[i] = 0.0; + if (ipour >= 0) { + itype = i; + onerad_dynamic[i] = + *((double *) modify->fix[ipour]->extract("radius",itype)); + } + if (idep >= 0) { + itype = i; + onerad_dynamic[i] = + *((double *) modify->fix[idep]->extract("radius",itype)); + } + } + + double *radius = atom->radius; + int *mask = atom->mask; + int *type = atom->type; + int nlocal = atom->nlocal; + + for (i = 0; i < nlocal; i++) + if (mask[i] & freeze_group_bit) + onerad_frozen[type[i]] = MAX(onerad_frozen[type[i]],radius[i]); + else + onerad_dynamic[type[i]] = MAX(onerad_dynamic[type[i]],radius[i]); + + MPI_Allreduce(&onerad_dynamic[1],&maxrad_dynamic[1],atom->ntypes, + MPI_DOUBLE,MPI_MAX,world); + MPI_Allreduce(&onerad_frozen[1],&maxrad_frozen[1],atom->ntypes, + MPI_DOUBLE,MPI_MAX,world); + + // set fix which stores history info + + if (history) { + int ifix = modify->find_fix("NEIGH_HISTORY"); + if (ifix < 0) error->all(FLERR,"Could not find pair fix neigh history ID"); + fix_history = (FixNeighHistory *) modify->fix[ifix]; + } +} + +/* ---------------------------------------------------------------------- + init for one type pair i,j and corresponding j,i +------------------------------------------------------------------------- */ + +double PairGranular::init_one(int i, int j) +{ + if (setflag[i][j] == 0) { + E[i][j] = mix_stiffnessE(E[i][i],E[j][j],G[i][i],G[j][j]); + G[i][j] = mix_stiffnessG(G[i][i],E[j][j],G[i][i],G[j][j]); + if (normaldamp[i][j] == TSUJI) { + alpha[i][j] = mix_geom(alpha[i][i],alpha[j][j]); + } + else if (normaldamp[i][j] == BRILLIANTOV) { + gamman[i][j] = mix_geom(gamman[i][i],gamman[j][j]); + } + muS[i][j] = mix_geom(muS[i][i],muS[j][j]); + Ecoh[i][j] = mix_geom(Ecoh[i][i],Ecoh[j][j]); + kR[i][j] = mix_geom(kR[i][i],kR[j][j]); + etaR[i][j] = mix_geom(etaR[i][i],etaR[j][j]); + muR[i][j] = mix_geom(muR[i][i],muR[j][j]); + } + + E[j][i] = E[i][j]; + G[j][i] = G[i][j]; + normaldamp[j][i] = normaldamp[i][j]; + alpha[j][i] = alpha[i][j]; + gamman[j][i] = gamman[i][j]; + rollingdamp[j][i] = rollingdamp[i][j]; + muS[j][i] = muS[i][j]; + Ecoh[j][i] = Ecoh[i][j]; + kR[j][i] = kR[i][j]; + etaR[j][i] = etaR[i][j]; + muR[j][i] = muR[i][j]; + + double cutoff = cut[i][j]; + + // It is likely that cut[i][j] at this point is still 0.0. This can happen when + // there is a future fix_pour after the current run. A cut[i][j] = 0.0 creates + // problems because neighbor.cpp uses min(cut[i][j]) to decide on the bin size + // To avoid this issue,for cases involving cut[i][j] = 0.0 (possible only + // if there is no current information about radius/cutoff of type i and j). + // we assign cutoff = min(cut[i][j]) for i,j such that cut[i][j] > 0.0. + + if (cut[i][j] < 0.0) { + if (((maxrad_dynamic[i] > 0.0) && (maxrad_dynamic[j] > 0.0)) || ((maxrad_dynamic[i] > 0.0) && (maxrad_frozen[j] > 0.0)) || + ((maxrad_frozen[i] > 0.0) && (maxrad_dynamic[j] > 0.0))) { // radius info about both i and j exist + cutoff = maxrad_dynamic[i]+maxrad_dynamic[j]; + cutoff = MAX(cutoff,maxrad_frozen[i]+maxrad_dynamic[j]); + cutoff = MAX(cutoff,maxrad_dynamic[i]+maxrad_frozen[j]); + } + else { // radius info about either i or j does not exist (i.e. not present and not about to get poured; set to largest value to not interfere with neighbor list) + double cutmax = 0.0; + for (int k = 1; k <= atom->ntypes; k++) { + cutmax = MAX(cutmax,2.0*maxrad_dynamic[k]); + cutmax = MAX(cutmax,2.0*maxrad_frozen[k]); + } + cutoff = cutmax; + } + } + return cutoff; +} + + +/* ---------------------------------------------------------------------- + proc 0 writes to restart file + ------------------------------------------------------------------------- */ + +void PairGranular::write_restart(FILE *fp) +{ + write_restart_settings(fp); + + int i,j; + for (i = 1; i <= atom->ntypes; i++) { + for (j = i; j <= atom->ntypes; j++) { + fwrite(&setflag[i][j],sizeof(int),1,fp); + if (setflag[i][j]) { + fwrite(&E[i][j],sizeof(double),1,fp); + fwrite(&G[i][j],sizeof(double),1,fp); + fwrite(&normaldamp[i][j],sizeof(int),1,fp); + fwrite(&rollingdamp[i][j],sizeof(int),1,fp); + fwrite(&alpha[i][j],sizeof(double),1,fp); + fwrite(&gamman[i][j],sizeof(double),1,fp); + fwrite(&muS[i][j],sizeof(double),1,fp); + fwrite(&Ecoh[i][j],sizeof(double),1,fp); + fwrite(&kR[i][j],sizeof(double),1,fp); + fwrite(&muR[i][j],sizeof(double),1,fp); + fwrite(&etaR[i][j],sizeof(double),1,fp); + fwrite(&cut[i][j],sizeof(double),1,fp); + } + } + } +} + +/* ---------------------------------------------------------------------- + proc 0 reads from restart file, bcasts + ------------------------------------------------------------------------- */ + +void PairGranular::read_restart(FILE *fp) +{ + read_restart_settings(fp); + allocate(); + + int i,j; + int me = comm->me; + for (i = 1; i <= atom->ntypes; i++) { + for (j = i; j <= atom->ntypes; j++) { + if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp); + MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world); + if (setflag[i][j]) { + if (me == 0) { + fread(&E[i][j],sizeof(double),1,fp); + fread(&G[i][j],sizeof(double),1,fp); + fread(&normaldamp[i][j],sizeof(int),1,fp); + fread(&rollingdamp[i][j],sizeof(int),1,fp); + fread(&alpha[i][j],sizeof(double),1,fp); + fread(&gamman[i][j],sizeof(double),1,fp); + fread(&muS[i][j],sizeof(double),1,fp); + fread(&Ecoh[i][j],sizeof(double),1,fp); + fread(&kR[i][j],sizeof(double),1,fp); + fread(&muR[i][j],sizeof(double),1,fp); + fread(&etaR[i][j],sizeof(double),1,fp); + fread(&cut[i][j],sizeof(double),1,fp); + } + MPI_Bcast(&E[i][j],1,MPI_DOUBLE,0,world); + MPI_Bcast(&G[i][j],1,MPI_DOUBLE,0,world); + MPI_Bcast(&normaldamp[i][j],1,MPI_INT,0,world); + MPI_Bcast(&rollingdamp[i][j],1,MPI_INT,0,world); + MPI_Bcast(&alpha[i][j],1,MPI_DOUBLE,0,world); + MPI_Bcast(&gamman[i][j],1,MPI_DOUBLE,0,world); + MPI_Bcast(&muS[i][j],1,MPI_DOUBLE,0,world); + MPI_Bcast(&Ecoh[i][j],1,MPI_DOUBLE,0,world); + MPI_Bcast(&kR[i][j],1,MPI_DOUBLE,0,world); + MPI_Bcast(&muR[i][j],1,MPI_DOUBLE,0,world); + MPI_Bcast(&etaR[i][j],1,MPI_DOUBLE,0,world); + MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); + } + } + } +} + +/* ---------------------------------------------------------------------- + proc 0 writes to restart file + ------------------------------------------------------------------------- */ + +void PairGranular::write_restart_settings(FILE *fp) +{ + fwrite(&cut_global,sizeof(double),1,fp); +} + +/* ---------------------------------------------------------------------- + proc 0 reads from restart file, bcasts + ------------------------------------------------------------------------- */ + +void PairGranular::read_restart_settings(FILE *fp) +{ + if (comm->me == 0) { + fread(&cut_global,sizeof(double),1,fp); + } + MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world); +} + +/* ---------------------------------------------------------------------- */ + +void PairGranular::reset_dt() +{ + dt = update->dt; +} + +/* ---------------------------------------------------------------------- */ + +double PairGranular::single(int i, int j, int itype, int jtype, + double rsq, double factor_coul, double factor_lj, double &fforce) +{ + // feenableexcept(FE_INVALID | FE_OVERFLOW); + double radi,radj,radsum; + double r,rinv,rsqinv,delx,dely,delz, nx, ny, nz, R; + double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3,wr1,wr2,wr3; + double overlap, a; + double mi,mj,meff,damp,kn,kt; + double Fdamp,Fne,Fntot,Fscrit; + double eta_N,eta_T; + double vtr1,vtr2,vtr3,vrel; + double fs1,fs2,fs3,fs; + double shrmag; + double F_C, delta_C, olapsq, olapcubed, sqrtterm, tmp, a0; + double keyterm, keyterm2, keyterm3, aovera0, foverFc; + + double *radius = atom->radius; + radi = radius[i]; + radj = radius[j]; + radsum = radi + radj; + + r = sqrt(rsq); + rinv = 1.0/r; + rsqinv = 1.0/rsq; + R = radi*radj/(radi+radj); + a0 = pow(9.0*M_PI*Ecoh[itype][jtype]*R*R/E[itype][jtype],ONETHIRD); + delta_C = 0.5*a0*a0*POW6ONE/R; + + int *touch = fix_history->firstflag[i]; + if ((rsq >= (radsum+delta_C)*(radsum+delta_C) )|| + (rsq >= radsum*radsum && touch[j])){ + fforce = 0.0; + svector[0] = svector[1] = svector[2] = svector[3] = 0.0; + return 0.0; + } + + // relative translational velocity + + double **v = atom->v; + vr1 = v[i][0] - v[j][0]; + vr2 = v[i][1] - v[j][1]; + vr3 = v[i][2] - v[j][2]; + + // normal component + + double **x = atom->x; + delx = x[i][0] - x[j][0]; + dely = x[i][1] - x[j][1]; + delz = x[i][2] - x[j][2]; + + nx = delx*rinv; + ny = dely*rinv; + nz = delz*rinv; + + + vnnr = vr1*nx + vr2*ny + vr3*nz; + vn1 = nx*vnnr; + vn2 = ny*vnnr; + vn3 = nz*vnnr; + + // tangential component + + vt1 = vr1 - vn1; + vt2 = vr2 - vn2; + vt3 = vr3 - vn3; + + // relative rotational velocity + + double **omega = atom->omega; + wr1 = (radi*omega[i][0] + radj*omega[j][0]); + wr2 = (radi*omega[i][1] + radj*omega[j][1]); + wr3 = (radi*omega[i][2] + radj*omega[j][2]); + + // meff = effective mass of pair of particles + // if I or J part of rigid body, use body mass + // if I or J is frozen, meff is other particle + + double *rmass = atom->rmass; + int *type = atom->type; + int *mask = atom->mask; + + mi = rmass[i]; + mj = rmass[j]; + if (fix_rigid) { + // NOTE: ensure mass_rigid is current for owned+ghost atoms? + if (mass_rigid[i] > 0.0) mi = mass_rigid[i]; + if (mass_rigid[j] > 0.0) mj = mass_rigid[j]; + } + + meff = mi*mj / (mi+mj); + if (mask[i] & freeze_group_bit) meff = mj; + if (mask[j] & freeze_group_bit) meff = mi; + + + // normal force = JKR + F_C = 3.0*R*M_PI*Ecoh[itype][jtype]; + overlap = radsum - r; + olapsq = overlap*overlap; + olapcubed = olapsq*olapsq; + sqrtterm = sqrt(1.0 + olapcubed); + tmp = 2.0 + olapcubed + 2.0*sqrtterm; + keyterm = pow(tmp,ONETHIRD); + keyterm2 = olapsq/keyterm; + keyterm3 = sqrt(overlap + keyterm2 + keyterm); + aovera0 = POW6TWO * (keyterm3 + + sqrt(2.0*overlap - keyterm2 - keyterm + 4.0/keyterm3));// eq 41 + a = aovera0*a0; + foverFc = 4.0*((aovera0*aovera0*aovera0) - pow(aovera0,1.5));//F_ne/F_C (eq 40) + + Fne = F_C*foverFc; + + //Damping + kn = 4.0/3.0*E[itype][jtype]*a; + if (normaldamp[itype][jtype] == BRILLIANTOV) eta_N = a*meff*gamman[itype][jtype]; + else if (normaldamp[itype][jtype] == TSUJI) eta_N=alpha[itype][jtype]*sqrt(meff*kn); + + Fdamp = -eta_N*vnnr; //F_nd eq 23 and Zhao eq 19 + + Fntot = Fne + Fdamp; + + // relative velocities + + vtr1 = vt1 - (nz*wr2-ny*wr3); + vtr2 = vt2 - (nx*wr3-nz*wr1); + vtr3 = vt3 - (ny*wr1-nx*wr2); + vrel = vtr1*vtr1 + vtr2*vtr2 + vtr3*vtr3; + vrel = sqrt(vrel); + + // history effects + // neighprev = index of found neigh on previous call + // search entire jnum list of neighbors of I for neighbor J + // start from neighprev, since will typically be next neighbor + // reset neighprev to 0 as necessary + + int jnum = list->numneigh[i]; + int *jlist = list->firstneigh[i]; + double *allhistory = fix_history->firstvalue[i]; + + for (int jj = 0; jj < jnum; jj++) { + neighprev++; + if (neighprev >= jnum) neighprev = 0; + if (jlist[neighprev] == j) break; + } + + double *history = &allhistory[3*neighprev]; + shrmag = sqrt(history[0]*history[0] + history[1]*history[1] + + history[2]*history[2]); + + // tangential forces = history + tangential velocity damping + kt=8.0*G[itype][jtype]*a; + + eta_T = eta_N; + fs1 = -kt*history[0] - eta_T*vtr1; + fs2 = -kt*history[1] - eta_T*vtr2; + fs3 = -kt*history[2] - eta_T*vtr3; + + // rescale frictional displacements and forces if needed + + fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); + Fscrit= muS[itype][jtype] * fabs(Fne + 2*F_C); + + if (fs > Fscrit) { + if (shrmag != 0.0) { + fs1 *= Fscrit/fs; + fs2 *= Fscrit/fs; + fs3 *= Fscrit/fs; + fs *= Fscrit/fs; + } else fs1 = fs2 = fs3 = fs = 0.0; + } + + // set all forces and return no energy + + fforce = Fntot; + + // set single_extra quantities + + svector[0] = fs1; + svector[1] = fs2; + svector[2] = fs3; + svector[3] = fs; + svector[4] = vn1; + svector[5] = vn2; + svector[6] = vn3; + svector[7] = vt1; + svector[8] = vt2; + svector[9] = vt3; + return 0.0; +} + +/* ---------------------------------------------------------------------- */ + +int PairGranular::pack_forward_comm(int n, int *list, double *buf, + int pbc_flag, int *pbc) +{ + int i,j,m; + + m = 0; + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = mass_rigid[j]; + } + return m; +} + +/* ---------------------------------------------------------------------- */ + +void PairGranular::unpack_forward_comm(int n, int first, double *buf) +{ + int i,m,last; + + m = 0; + last = first + n; + for (i = first; i < last; i++) + mass_rigid[i] = buf[m++]; +} + +/* ---------------------------------------------------------------------- + memory usage of local atom-based arrays + ------------------------------------------------------------------------- */ + +double PairGranular::memory_usage() +{ + double bytes = nmax * sizeof(double); + return bytes; +} + +/* ---------------------------------------------------------------------- + mixing of stiffness (E) +------------------------------------------------------------------------- */ + +double PairGranular::mix_stiffnessE(double Eii, double Ejj, double Gii, double Gjj) +{ + double poisii = Eii/(2.0*Gii) - 1.0; + double poisjj = Ejj/(2.0*Gjj) - 1.0; + return 1/((1-poisii*poisjj)/Eii+(1-poisjj*poisjj)/Ejj); +} + +/* ---------------------------------------------------------------------- + mixing of stiffness (G) + ------------------------------------------------------------------------- */ + +double PairGranular::mix_stiffnessG(double Eii, double Ejj, double Gii, double Gjj) +{ + double poisii = Eii/(2.0*Gii) - 1.0; + double poisjj = Ejj/(2.0*Gjj) - 1.0; + return 1/((2.0 -poisjj)/Gii+(2.0-poisjj)/Gjj); +} + +/* ---------------------------------------------------------------------- + mixing of everything else + ------------------------------------------------------------------------- */ + +double PairGranular::mix_geom(double valii, double valjj) +{ + return sqrt(valii*valjj); +} diff --git a/src/GRANULAR/pair_granular.h b/src/GRANULAR/pair_granular.h new file mode 100644 index 0000000000..9fbc9acd51 --- /dev/null +++ b/src/GRANULAR/pair_granular.h @@ -0,0 +1,89 @@ +/* ---------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain 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(granular,PairGranular) + +#else + +#ifndef LMP_PAIR_GRANULAR_H +#define LMP_PAIR_GRANULAR_H + +#include "pair.h" + +namespace LAMMPS_NS { + +class PairGranular : public Pair { +public: + PairGranular(class LAMMPS *); + virtual ~PairGranular(); + virtual void compute(int, int); + virtual void settings(int, char **); + virtual void coeff(int, char **); + void init_style(); + double init_one(int, int); + void write_restart(FILE *); + void read_restart(FILE *); + void write_restart_settings(FILE *); + void read_restart_settings(FILE *); + void reset_dt(); + virtual double single(int, int, int, int, double, double, double, double &); + int pack_forward_comm(int, int *, double *, int, int *); + void unpack_forward_comm(int, int, double *); + double memory_usage(); + + protected: + double cut_global; + double dt; + int freeze_group_bit; + int history; + + int neighprev; + double *onerad_dynamic,*onerad_frozen; + double *maxrad_dynamic,*maxrad_frozen; + + class FixNeighHistory *fix_history; + + // storage of rigid body masses for use in granular interactions + + class Fix *fix_rigid; // ptr to rigid body fix, NULL if none + double *mass_rigid; // rigid mass for owned+ghost atoms + int nmax; // allocated size of mass_rigid + + virtual void allocate(); + + private: + int size_history; + int num_coeffs; + double ***coeffs; + + double mix_stiffnessE(double Eii, double Ejj, double Gii, double Gjj); + double mix_stiffnessG(double Eii, double Ejj, double Gii, double Gjj); + double mix_geom(double valii, double valjj); +}; + +} + +#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. + + */ From 7861de03a21da687d813f5f34eaf92dc27787def Mon Sep 17 00:00:00 2001 From: Dan Stefan Bolintineanu Date: Thu, 20 Dec 2018 16:59:21 -0700 Subject: [PATCH 06/44] Progress on general granular pair style --- src/GRANULAR/pair_granular.cpp | 643 +++++++++++++++++++++++++++------ src/GRANULAR/pair_granular.h | 44 ++- 2 files changed, 564 insertions(+), 123 deletions(-) diff --git a/src/GRANULAR/pair_granular.cpp b/src/GRANULAR/pair_granular.cpp index 9b693c74b5..73fcb19a8c 100644 --- a/src/GRANULAR/pair_granular.cpp +++ b/src/GRANULAR/pair_granular.cpp @@ -46,8 +46,12 @@ using namespace MathConst; #define EPSILON 1e-10 -enum {TSUJI, BRILLIANTOV}; -enum {INDEP, BRILLROLL}; +enum {STIFFNESS, MATERIAL}; +enum {VELOCITY, VISCOELASTIC, TSUJI}; +enum {HOOKE, HERTZ, DMT, JKR}; +enum {TANGENTIAL_MINDLIN, TANGENTIAL_NOHISTORY}; +enum {NONE, TWISTING_NOHISTORY, TWISTING_SDS, TWISTING_MARSHALL}; +enum {NONE, ROLLING_NOHISTORY, ROLLING_SDS}; /* ---------------------------------------------------------------------- */ @@ -55,7 +59,7 @@ PairGranular::PairGranular(LAMMPS *lmp) : Pair(lmp) { single_enable = 1; no_virial_fdotr_compute = 1; - history = 1; + use_history = 1; fix_history = NULL; single_extra = 10; @@ -76,6 +80,10 @@ PairGranular::PairGranular(LAMMPS *lmp) : Pair(lmp) // set comm size needed by this Pair if used with fix rigid comm_forward = 1; + + beyond_contact = 0; + rolling_history_index = twisting_history_index = 0; + tangential_history_index = -1; } /* ---------------------------------------------------------------------- */ @@ -108,9 +116,194 @@ PairGranular::~PairGranular() } memory->destroy(mass_rigid); } -/* ---------------------------------------------------------------------- */ -void PairGranular::compute(int eflag, int vflag) +void PairGranular::compute(int eflag, int vflag){ + /* +#ifdef TEMPLATED_PAIR_GRANULAR + if (normal == 0){ + if (damping == 0){ + if (tangential == 0){ + if (rolling == 0){ + if (twisting == 0) compute_templated<0,0,0,0,0,0>(eflag, vflag); + else if (twisting == 1) compute_templated<0,0,0,0,0,1>(eflag, vflag); + else if (twisting == 2) compute_templated<0,0,0,0,0,2>(eflag, vflag); + } + else if (rolling == 1){ + if (twisting == 0) compute_templated<0,0,0,0,1,0>(eflag, vflag); + else if (twisting == 1) compute_templated<0,0,0,0,1,1>(eflag, vflag); + else if (twisting == 2) compute_templated<0,0,0,0,1,2>(eflag, vflag); + } + else if (rolling == 2){ + if (twisting == 0) compute_templated<0,0,0,0,2,0>(eflag, vflag); + else if (twisting == 1) compute_templated<0,0,0,0,2,1>(eflag, vflag); + else if (twisting == 2) compute_templated<0,0,0,0,2,2>(eflag, vflag); + } + } + else if (tangential == 1){ + if (rolling == 0){ + if (twisting == 0) compute_templated<0,0,0,1,0,0>(eflag, vflag); + else if (twisting == 1) compute_templated<0,0,0,1,0,1>(eflag, vflag); + else if (twisting == 2) compute_templated<0,0,0,1,0,2>(eflag, vflag); + } + else if (rolling == 1){ + if (twisting == 0) compute_templated<0,0,0,1,1,0>(eflag, vflag); + else if (twisting == 1) compute_templated<0,0,0,1,1,1>(eflag, vflag); + else if (twisting == 2) compute_templated<0,0,0,1,1,2>(eflag, vflag); + } + else if (rolling == 2){ + if (twisting == 0) compute_templated<0,0,0,1,2,0>(eflag, vflag); + else if (twisting == 1) compute_templated<0,0,0,1,2,1>(eflag, vflag); + else if (twisting == 2) compute_templated<0,0,0,1,2,2>(eflag, vflag); + } + } + else if (tangential == 2){ + if (rolling == 0){ + if (twisting == 0) compute_templated<0,0,0,2,0,0>(eflag, vflag); + else if (twisting == 1) compute_templated<0,0,0,2,0,1>(eflag, vflag); + else if (twisting == 2) compute_templated<0,0,0,2,0,2>(eflag, vflag); + } + else if (rolling == 1){ + if (twisting == 0) compute_templated<0,0,0,2,1,0>(eflag, vflag); + else if (twisting == 1) compute_templated<0,0,0,2,1,1>(eflag, vflag); + else if (twisting == 2) compute_templated<0,0,0,2,1,2>(eflag, vflag); + } + else if (rolling == 2){ + if (twisting == 0) compute_templated<0,0,0,2,2,0>(eflag, vflag); + else if (twisting == 1) compute_templated<0,0,0,2,2,1>(eflag, vflag); + else if (twisting == 2) compute_templated<0,0,0,2,2,2>(eflag, vflag); + } + } + } + else if (damping == 1){ + if (tangential == 0){ + if (rolling == 0){ + if (twisting == 0) compute_templated<0,0,1,0,0,0>(eflag, vflag); + else if (twisting == 1) compute_templated<0,0,1,0,0,1>(eflag, vflag); + else if (twisting == 2) compute_templated<0,0,1,0,0,2>(eflag, vflag); + } + else if (rolling == 1){ + if (twisting == 0) compute_templated<0,0,1,0,1,0>(eflag, vflag); + else if (twisting == 1) compute_templated<0,0,1,0,1,1>(eflag, vflag); + else if (twisting == 2) compute_templated<0,0,1,0,1,2>(eflag, vflag); + } + else if (rolling == 2){ + if (twisting == 0) compute_templated<0,0,1,0,2,0>(eflag, vflag); + else if (twisting == 1) compute_templated<0,0,1,0,2,1>(eflag, vflag); + else if (twisting == 2) compute_templated<0,0,1,0,2,2>(eflag, vflag); + } + } + else if (tangential == 1){ + if (rolling == 0){ + if (twisting == 0) compute_templated<0,0,1,1,0,0>(eflag, vflag); + else if (twisting == 1) compute_templated<0,0,1,1,0,1>(eflag, vflag); + else if (twisting == 2) compute_templated<0,0,1,1,0,2>(eflag, vflag); + } + else if (rolling == 1){ + if (twisting == 0) compute_templated<0,0,1,1,1,0>(eflag, vflag); + else if (twisting == 1) compute_templated<0,0,1,1,1,1>(eflag, vflag); + else if (twisting == 2) compute_templated<0,0,1,1,1,2>(eflag, vflag); + } + else if (rolling == 2){ + if (twisting == 0) compute_templated<0,0,1,1,2,0>(eflag, vflag); + else if (twisting == 1) compute_templated<0,0,1,1,2,1>(eflag, vflag); + else if (twisting == 2) compute_templated<0,0,1,1,2,2>(eflag, vflag); + } + } + else if (tangential == 2){ + if (rolling == 0){ + if (twisting == 0) compute_templated<0,0,1,2,0,0>(eflag, vflag); + else if (twisting == 1) compute_templated<0,0,1,2,0,1>(eflag, vflag); + else if (twisting == 2) compute_templated<0,0,1,2,0,2>(eflag, vflag); + } + else if (rolling == 1){ + if (twisting == 0) compute_templated<0,0,1,2,1,0>(eflag, vflag); + else if (twisting == 1) compute_templated<0,0,1,2,1,1>(eflag, vflag); + else if (twisting == 2) compute_templated<0,0,1,2,1,2>(eflag, vflag); + } + else if (rolling == 2){ + if (twisting == 0) compute_templated<0,0,1,2,2,0>(eflag, vflag); + else if (twisting == 1) compute_templated<0,0,1,2,2,1>(eflag, vflag); + else if (twisting == 2) compute_templated<0,0,1,2,2,2>(eflag, vflag); + } + } + } + else if (damping == 2){ + if (tangential == 0){ + if (rolling == 0){ + if (twisting == 0) compute_templated<0,0,2,0,0,0>(eflag, vflag); + else if (twisting == 1) compute_templated<0,0,2,0,0,1>(eflag, vflag); + else if (twisting == 2) compute_templated<0,0,2,0,0,2>(eflag, vflag); + } + else if (rolling == 1){ + if (twisting == 0) compute_templated<0,0,2,0,1,0>(eflag, vflag); + else if (twisting == 1) compute_templated<0,0,2,0,1,1>(eflag, vflag); + else if (twisting == 2) compute_templated<0,0,2,0,1,2>(eflag, vflag); + } + else if (rolling == 2){ + if (twisting == 0) compute_templated<0,0,2,0,2,0>(eflag, vflag); + else if (twisting == 1) compute_templated<0,0,2,0,2,1>(eflag, vflag); + else if (twisting == 2) compute_templated<0,0,2,0,2,2>(eflag, vflag); + } + } + else if (tangential == 1){ + if (rolling == 0){ + if (twisting == 0) compute_templated<0,0,2,1,0,0>(eflag, vflag); + else if (twisting == 1) compute_templated<0,0,2,1,0,1>(eflag, vflag); + else if (twisting == 2) compute_templated<0,0,2,1,0,2>(eflag, vflag); + } + else if (rolling == 1){ + if (twisting == 0) compute_templated<0,0,2,1,1,0>(eflag, vflag); + else if (twisting == 1) compute_templated<0,0,2,1,1,1>(eflag, vflag); + else if (twisting == 2) compute_templated<0,0,2,1,1,2>(eflag, vflag); + } + else if (rolling == 2){ + if (twisting == 0) compute_templated<0,0,2,1,2,0>(eflag, vflag); + else if (twisting == 1) compute_templated<0,0,2,1,2,1>(eflag, vflag); + else if (twisting == 2) compute_templated<0,0,2,1,2,2>(eflag, vflag); + } + } + else if (tangential == 2){ + if (rolling == 0){ + if (twisting == 0) compute_templated<0,0,2,2,0,0>(eflag, vflag); + else if (twisting == 1) compute_templated<0,0,2,2,0,1>(eflag, vflag); + else if (twisting == 2) compute_templated<0,0,2,2,0,2>(eflag, vflag); + } + else if (rolling == 1){ + if (twisting == 0) compute_templated<0,0,2,2,1,0>(eflag, vflag); + else if (twisting == 1) compute_templated<0,0,2,2,1,1>(eflag, vflag); + else if (twisting == 2) compute_templated<0,0,2,2,1,2>(eflag, vflag); + } + else if (rolling == 2){ + if (twisting == 0) compute_templated<0,0,2,2,2,0>(eflag, vflag); + else if (twisting == 1) compute_templated<0,0,2,2,2,1>(eflag, vflag); + else if (twisting == 2) compute_templated<0,0,2,2,2,2>(eflag, vflag); + } + } + } + } + + + } +#else +#endif +*/ + compute_untemplated(Tp_coeff_types, Tp_normal, Tp_damping, Tp_tangential, + Tp_rolling, Tp_twisting, eflag, vflag); +} +/* ---------------------------------------------------------------------- */ +/*#ifdef TEMPLATED_PAIR_GRANULAR +template < int Tp_coeff_types, + int Tp_normal, int Tp_damping, int Tp_tangential, + int Tp_rolling, int Tp_twisting > +void PairGranular::compute_templated(int eflag, int vflag) +#else +*/ +void PairGranular::compute_untemplated + (int Tp_coeff_types, + int Tp_normal, int Tp_damping, int Tp_tangential, + int Tp_rolling, int Tp_twisting, + int eflag, int vflag) +//#endif { int i,j,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,fx,fy,fz,nx,ny,nz; @@ -119,9 +312,13 @@ void PairGranular::compute(int eflag, int vflag) double wr1,wr2,wr3; double vtr1,vtr2,vtr3,vrel; double kn, kt, k_Q, k_R, eta_N, eta_T, eta_Q, eta_R; - double Fne, Fdamp, Fntot, Fscrit, Frcrit, F_C, delta_C, delta_Cinv; + double Fne, Fdamp, Fntot, Fscrit, Frcrit; + + //For JKR + double R, R2, coh, delta_pulloff, dist_pulloff, a, E; double overlap, olapsq, olapcubed, sqrtterm, tmp, a0; double keyterm, keyterm2, keyterm3, aovera0, foverFc; + double mi,mj,meff,damp,ccel,tor1,tor2,tor3; double relrot1,relrot2,relrot3,vrl1,vrl2,vrl3,vrlmag,vrlmaginv; double rollmag, rolldotn, scalefac; @@ -134,6 +331,8 @@ void PairGranular::compute(int eflag, int vflag) int *touch,**firsttouch; double *history,*allhistory,**firsthistory; + bool untouchflag; + if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; @@ -179,10 +378,18 @@ void PairGranular::compute(int eflag, int vflag) firsttouch = fix_history->firstflag; firsthistory = fix_history->firstvalue; - // loop over neighbors of my atoms + double coh; + double **cohesion; + double **stiffness; + double **damping; + if (Tp_normal == JKR){ + cohesion = coeffs[normal_coeff_inds[4]]; + } + for (ii = 0; ii < inum; ii++) { i = ilist[ii]; + itype = type[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; @@ -193,7 +400,7 @@ void PairGranular::compute(int eflag, int vflag) jlist = firstneigh[i]; jnum = numneigh[i]; - for (jj = 0; jj < jnum; jj++) { + for (jj = 0; jj < jnum; jj++){ j = jlist[jj]; j &= NEIGHMASK; @@ -204,23 +411,25 @@ void PairGranular::compute(int eflag, int vflag) rsq = delx*delx + dely*dely + delz*delz; radj = radius[j]; radsum = radi + radj; - R = radi*radj/(radi+radj); - a0 = pow(9.0*M_PI*Ecoh[itype][jtype]*R*R/E[itype][jtype],ONETHIRD); - delta_C = 0.5*a0*a0*POW6ONE/R; + untouchflag = (rsq >= radsum*radsum); - if ((rsq >= radsum*radsum && touch[jj] == 0) || - (rsq >= (radsum+delta_C)*(radsum+delta_C))) { + if (normal[itype][jtype] == JKR){ + R = radi*radj/(radi+radj); + R2 = R*R; + coh = cohesion[itype][jtype]; + a = cbrt(9.0*M_PI*coh*R2/(4*E)); + delta_pulloff = a*a/R - 2*sqrt(M_PI*coh*a/E); + dist_pulloff = radsum+delta_pulloff; + untouchflag = (rsq >= (dist_pulloff)*(dist_pulloff)); + } + if (untouchflag){ // unset non-touching neighbors - touch[jj] = 0; - history = &allhistory[3*jj]; - history[0] = 0.0; - history[1] = 0.0; - history[2] = 0.0; - - } else { - F_C = 3.0*R*M_PI*Ecoh[itype][jtype]; + history = &allhistory[size_history*jj]; + for (int k = 0; k < size_history; k++) history[k] = 0.0; + } + else{ r = sqrt(rsq); rinv = 1.0/r; rsqinv = 1.0/rsq; @@ -260,23 +469,9 @@ void PairGranular::compute(int eflag, int vflag) //**************************************** //Normal force = JKR-adjusted Hertzian contact + damping //**************************************** - if (Ecoh[itype][jtype] != 0.0) delta_Cinv = 1.0/delta_C; - else delta_Cinv = 1.0; - overlap = (radsum - r)*delta_Cinv; - olapsq = overlap*overlap; - olapcubed = olapsq*overlap; - sqrtterm = sqrt(1.0 + olapcubed); - tmp = 2.0 + olapcubed + 2.0*sqrtterm; - keyterm = pow(tmp,ONETHIRD); - keyterm2 = olapsq/keyterm; - keyterm3 = sqrt(overlap + keyterm2 + keyterm); - aovera0 = POW6TWO * (keyterm3 + - sqrt(2.0*overlap - keyterm2 - keyterm + 4.0/keyterm3));// eq 41 - a = aovera0*a0; - foverFc = 4.0*((aovera0*aovera0*aovera0) - pow(aovera0,1.5));//F_ne/F_C (eq 40) - - Fne = F_C*foverFc; + if (normal[itype][jtype] == JKR){ + } //Damping kn = 4.0/3.0*E[itype][jtype]*a; if (normaldamp[itype][jtype] == BRILLIANTOV) eta_N = a*meff*gamman[itype][jtype]; @@ -522,18 +717,15 @@ void PairGranular::allocate() setflag[i][j] = 0; memory->create(cutsq,n+1,n+1,"pair:cutsq"); - memory->create(cut,n+1,n+1,"pair:cut"); - memory->create(E,n+1,n+1,"pair:E"); - memory->create(G,n+1,n+1,"pair:G"); - memory->create(normaldamp,n+1,n+1,"pair:normaldamp"); - memory->create(rollingdamp,n+1,n+1,"pair:rollingdamp"); - memory->create(alpha,n+1,n+1,"pair:alpha"); - memory->create(gamman,n+1,n+1,"pair:gamman"); - memory->create(muS,n+1,n+1,"pair:muS"); - memory->create(Ecoh,n+1,n+1,"pair:Ecoh"); - memory->create(kR,n+1,n+1,"pair:kR"); - memory->create(muR,n+1,n+1,"pair:muR"); - memory->create(etaR,n+1,n+1,"pair:etaR"); + memory->create(normal_coeffs,n+1,n+1,4,"pair:normal_coeffs"); + memory->create(tangential_coeffs,n+1,n+1,3,"pair:tangential_coeffs"); + memory->create(rolling_coeffs,n+1,n+1,3,"pair:rolling_coeffs"); + memory->create(twisting_coeffs,n+1,n+1,3,"pair:twisting_coeffs"); + + memory->create(normal,n+1,n+1,"pair:normal"); + memory->create(tangential,n+1,n+1,"pair:tangential"); + memory->create(rolling,n+1,n+1,"pair:rolling"); + memory->create(twisting,n+1,n+1,"pair:twisting"); onerad_dynamic = new double[n+1]; onerad_frozen = new double[n+1]; @@ -547,17 +739,135 @@ void PairGranular::allocate() void PairGranular::settings(int narg, char **arg) { - if (narg != 1) error->all(FLERR,"Illegal pair_style command"); + if (narg < 5) error->all(FLERR,"Illegal pair_style command"); - if (strcmp(arg[0],"NULL") == 0 ) cut_global = -1.0; - else cut_global = force->numeric(FLERR,arg[0]); + int iarg = 0; - // reset cutoffs that have been explicitly set - if (allocated) { - int i,j; - for (i = 1; i <= atom->ntypes; i++) - for (j = i; j <= atom->ntypes; j++) - if (setflag[i][j]) cut[i][j] = cut_global; + //Some defaults + damping_global = VISCOELASTIC; + coeff_types = STIFFNESS; + tangential_global = -1; //Needs to be explicitly set, since it requires parameters + rolling_global = NONE; + twisting_global = NONE; + tangential_history = rolling_history = twisting_history = 0; + + if (strcmp(arg[iarg], "material") == 0){ + coeff_types = MATERIAL; + iarg += 1; + } + while (iarg < narg){ + if (strcmp(arg[iarg], "hooke") == 0){ + if (coeff_types == MATERIAL) error->all(FLERR,"Illegal pair_coeff command, 'stiffness' coefficients required for Hooke"); + if (iarg + 2 >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for Hooke option"); + normal_global = HOOKE; + memory->create(normal_coeffs_one, 2, "pair:normal_coeffs_one"); + normal_coeffs_one[0] = force->numeric(FLERR,arg[iarg+1]); //kn + normal_coeffs_one[1] = force->numeric(FLERR,arg[iarg+2]); //damping + iarg += 3; + } + else if (strcmp(arg[iarg], "hertz") == 0){ + int num_coeffs = 2; + if (coeff_types == MATERIAL) num_coeffs += 1; + if (iarg + offset >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for Hertz option"); + normal_global = HERTZ; + memory->create(normal_coeffs_one, num_coeffs, "pair:normal_coeffs_one"); + normal_coeffs_one[0] = force->numeric(FLERR,arg[iarg+1]); //kn or E + normal_coeffs_one[1] = force->numeric(FLERR,arg[iarg+2]); //damping + if (coeff_types == MATERIAL) normal_coeffs_one[2] = force->numeric(FLERR,arg[iarg+3]); //G (if 'material') + iarg += num_coeffs+1; + } + else if (strcmp(arg[iarg], "dmt") == 0){ + if (coeff_types == STIFFNESS) error->all(FLERR,"Illegal pair_style command, 'material' coefficients required for DMT"); + if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for Hertz option"); + normal_global = DMT; + memory->create(normal_coeffs_one, 4, "pair:normal_coeffs_one"); + normal_coeffs_one[0] = force->numeric(FLERR,arg[iarg+1]); //E + normal_coeffs_one[1] = force->numeric(FLERR,arg[iarg+2]); //damping + normal_coeffs_one[2] = force->numeric(FLERR,arg[iarg+3]); //G + normal_coeffs_one[3] = force->numeric(FLERR,arg[iarg+3]); //cohesion + iarg += 5; + } + else if (strcmp(arg[iarg], "jkr") == 0){ + if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for JKR option"); + if (coeff_types == STIFFNESS) error->all(FLERR,"Illegal pair_style command, 'material' coefficients required for JKR"); + beyond_contact = 1; + normal_global = JKR; + memory->create(normal_coeffs_one, 4, "pair:normal_coeffs_one"); + normal_coeffs_one[0] = force->numeric(FLERR,arg[iarg+1]); //E + normal_coeffs_one[1] = force->numeric(FLERR,arg[iarg+2]); //damping + normal_coeffs_one[2] = force->numeric(FLERR,arg[iarg+3]); //G + normal_coeffs_one[3] = force->numeric(FLERR,arg[iarg+4]); //cohesion + iarg += 5; + } + else if (strcmp(arg[iarg], "damp_velocity") == 0){ + damping_global = VELOCITY; + iarg += 1; + } + else if (strcmp(arg[iarg], "damp_viscoelastic") == 0){ + damping_global = VISCOELASTIC; + iarg += 1; + } + else if (strcmp(arg[iarg], "damp_tsuji") == 0){ + damping_global = TSUJI; + iarg += 1; + } + else if (strstr(arg[iarg], "tangential") != NULL){ + if (iarg + 3 >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for tangential model"); + if (strstr(arg[iarg], "nohistory") != NULL){ + tangential_global = TANGENTIAL_NOHISTORY; + } + else{ + tangential_global = TANGENTIAL_MINDLIN; + tangential_history = 1; + } + memory->create(tangential_coeffs_one, 3, "pair:tangential_coeffs_one"); + tangential_coeffs_one[0] = force->numeric(FLERR,arg[iarg+1]); //kt + tangential_coeffs_one[1] = force->numeric(FLERR,arg[iarg+2]); //gammat + tangential_coeffs_one[2] = force->numeric(FLERR,arg[iarg+3]); //friction coeff. + iarg += 4; + } + else if (strstr(arg[iarg], "rolling") != NULL){ + if (iarg + 3 >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for rolling model"); + if (strstr(arg[iarg], "nohistory") != NULL){ + rolling_global = ROLLING_NOHISTORY; + } + else{ + rolling_global = ROLLING_SDS; + rolling_history = 1; + } + memory->create(rolling_coeffs_one, 3, "pair:rolling_coeffs_one"); + rolling_coeffs_one[0] = force->numeric(FLERR,arg[iarg+1]); //kt + rolling_coeffs_one[1] = force->numeric(FLERR,arg[iarg+2]); //gammat + rolling_coeffs_one[2] = force->numeric(FLERR,arg[iarg+3]); //friction coeff. + iarg += 4; + } + else if (strstr(arg[iarg], "twisting") != NULL){ + if (strstr(arg[iarg], "marshall") != NULL){ + twisting_global = TWISTING_MARSHALL; + twisting_history = 1; + memory->create(twisting_coeffs_one, 3, "pair:twisting_coeffs_one"); //To be filled later + } + else{ + if (iarg + 3 >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for twisting model"); + if (strstr(arg[iarg], "nohistory") != NULL){ + twisting_global = TWISTING_NOHISTORY; + } + else{ + twisting_global = TWISTING_SDS; + twisting_history = 1; + } + memory->create(twisting_coeffs_one, 3, "pair:twisting_coeffs_one"); + twisting_coeffs_one[0] = force->numeric(FLERR,arg[iarg+1]); //kt + twisting_coeffs_one[1] = force->numeric(FLERR,arg[iarg+2]); //gammat + twisting_coeffs_one[2] = force->numeric(FLERR,arg[iarg+3]); //friction coeff. + iarg += 4; + } + } + } + + //Additional checks + if (tangential_global == -1){ + error->all(FLERR, "Illegal pair_style command: must specify tangential model"); } } @@ -567,8 +877,19 @@ void PairGranular::settings(int narg, char **arg) void PairGranular::coeff(int narg, char **arg) { - if (narg < 10 || narg > 15) - error->all(FLERR,"Incorrect args for pair coefficients2"); + int normal_local, damping_local, tangential_local, rolling_local, twisting_local; + double *normal_coeffs_local; + double *tangential_coeffs_local; + double *rolling_coeffs_local; + double *twisting_coeffs_local; + + normal_coeffs_local = new double[4]; + tangential_coeffs_local = new double[4]; + rolling_coeffs_local = new double[4]; + twisting_coeffs_local = new double[4]; + + if (narg < 2) + error->all(FLERR,"Incorrect args for pair coefficients"); if (!allocated) allocate(); @@ -576,77 +897,149 @@ void PairGranular::coeff(int narg, char **arg) force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); - double E_one = force->numeric(FLERR,arg[2]); - double G_one = force->numeric(FLERR,arg[3]); - double muS_one = force->numeric(FLERR,arg[4]); - double cor_one = force->numeric(FLERR,arg[5]); - double Ecoh_one = force->numeric(FLERR,arg[6]); - double kR_one = force->numeric(FLERR,arg[7]); - double muR_one = force->numeric(FLERR,arg[8]); - double etaR_one = force->numeric(FLERR,arg[9]); - - //Defaults - int normaldamp_one = TSUJI; - int rollingdamp_one = INDEP; - double cut_one = cut_global; - - int iarg = 10; - while (iarg < narg) { - if (strcmp(arg[iarg],"normaldamp") == 0){ - if (iarg+2 > narg) error->all(FLERR, "Invalid pair/gran/dmt/rolling entry"); - if (strcmp(arg[iarg+1],"tsuji") == 0) normaldamp_one = TSUJI; - else if (strcmp(arg[iarg+1],"brilliantov") == 0) normaldamp_one = BRILLIANTOV; - else error->all(FLERR, "Invalid normal damping model for pair/gran/dmt/rolling"); - iarg += 2; + int iarg = 2; + while (iarg < narg){ + if (strcmp(arg[iarg], "hooke") == 0){ + if (coeff_types == MATERIAL) error->all(FLERR,"Illegal pair_coeff command, 'stiffness' coefficients required for Hooke"); + if (iarg + 2 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hooke option"); + normal_local = HOOKE; + normal_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1]); //kn + normal_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //damping + iarg += 3; } - else if (strcmp(arg[iarg],"rollingdamp") == 0){ - if (iarg+2 > narg) error->all(FLERR, "Invalid pair/gran/dmt/rolling entry"); - if (strcmp(arg[iarg+1],"independent") == 0) rollingdamp_one = INDEP; - else if (strcmp(arg[iarg+1],"brilliantov") == 0) rollingdamp_one = BRILLROLL; - else error->all(FLERR, "Invalid rolling damping model for pair/gran/dmt/rolling"); - iarg +=2; + else if (strcmp(arg[iarg], "hertz") == 0){ + int num_coeffs = 2; + if (coeff_types == MATERIAL) num_coeffs += 1; + if (iarg + offset >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hertz option"); + normal_local = HERTZ; + normal_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1]); //kn or E + normal_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //damping + if (coeff_types == MATERIAL) normal_coeffs_local[2] = force->numeric(FLERR,arg[iarg+3]); //G (if 'material') + iarg += num_coeffs+1; } - else { - if (strcmp(arg[iarg],"NULL") == 0) cut_one = -1.0; - else cut_one = force->numeric(FLERR,arg[iarg]); + else if (strcmp(arg[iarg], "dmt") == 0){ + if (coeff_types == STIFFNESS) error->all(FLERR,"Illegal pair_coeff command, 'material' coefficients required for DMT"); + if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hertz option"); + normal_local = DMT; + normal_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1]); //E + normal_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //damping + normal_coeffs_local[2] = force->numeric(FLERR,arg[iarg+3]); //G + normal_coeffs_local[3] = force->numeric(FLERR,arg[iarg+3]); //cohesion + iarg += 5; + } + else if (strcmp(arg[iarg], "jkr") == 0){ + if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for JKR option"); + if (coeff_types == STIFFNESS) error->all(FLERR,"Illegal pair_coeff command, 'material' coefficients required for JKR"); + beyond_contact = 1; + normal_local = JKR; + normal_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1]); //E + normal_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //damping + normal_coeffs_local[2] = force->numeric(FLERR,arg[iarg+3]); //G + normal_coeffs_local[3] = force->numeric(FLERR,arg[iarg+4]); //cohesion + iarg += 5; + } + else if (strcmp(arg[iarg], "damp_velocity") == 0){ + damping_local = VELOCITY; iarg += 1; } + else if (strcmp(arg[iarg], "damp_viscoelastic") == 0){ + damping_local = VISCOELASTIC; + iarg += 1; + } + else if (strcmp(arg[iarg], "damp_tsuji") == 0){ + damping_local = TSUJI; + iarg += 1; + } + else if (strstr(arg[iarg], "tangential") != NULL){ + if (iarg + 3 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for tangential model"); + if (strstr(arg[iarg], "nohistory") != NULL){ + tangential_local = TANGENTIAL_NOHISTORY; + } + else{ + tangential_local = TANGENTIAL_MINDLIN; + tangential_history = 1; + } + tangential_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1]); //kt + tangential_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //gammat + tangential_coeffs_local[2] = force->numeric(FLERR,arg[iarg+3]); //friction coeff. + iarg += 4; + } + else if (strstr(arg[iarg], "rolling") != NULL){ + if (iarg + 3 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for rolling model"); + if (strstr(arg[iarg], "nohistory") != NULL){ + rolling_local = ROLLING_NOHISTORY; + } + else{ + rolling_local = ROLLING_SDS; + rolling_history = 1; + } + rolling_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1]); //kt + rolling_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //gammat + rolling_coeffs_local[2] = force->numeric(FLERR,arg[iarg+3]); //friction coeff. + iarg += 4; + } + else if (strstr(arg[iarg], "twisting") != NULL){ + if (strstr(arg[iarg], "marshall") != NULL){ + twisting_local = TWISTING_MARSHALL; + twisting_history = 1; + } + else{ + if (iarg + 3 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for twisting model"); + if (strstr(arg[iarg], "nohistory") != NULL){ + twisting_local = TWISTING_NOHISTORY; + } + else{ + twisting_local = TWISTING_SDS; + twisting_history = 1; + size_history += 1; + } + twisting_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1]); //kt + twisting_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //gammat + twisting_coeffs_local[2] = force->numeric(FLERR,arg[iarg+3]); //friction coeff. + iarg += 4; + } + } } int count = 0; - for (int i = ilo; i <= ihi; i++) { - double pois = E_one/(2.0*G_one) - 1.0; - double alpha_one = 1.2728-4.2783*cor_one+11.087*cor_one*cor_one-22.348*cor_one*cor_one*cor_one+27.467*cor_one*cor_one*cor_one*cor_one-18.022*cor_one*cor_one*cor_one*cor_one*cor_one+4.8218*cor_one*cor_one*cor_one*cor_one*cor_one*cor_one; + double damp; + if (damping_local == TSUJI){ + double cor = normal_coeffs_local[1]; + damp =1.2728-4.2783*cor+11.087*pow(cor,2)-22.348*pow(cor,3)+ + 27.467*pow(cor,4)-18.022*pow(cor,5)+ + 4.8218*pow(cor,6); + } + else damp = normal_coeffs_local[1]; + for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { - E[i][j] = E_one; - G[i][j] = G_one; - if (normaldamp_one == TSUJI) { - normaldamp[i][j] = TSUJI; - alpha[i][j] = alpha_one; - } - else if (normaldamp_one == BRILLIANTOV) { - normaldamp[i][j] = BRILLIANTOV; - gamman[i][j] = cor_one; - } - if (rollingdamp_one == INDEP) { - rollingdamp[i][j] = INDEP; - } - else if (rollingdamp_one == BRILLROLL) { - rollingdamp[i][j] = BRILLROLL; - } - muS[i][j] = muS_one; - Ecoh[i][j] = Ecoh_one; - kR[i][j] = kR_one; - etaR[i][j] = etaR_one; - muR[i][j] = muR_one; - cut[i][j] = cut_one; + normal[i][j] = normal_local; + normal_coeffs[i][j][0] = normal_coeffs_local[0]; + normal_coeffs[i][j][1] = damp; + if (coeff_types == MATERIAL) normal_coeffs[i][j][2] = normal_coeffs_local[2]; + if ((normal_local == JKR) || (normal_local == DMT)) + normal_coeffs[i][j][3] = normal_coeffs_local[3]; + + tangential[i][j] = tangential_local; + if (tangential_local != NONE) + for (int k = 0; k < 3; k++) + tangential_coeffs[i][j][k] = tangential_coeffs_local[k]; + + rolling[i][j] = rolling_local; + if (rolling_local != NONE) + for (int k = 0; k < 3; k++) + rolling_coeffs[i][j][k] = tangential_coeffs_local[k]; + + twisting[i][j] = twisting_local; + if (twisting_local != NONE) + for (int k = 0; k < 3; k++) + rolling_coeffs[i][j][k] = tangential_coeffs_local[k]; + setflag[i][j] = 1; count++; } } - - if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients1"); + if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- @@ -751,7 +1144,7 @@ void PairGranular::init_style() // set fix which stores history info - if (history) { + if (size_history > 0) { int ifix = modify->find_fix("NEIGH_HISTORY"); if (ifix < 0) error->all(FLERR,"Could not find pair fix neigh history ID"); fix_history = (FixNeighHistory *) modify->fix[ifix]; @@ -765,7 +1158,17 @@ void PairGranular::init_style() double PairGranular::init_one(int i, int j) { if (setflag[i][j] == 0) { - E[i][j] = mix_stiffnessE(E[i][i],E[j][j],G[i][i],G[j][j]); + if ((normal[i] != normal[j]) || + (damping[i] != damping[j]) || + (tangential[i] != tangential[j]) || + (rolling[i] != rolling[j]) || + (twisting[i] != twisting[j])){ + + char str[128]; + sprintf(str,"Failed to open FFmpeg pipeline to file %s",filename); + error->one(FLERR,str); + } + G[i][j] = mix_stiffnessG(G[i][i],E[j][j],G[i][i],G[j][j]); if (normaldamp[i][j] == TSUJI) { alpha[i][j] = mix_geom(alpha[i][i],alpha[j][j]); diff --git a/src/GRANULAR/pair_granular.h b/src/GRANULAR/pair_granular.h index 9fbc9acd51..33d28b03bf 100644 --- a/src/GRANULAR/pair_granular.h +++ b/src/GRANULAR/pair_granular.h @@ -47,7 +47,7 @@ public: double cut_global; double dt; int freeze_group_bit; - int history; + int use_history; int neighprev; double *onerad_dynamic,*onerad_frozen; @@ -62,11 +62,49 @@ public: int nmax; // allocated size of mass_rigid virtual void allocate(); + int beyond_contact; + + + // comment next line to turn off templating +/*#define TEMPLATED_PAIR_GRANULAR +#ifdef TEMPLATED_PAIR_GRANULAR + template < int Tp_coeff_types, + int Tp_normal, int Tp_damping, int Tp_tangential, + int Tp_rolling, int Tp_twisting > + void compute_templated(int eflag, int vflag); +#else +*/ + void compute_untemplated( + int, + int, int, int, + int, int, + int, int); +//#endif private: + int coeff_types; int size_history; - int num_coeffs; - double ***coeffs; + + //Per-type models + int **normal, **damping, **tangential, **rolling, **twisting; + + int normal_global, damping_global; + int tangential_global, rolling_global, twisting_global; + + int tangential_history, rolling_history, twisting_history; + int tangential_history_index; + int rolling_history_index; + int twisting_history_index; + + double *normal_coeffs_one; + double *tangential_coeffs_one; + double *rolling_coeffs_one; + double *twisting_coeffs_one; + + double ***normal_coeffs; + double ***tangential_coeffs; + double ***rolling_coeffs; + double ***twisting_coeffs; double mix_stiffnessE(double Eii, double Ejj, double Gii, double Gjj); double mix_stiffnessG(double Eii, double Ejj, double Gii, double Gjj); From 009d8c8ebf3af1c9d3196192fe2a033af624c6b6 Mon Sep 17 00:00:00 2001 From: dsbolin Date: Fri, 21 Dec 2018 09:29:47 -0700 Subject: [PATCH 07/44] Added parsing to pair_coeff, added for for init_one --- src/GRANULAR/pair_granular.cpp | 174 +++++++++++++++++++++------------ src/GRANULAR/pair_granular.h | 8 +- 2 files changed, 114 insertions(+), 68 deletions(-) diff --git a/src/GRANULAR/pair_granular.cpp b/src/GRANULAR/pair_granular.cpp index 73fcb19a8c..a94575185a 100644 --- a/src/GRANULAR/pair_granular.cpp +++ b/src/GRANULAR/pair_granular.cpp @@ -493,8 +493,6 @@ void PairGranular::compute_untemplated vt3 = vr3 - vn3; // relative rotational velocity - // Luding Gran Matt 2008, v10,p235 suggests correcting radi and radj by subtracting - // delta/2, i.e. instead of radi, use distance to center of contact point? wr1 = (radi*omega[i][0] + radj*omega[j][0]); wr2 = (radi*omega[i][1] + radj*omega[j][1]); wr3 = (radi*omega[i][2] + radj*omega[j][2]); @@ -508,7 +506,7 @@ void PairGranular::compute_untemplated // history effects touch[jj] = 1; - history = &allhistory[3*jj]; + history = &allhistory[size_history*jj]; shrmag = sqrt(history[0]*history[0] + history[1]*history[1] + history[2]*history[2]); @@ -760,9 +758,9 @@ void PairGranular::settings(int narg, char **arg) if (coeff_types == MATERIAL) error->all(FLERR,"Illegal pair_coeff command, 'stiffness' coefficients required for Hooke"); if (iarg + 2 >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for Hooke option"); normal_global = HOOKE; - memory->create(normal_coeffs_one, 2, "pair:normal_coeffs_one"); - normal_coeffs_one[0] = force->numeric(FLERR,arg[iarg+1]); //kn - normal_coeffs_one[1] = force->numeric(FLERR,arg[iarg+2]); //damping + memory->create(normal_coeffs_global, 2, "pair:normal_coeffs_global"); + normal_coeffs_global[0] = force->numeric(FLERR,arg[iarg+1]); //kn + normal_coeffs_global[1] = force->numeric(FLERR,arg[iarg+2]); //damping iarg += 3; } else if (strcmp(arg[iarg], "hertz") == 0){ @@ -770,21 +768,21 @@ void PairGranular::settings(int narg, char **arg) if (coeff_types == MATERIAL) num_coeffs += 1; if (iarg + offset >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for Hertz option"); normal_global = HERTZ; - memory->create(normal_coeffs_one, num_coeffs, "pair:normal_coeffs_one"); - normal_coeffs_one[0] = force->numeric(FLERR,arg[iarg+1]); //kn or E - normal_coeffs_one[1] = force->numeric(FLERR,arg[iarg+2]); //damping - if (coeff_types == MATERIAL) normal_coeffs_one[2] = force->numeric(FLERR,arg[iarg+3]); //G (if 'material') + memory->create(normal_coeffs_global, num_coeffs, "pair:normal_coeffs_global"); + normal_coeffs_global[0] = force->numeric(FLERR,arg[iarg+1]); //kn or E + normal_coeffs_global[1] = force->numeric(FLERR,arg[iarg+2]); //damping + if (coeff_types == MATERIAL) normal_coeffs_global[2] = force->numeric(FLERR,arg[iarg+3]); //G (if 'material') iarg += num_coeffs+1; } else if (strcmp(arg[iarg], "dmt") == 0){ if (coeff_types == STIFFNESS) error->all(FLERR,"Illegal pair_style command, 'material' coefficients required for DMT"); if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for Hertz option"); normal_global = DMT; - memory->create(normal_coeffs_one, 4, "pair:normal_coeffs_one"); - normal_coeffs_one[0] = force->numeric(FLERR,arg[iarg+1]); //E - normal_coeffs_one[1] = force->numeric(FLERR,arg[iarg+2]); //damping - normal_coeffs_one[2] = force->numeric(FLERR,arg[iarg+3]); //G - normal_coeffs_one[3] = force->numeric(FLERR,arg[iarg+3]); //cohesion + memory->create(normal_coeffs_global, 4, "pair:normal_coeffs_global"); + normal_coeffs_global[0] = force->numeric(FLERR,arg[iarg+1]); //E + normal_coeffs_global[1] = force->numeric(FLERR,arg[iarg+2]); //damping + normal_coeffs_global[2] = force->numeric(FLERR,arg[iarg+3]); //G + normal_coeffs_global[3] = force->numeric(FLERR,arg[iarg+3]); //cohesion iarg += 5; } else if (strcmp(arg[iarg], "jkr") == 0){ @@ -792,11 +790,11 @@ void PairGranular::settings(int narg, char **arg) if (coeff_types == STIFFNESS) error->all(FLERR,"Illegal pair_style command, 'material' coefficients required for JKR"); beyond_contact = 1; normal_global = JKR; - memory->create(normal_coeffs_one, 4, "pair:normal_coeffs_one"); - normal_coeffs_one[0] = force->numeric(FLERR,arg[iarg+1]); //E - normal_coeffs_one[1] = force->numeric(FLERR,arg[iarg+2]); //damping - normal_coeffs_one[2] = force->numeric(FLERR,arg[iarg+3]); //G - normal_coeffs_one[3] = force->numeric(FLERR,arg[iarg+4]); //cohesion + memory->create(normal_coeffs_global, 4, "pair:normal_coeffs_global"); + normal_coeffs_global[0] = force->numeric(FLERR,arg[iarg+1]); //E + normal_coeffs_global[1] = force->numeric(FLERR,arg[iarg+2]); //damping + normal_coeffs_global[2] = force->numeric(FLERR,arg[iarg+3]); //G + normal_coeffs_global[3] = force->numeric(FLERR,arg[iarg+4]); //cohesion iarg += 5; } else if (strcmp(arg[iarg], "damp_velocity") == 0){ @@ -820,10 +818,10 @@ void PairGranular::settings(int narg, char **arg) tangential_global = TANGENTIAL_MINDLIN; tangential_history = 1; } - memory->create(tangential_coeffs_one, 3, "pair:tangential_coeffs_one"); - tangential_coeffs_one[0] = force->numeric(FLERR,arg[iarg+1]); //kt - tangential_coeffs_one[1] = force->numeric(FLERR,arg[iarg+2]); //gammat - tangential_coeffs_one[2] = force->numeric(FLERR,arg[iarg+3]); //friction coeff. + memory->create(tangential_coeffs_global, 3, "pair:tangential_coeffs_global"); + tangential_coeffs_global[0] = force->numeric(FLERR,arg[iarg+1]); //kt + tangential_coeffs_global[1] = force->numeric(FLERR,arg[iarg+2]); //gammat + tangential_coeffs_global[2] = force->numeric(FLERR,arg[iarg+3]); //friction coeff. iarg += 4; } else if (strstr(arg[iarg], "rolling") != NULL){ @@ -835,17 +833,17 @@ void PairGranular::settings(int narg, char **arg) rolling_global = ROLLING_SDS; rolling_history = 1; } - memory->create(rolling_coeffs_one, 3, "pair:rolling_coeffs_one"); - rolling_coeffs_one[0] = force->numeric(FLERR,arg[iarg+1]); //kt - rolling_coeffs_one[1] = force->numeric(FLERR,arg[iarg+2]); //gammat - rolling_coeffs_one[2] = force->numeric(FLERR,arg[iarg+3]); //friction coeff. + memory->create(rolling_coeffs_global, 3, "pair:rolling_coeffs_global"); + rolling_coeffs_global[0] = force->numeric(FLERR,arg[iarg+1]); //kt + rolling_coeffs_global[1] = force->numeric(FLERR,arg[iarg+2]); //gammat + rolling_coeffs_global[2] = force->numeric(FLERR,arg[iarg+3]); //friction coeff. iarg += 4; } else if (strstr(arg[iarg], "twisting") != NULL){ if (strstr(arg[iarg], "marshall") != NULL){ twisting_global = TWISTING_MARSHALL; twisting_history = 1; - memory->create(twisting_coeffs_one, 3, "pair:twisting_coeffs_one"); //To be filled later + memory->create(twisting_coeffs_global, 3, "pair:twisting_coeffs_global"); //To be filled later } else{ if (iarg + 3 >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for twisting model"); @@ -856,15 +854,60 @@ void PairGranular::settings(int narg, char **arg) twisting_global = TWISTING_SDS; twisting_history = 1; } - memory->create(twisting_coeffs_one, 3, "pair:twisting_coeffs_one"); - twisting_coeffs_one[0] = force->numeric(FLERR,arg[iarg+1]); //kt - twisting_coeffs_one[1] = force->numeric(FLERR,arg[iarg+2]); //gammat - twisting_coeffs_one[2] = force->numeric(FLERR,arg[iarg+3]); //friction coeff. + memory->create(twisting_coeffs_global, 3, "pair:twisting_coeffs_global"); + twisting_coeffs_global[0] = force->numeric(FLERR,arg[iarg+1]); //kt + twisting_coeffs_global[1] = force->numeric(FLERR,arg[iarg+2]); //gammat + twisting_coeffs_global[2] = force->numeric(FLERR,arg[iarg+3]); //friction coeff. iarg += 4; } } } + //Set all i-i entrie, which may be replaced by pair coeff commands + //It may also make sense to consider removing all of the above, and only + // having the option for pair_coeff to set the parameters, similar to most LAMMPS pair styles + // The reason for the current setup is to keep true to existing pair gran/hooke etc. syntax, + // where coeffs are set in the pair_style command, and a pair_coeff * * command is issued. + allocate(); + double damp; + for (int i = 1; i <= atom->ntypes; i++){ + normal[i][i] = normal_global; + damping[i][i] = damping_global; + tangential[i][i] = tangential_global; + rolling[i][i] = rolling_global; + twisting[i][i] = twisting_global; + + if (damping_global == TSUJI){ + double cor = normal_coeffs_global[1]; + damp = 1.2728-4.2783*cor+11.087*pow(cor,2)-22.348*pow(cor,3)+ + 27.467*pow(cor,4)-18.022*pow(cor,5)+ + 4.8218*pow(cor,6); + } + else damp = normal_coeffs_global[1]; + normal_coeffs[i][i][0] = normal_coeffs_global[0]; + normal_coeffs[i][i][1] = damp; + if (coeff_types == MATERIAL) normal_coeffs[i][i][2] = normal_coeffs_global[2]; + if ((normal_global == JKR) || (normal_global == DMT)) + normal_coeffs[i][i][3] = normal_coeffs_global[3]; + + tangential[i][i] = tangential_global; + if (tangential_global != NONE) + for (int k = 0; k < 3; k++) + tangential_coeffs[i][i][k] = tangential_coeffs_global[k]; + + rolling[i][i] = rolling_global; + if (rolling_global != NONE) + for (int k = 0; k < 3; k++) + rolling_coeffs[i][i][k] = rolling_coeffs_global[k]; + + twisting[i][i] = twisting_global; + if (twisting_global != NONE) + for (int k = 0; k < 3; k++) + twisting_coeffs[i][i][k] = twisting_coeffs_local[k]; + + setflag[i][i] = 1; + } + //Additional checks if (tangential_global == -1){ error->all(FLERR, "Illegal pair_style command: must specify tangential model"); @@ -1005,7 +1048,7 @@ void PairGranular::coeff(int narg, char **arg) double damp; if (damping_local == TSUJI){ double cor = normal_coeffs_local[1]; - damp =1.2728-4.2783*cor+11.087*pow(cor,2)-22.348*pow(cor,3)+ + damp = 1.2728-4.2783*cor+11.087*pow(cor,2)-22.348*pow(cor,3)+ 27.467*pow(cor,4)-18.022*pow(cor,5)+ 4.8218*pow(cor,6); } @@ -1028,12 +1071,12 @@ void PairGranular::coeff(int narg, char **arg) rolling[i][j] = rolling_local; if (rolling_local != NONE) for (int k = 0; k < 3; k++) - rolling_coeffs[i][j][k] = tangential_coeffs_local[k]; + rolling_coeffs[i][j][k] = rolling_coeffs_local[k]; twisting[i][j] = twisting_local; if (twisting_local != NONE) - for (int k = 0; k < 3; k++) - rolling_coeffs[i][j][k] = tangential_coeffs_local[k]; + for (int k = 0; k < 3; k++) + twisting_coeffs[i][j][k] = twisting_coeffs_local[k]; setflag[i][j] = 1; count++; @@ -1164,36 +1207,39 @@ double PairGranular::init_one(int i, int j) (rolling[i] != rolling[j]) || (twisting[i] != twisting[j])){ - char str[128]; - sprintf(str,"Failed to open FFmpeg pipeline to file %s",filename); - error->one(FLERR,str); + char str[512]; + sprintf(str,"Granular pair style functional forms are different, cannot mix coefficients for types %d and %d. \nThis combination must be set explicitly via pair_coeff command.",i,j); + error->one(FLERR,str); } - G[i][j] = mix_stiffnessG(G[i][i],E[j][j],G[i][i],G[j][j]); - if (normaldamp[i][j] == TSUJI) { - alpha[i][j] = mix_geom(alpha[i][i],alpha[j][j]); + if (coeff_types == MATERIAL){ + normal_coeffs[i][j][0] = mix_stiffnessE(normal_coeffs[i][i][0], normal_coeffs[j][j][0], + normal_coeffs[i][i][2], normal_coeffs[j][j][2]); + normal_coeffs[i][j][2] = mix_stiffnessG(normal_coeffs[i][i][0], normal_coeffs[j][j][0], + normal_coeffs[i][i][2], normal_coeffs[j][j][2]); } - else if (normaldamp[i][j] == BRILLIANTOV) { - gamman[i][j] = mix_geom(gamman[i][i],gamman[j][j]); + else{ + normal_coeffs[i][j][0] = mix_geom(normal_coeffs[i][i][0], normal_coeffs[j][j][0];) } - muS[i][j] = mix_geom(muS[i][i],muS[j][j]); - Ecoh[i][j] = mix_geom(Ecoh[i][i],Ecoh[j][j]); - kR[i][j] = mix_geom(kR[i][i],kR[j][j]); - etaR[i][j] = mix_geom(etaR[i][i],etaR[j][j]); - muR[i][j] = mix_geom(muR[i][i],muR[j][j]); - } - E[j][i] = E[i][j]; - G[j][i] = G[i][j]; - normaldamp[j][i] = normaldamp[i][j]; - alpha[j][i] = alpha[i][j]; - gamman[j][i] = gamman[i][j]; - rollingdamp[j][i] = rollingdamp[i][j]; - muS[j][i] = muS[i][j]; - Ecoh[j][i] = Ecoh[i][j]; - kR[j][i] = kR[i][j]; - etaR[j][i] = etaR[i][j]; - muR[j][i] = muR[i][j]; + normal_coeffs[i][j][1] = mix_geom(normal_coeffs[i][i][1], normal_coeffs[j][j][1];) + if ((normal[i][i] == JKR) || (normal[i][i] == DMT)) + normal_coeffs[i][j][3] = mix_geom(normal_coeffs[i][i][3], normal_coeffs[j][j][3]); + + if (tangential[i][i] != NONE){ + for (int k = 0; k < 3; k++) + tangential_coeffs[i][j][k] = mix_geom(tangential_coeffs[i][i][k], tangential_coeffs[j][j][k]); + } + + if (rolling[i][i] != NONE){ + for (int k = 0; k < 3; k++) + rolling_coeffs[i][j][k] = mix_geom(rolling_coeffs[i][i][k], rolling_coeffs[j][j][k]); + } + + if (twisting[i][i] != NONE){ + for (int k = 0; k < 3; k++) + twisting_coeffs[i][j][k] = mix_geom(twisting_coeffs[i][i][k], twisting_coeffs[j][j][k]); + } double cutoff = cut[i][j]; @@ -1559,7 +1605,7 @@ double PairGranular::memory_usage() } /* ---------------------------------------------------------------------- - mixing of stiffness (E) + mixing of Young's modulus (E) ------------------------------------------------------------------------- */ double PairGranular::mix_stiffnessE(double Eii, double Ejj, double Gii, double Gjj) @@ -1570,7 +1616,7 @@ double PairGranular::mix_stiffnessE(double Eii, double Ejj, double Gii, double G } /* ---------------------------------------------------------------------- - mixing of stiffness (G) + mixing of shear modulus (G) ------------------------------------------------------------------------- */ double PairGranular::mix_stiffnessG(double Eii, double Ejj, double Gii, double Gjj) diff --git a/src/GRANULAR/pair_granular.h b/src/GRANULAR/pair_granular.h index 33d28b03bf..0ad36d85c7 100644 --- a/src/GRANULAR/pair_granular.h +++ b/src/GRANULAR/pair_granular.h @@ -96,10 +96,10 @@ public: int rolling_history_index; int twisting_history_index; - double *normal_coeffs_one; - double *tangential_coeffs_one; - double *rolling_coeffs_one; - double *twisting_coeffs_one; + double *normal_coeffs_global; + double *tangential_coeffs_global; + double *rolling_coeffs_global; + double *twisting_coeffs_global; double ***normal_coeffs; double ***tangential_coeffs; From 71ed60ced31a741b708c114c221257237d2421de Mon Sep 17 00:00:00 2001 From: Dan Stefan Bolintineanu Date: Fri, 21 Dec 2018 15:41:46 -0700 Subject: [PATCH 08/44] More work on compute method for generalized pair granular --- src/GRANULAR/pair_granular.cpp | 502 +++++++++++++-------------------- src/GRANULAR/pair_granular.h | 22 +- 2 files changed, 199 insertions(+), 325 deletions(-) diff --git a/src/GRANULAR/pair_granular.cpp b/src/GRANULAR/pair_granular.cpp index a94575185a..dd124671e0 100644 --- a/src/GRANULAR/pair_granular.cpp +++ b/src/GRANULAR/pair_granular.cpp @@ -39,10 +39,12 @@ Contributing authors: Leo Silbert (SNL), Gary Grest (SNL), using namespace LAMMPS_NS; using namespace MathConst; -#define ONETHIRD 0.33333333333333333 -#define TWOTHIRDS 0.66666666666666666 -#define POW6ONE 0.550321208149104 //6^(-1/3) -#define POW6TWO 0.30285343213869 //6^(-2/3) +#define PI27SQ 266.47931882941264802866 // 27*PI**2 +#define THREEROOT3 5.19615242270663202362 // 3*sqrt(3) +#define SIXROOT6 14.69693845669906728801 // 6*sqrt(6) +#define INVROOT6 0.40824829046386307274 // 1/sqrt(6) +#define FOURTHIRDS 1.333333333333333 // 4/3 +#define TWOPI 6.28318530717959 // 2*PI #define EPSILON 1e-10 @@ -97,17 +99,6 @@ PairGranular::~PairGranular() memory->destroy(cutsq); memory->destroy(cut); - memory->destroy(E); - memory->destroy(G); - memory->destroy(normaldamp); - memory->destroy(rollingdamp); - memory->destroy(alpha); - memory->destroy(gamman); - memory->destroy(muS); - memory->destroy(Ecoh); - memory->destroy(kR); - memory->destroy(muR); - memory->destroy(etaR); delete [] onerad_dynamic; delete [] onerad_frozen; @@ -117,215 +108,38 @@ PairGranular::~PairGranular() memory->destroy(mass_rigid); } -void PairGranular::compute(int eflag, int vflag){ - /* -#ifdef TEMPLATED_PAIR_GRANULAR - if (normal == 0){ - if (damping == 0){ - if (tangential == 0){ - if (rolling == 0){ - if (twisting == 0) compute_templated<0,0,0,0,0,0>(eflag, vflag); - else if (twisting == 1) compute_templated<0,0,0,0,0,1>(eflag, vflag); - else if (twisting == 2) compute_templated<0,0,0,0,0,2>(eflag, vflag); - } - else if (rolling == 1){ - if (twisting == 0) compute_templated<0,0,0,0,1,0>(eflag, vflag); - else if (twisting == 1) compute_templated<0,0,0,0,1,1>(eflag, vflag); - else if (twisting == 2) compute_templated<0,0,0,0,1,2>(eflag, vflag); - } - else if (rolling == 2){ - if (twisting == 0) compute_templated<0,0,0,0,2,0>(eflag, vflag); - else if (twisting == 1) compute_templated<0,0,0,0,2,1>(eflag, vflag); - else if (twisting == 2) compute_templated<0,0,0,0,2,2>(eflag, vflag); - } - } - else if (tangential == 1){ - if (rolling == 0){ - if (twisting == 0) compute_templated<0,0,0,1,0,0>(eflag, vflag); - else if (twisting == 1) compute_templated<0,0,0,1,0,1>(eflag, vflag); - else if (twisting == 2) compute_templated<0,0,0,1,0,2>(eflag, vflag); - } - else if (rolling == 1){ - if (twisting == 0) compute_templated<0,0,0,1,1,0>(eflag, vflag); - else if (twisting == 1) compute_templated<0,0,0,1,1,1>(eflag, vflag); - else if (twisting == 2) compute_templated<0,0,0,1,1,2>(eflag, vflag); - } - else if (rolling == 2){ - if (twisting == 0) compute_templated<0,0,0,1,2,0>(eflag, vflag); - else if (twisting == 1) compute_templated<0,0,0,1,2,1>(eflag, vflag); - else if (twisting == 2) compute_templated<0,0,0,1,2,2>(eflag, vflag); - } - } - else if (tangential == 2){ - if (rolling == 0){ - if (twisting == 0) compute_templated<0,0,0,2,0,0>(eflag, vflag); - else if (twisting == 1) compute_templated<0,0,0,2,0,1>(eflag, vflag); - else if (twisting == 2) compute_templated<0,0,0,2,0,2>(eflag, vflag); - } - else if (rolling == 1){ - if (twisting == 0) compute_templated<0,0,0,2,1,0>(eflag, vflag); - else if (twisting == 1) compute_templated<0,0,0,2,1,1>(eflag, vflag); - else if (twisting == 2) compute_templated<0,0,0,2,1,2>(eflag, vflag); - } - else if (rolling == 2){ - if (twisting == 0) compute_templated<0,0,0,2,2,0>(eflag, vflag); - else if (twisting == 1) compute_templated<0,0,0,2,2,1>(eflag, vflag); - else if (twisting == 2) compute_templated<0,0,0,2,2,2>(eflag, vflag); - } - } - } - else if (damping == 1){ - if (tangential == 0){ - if (rolling == 0){ - if (twisting == 0) compute_templated<0,0,1,0,0,0>(eflag, vflag); - else if (twisting == 1) compute_templated<0,0,1,0,0,1>(eflag, vflag); - else if (twisting == 2) compute_templated<0,0,1,0,0,2>(eflag, vflag); - } - else if (rolling == 1){ - if (twisting == 0) compute_templated<0,0,1,0,1,0>(eflag, vflag); - else if (twisting == 1) compute_templated<0,0,1,0,1,1>(eflag, vflag); - else if (twisting == 2) compute_templated<0,0,1,0,1,2>(eflag, vflag); - } - else if (rolling == 2){ - if (twisting == 0) compute_templated<0,0,1,0,2,0>(eflag, vflag); - else if (twisting == 1) compute_templated<0,0,1,0,2,1>(eflag, vflag); - else if (twisting == 2) compute_templated<0,0,1,0,2,2>(eflag, vflag); - } - } - else if (tangential == 1){ - if (rolling == 0){ - if (twisting == 0) compute_templated<0,0,1,1,0,0>(eflag, vflag); - else if (twisting == 1) compute_templated<0,0,1,1,0,1>(eflag, vflag); - else if (twisting == 2) compute_templated<0,0,1,1,0,2>(eflag, vflag); - } - else if (rolling == 1){ - if (twisting == 0) compute_templated<0,0,1,1,1,0>(eflag, vflag); - else if (twisting == 1) compute_templated<0,0,1,1,1,1>(eflag, vflag); - else if (twisting == 2) compute_templated<0,0,1,1,1,2>(eflag, vflag); - } - else if (rolling == 2){ - if (twisting == 0) compute_templated<0,0,1,1,2,0>(eflag, vflag); - else if (twisting == 1) compute_templated<0,0,1,1,2,1>(eflag, vflag); - else if (twisting == 2) compute_templated<0,0,1,1,2,2>(eflag, vflag); - } - } - else if (tangential == 2){ - if (rolling == 0){ - if (twisting == 0) compute_templated<0,0,1,2,0,0>(eflag, vflag); - else if (twisting == 1) compute_templated<0,0,1,2,0,1>(eflag, vflag); - else if (twisting == 2) compute_templated<0,0,1,2,0,2>(eflag, vflag); - } - else if (rolling == 1){ - if (twisting == 0) compute_templated<0,0,1,2,1,0>(eflag, vflag); - else if (twisting == 1) compute_templated<0,0,1,2,1,1>(eflag, vflag); - else if (twisting == 2) compute_templated<0,0,1,2,1,2>(eflag, vflag); - } - else if (rolling == 2){ - if (twisting == 0) compute_templated<0,0,1,2,2,0>(eflag, vflag); - else if (twisting == 1) compute_templated<0,0,1,2,2,1>(eflag, vflag); - else if (twisting == 2) compute_templated<0,0,1,2,2,2>(eflag, vflag); - } - } - } - else if (damping == 2){ - if (tangential == 0){ - if (rolling == 0){ - if (twisting == 0) compute_templated<0,0,2,0,0,0>(eflag, vflag); - else if (twisting == 1) compute_templated<0,0,2,0,0,1>(eflag, vflag); - else if (twisting == 2) compute_templated<0,0,2,0,0,2>(eflag, vflag); - } - else if (rolling == 1){ - if (twisting == 0) compute_templated<0,0,2,0,1,0>(eflag, vflag); - else if (twisting == 1) compute_templated<0,0,2,0,1,1>(eflag, vflag); - else if (twisting == 2) compute_templated<0,0,2,0,1,2>(eflag, vflag); - } - else if (rolling == 2){ - if (twisting == 0) compute_templated<0,0,2,0,2,0>(eflag, vflag); - else if (twisting == 1) compute_templated<0,0,2,0,2,1>(eflag, vflag); - else if (twisting == 2) compute_templated<0,0,2,0,2,2>(eflag, vflag); - } - } - else if (tangential == 1){ - if (rolling == 0){ - if (twisting == 0) compute_templated<0,0,2,1,0,0>(eflag, vflag); - else if (twisting == 1) compute_templated<0,0,2,1,0,1>(eflag, vflag); - else if (twisting == 2) compute_templated<0,0,2,1,0,2>(eflag, vflag); - } - else if (rolling == 1){ - if (twisting == 0) compute_templated<0,0,2,1,1,0>(eflag, vflag); - else if (twisting == 1) compute_templated<0,0,2,1,1,1>(eflag, vflag); - else if (twisting == 2) compute_templated<0,0,2,1,1,2>(eflag, vflag); - } - else if (rolling == 2){ - if (twisting == 0) compute_templated<0,0,2,1,2,0>(eflag, vflag); - else if (twisting == 1) compute_templated<0,0,2,1,2,1>(eflag, vflag); - else if (twisting == 2) compute_templated<0,0,2,1,2,2>(eflag, vflag); - } - } - else if (tangential == 2){ - if (rolling == 0){ - if (twisting == 0) compute_templated<0,0,2,2,0,0>(eflag, vflag); - else if (twisting == 1) compute_templated<0,0,2,2,0,1>(eflag, vflag); - else if (twisting == 2) compute_templated<0,0,2,2,0,2>(eflag, vflag); - } - else if (rolling == 1){ - if (twisting == 0) compute_templated<0,0,2,2,1,0>(eflag, vflag); - else if (twisting == 1) compute_templated<0,0,2,2,1,1>(eflag, vflag); - else if (twisting == 2) compute_templated<0,0,2,2,1,2>(eflag, vflag); - } - else if (rolling == 2){ - if (twisting == 0) compute_templated<0,0,2,2,2,0>(eflag, vflag); - else if (twisting == 1) compute_templated<0,0,2,2,2,1>(eflag, vflag); - else if (twisting == 2) compute_templated<0,0,2,2,2,2>(eflag, vflag); - } - } - } - } - - - } -#else -#endif -*/ - compute_untemplated(Tp_coeff_types, Tp_normal, Tp_damping, Tp_tangential, - Tp_rolling, Tp_twisting, eflag, vflag); -} -/* ---------------------------------------------------------------------- */ -/*#ifdef TEMPLATED_PAIR_GRANULAR -template < int Tp_coeff_types, - int Tp_normal, int Tp_damping, int Tp_tangential, - int Tp_rolling, int Tp_twisting > -void PairGranular::compute_templated(int eflag, int vflag) -#else -*/ -void PairGranular::compute_untemplated - (int Tp_coeff_types, - int Tp_normal, int Tp_damping, int Tp_tangential, - int Tp_rolling, int Tp_twisting, - int eflag, int vflag) -//#endif +void PairGranular::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,fx,fy,fz,nx,ny,nz; - double radi,radj,radsum,rsq,r,rinv,rsqinv,R,a; + double radi,radj,radsum,rsq,r,rinv,rsqinv; + double Reff, delta, dR, dR2, sqdR, knfac; + double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3; double wr1,wr2,wr3; double vtr1,vtr2,vtr3,vrel; - double kn, kt, k_Q, k_R, eta_N, eta_T, eta_Q, eta_R; + + double damp_normal, damp_tangential; + double kt; double Fne, Fdamp, Fntot, Fscrit, Frcrit; //For JKR - double R, R2, coh, delta_pulloff, dist_pulloff, a, E; - double overlap, olapsq, olapcubed, sqrtterm, tmp, a0; - double keyterm, keyterm2, keyterm3, aovera0, foverFc; + double R2, coh, delta_pulloff, dist_pulloff, a, a2, E; + double delta, t0, t1, t2, t3, t4, t5, t6; + double sqrt1, sqrt2, sqrt3, sqrt4; double mi,mj,meff,damp,ccel,tor1,tor2,tor3; double relrot1,relrot2,relrot3,vrl1,vrl2,vrl3,vrlmag,vrlmaginv; + + //Rolling double rollmag, rolldotn, scalefac; double fr, fr1, fr2, fr3; + + //Twisting double signtwist, magtwist, magtortwist, Mtcrit; double fs,fs1,fs2,fs3,roll1,roll2,roll3,torroll1,torroll2,torroll3; double tortwist1, tortwist2, tortwist3; + double shrmag,rsht; int *ilist,*jlist,*numneigh,**firstneigh; int *touch,**firsttouch; @@ -378,15 +192,6 @@ void PairGranular::compute_untemplated firsttouch = fix_history->firstflag; firsthistory = fix_history->firstvalue; - double coh; - double **cohesion; - double **stiffness; - double **damping; - if (Tp_normal == JKR){ - cohesion = coeffs[normal_coeff_inds[4]]; - } - - for (ii = 0; ii < inum; ii++) { i = ilist[ii]; itype = type[i]; @@ -413,12 +218,13 @@ void PairGranular::compute_untemplated radsum = radi + radj; untouchflag = (rsq >= radsum*radsum); + E = normal_coeffs[itype][jtype][0]; + Reff = radi*radj/(radi+radj); if (normal[itype][jtype] == JKR){ - R = radi*radj/(radi+radj); - R2 = R*R; - coh = cohesion[itype][jtype]; + R2 = Reff*Reff; + coh = normal_coeffs[itype][jtype][3]; a = cbrt(9.0*M_PI*coh*R2/(4*E)); - delta_pulloff = a*a/R - 2*sqrt(M_PI*coh*a/E); + delta_pulloff = a*a/Reff - 2*sqrt(M_PI*coh*a/E); dist_pulloff = radsum+delta_pulloff; untouchflag = (rsq >= (dist_pulloff)*(dist_pulloff)); } @@ -466,22 +272,52 @@ void PairGranular::compute_untemplated if (mask[i] & freeze_group_bit) meff = mj; if (mask[j] & freeze_group_bit) meff = mi; - //**************************************** - //Normal force = JKR-adjusted Hertzian contact + damping - //**************************************** + delta = radsum - r; + if (normal[itype][jtype] == JKR){ - + dR = delta*Reff; + dR2 = dR*dR; + t0 = coh*coh*R2*R2*E; + t1 = PI27SQ*t0; + t2 = 8*dR*dR2*E*E*E; + t3 = 4*dR2*E; + sqrt1 = MAX(0, t0*(t1+2*t2)); //In case of sqrt(0) < 0 due to precision issues + t4 = cbrt(t1+t2+THREEROOT3*M_PI*sqrt(sqrt1)); + t5 = t3/t4 + t4/E; + sqrt2 = MAX(0, 2*dR + t5); + t6 = sqrt(sqrt2); + sqrt3 = MAX(0, 4*dR - t5 + SIXROOT6*coh*M_PI*R2/(E*t6)); + a = INVROOT6*(t6 + sqrt(sqrt3)); + a2 = a*a; + knfac = FOURTHIRDS*E*a; + Fne = knfac*a2/Reff - TWOPI*a2*sqrt(4*coh*E/(M_PI*a)); } - //Damping - kn = 4.0/3.0*E[itype][jtype]*a; - if (normaldamp[itype][jtype] == BRILLIANTOV) eta_N = a*meff*gamman[itype][jtype]; - else if (normaldamp[itype][jtype] == TSUJI) eta_N=alpha[itype][jtype]*sqrt(meff*kn); - Fdamp = -eta_N*vnnr; //F_nd eq 23 and Zhao eq 19 + else if (normal[itype][jtype] != HOOKE){ //HERTZ, DMT + a = sqdR = sqrt(dR); + knfac = FOURTHIRDS*E*sqdR; + Fne = knfac*delta; + } + else{ //Hooke + knfac = FOURTHIRDS*E; + Fne = knfac*delta; + } + + //Consider restricting Hooke to only have 'velocity' as an option for damping? + if (damping[itype][jtype] == VELOCITY){ + damp_normal = normal_coeffs[itype][jtype][1]; + } + else if (damping[itype][jtype] == VISCOELASTIC){ + if (normal[itype][jtype] == HOOKE) sqdR = sqrt(dR); + damp_normal = normal_coeffs[itype][jtype][1]*sqdR*meff; + } + else if (damping[itype][jtype] == TSUJI){ + damp_normal = normal_coeffs[itype][jtype][1]*sqrt(meff*knfac); + } + + Fdamp = -damp_normal*vnnr; Fntot = Fne + Fdamp; - //if (screen) fprintf(screen,"%d %d %16.16g %16.16g \n",itype,jtype,Ecoh[itype][jtype],E[itype][jtype]); - //if (logfile) fprintf(logfile,"%d %d %16.16g %16.16g \n",itype,jtype,Ecoh[itype][jtype],E[itype][jtype]); //**************************************** //Tangential force, including history effects @@ -505,54 +341,58 @@ void PairGranular::compute_untemplated vrel = sqrt(vrel); // history effects - touch[jj] = 1; - history = &allhistory[size_history*jj]; - shrmag = sqrt(history[0]*history[0] + history[1]*history[1] + - history[2]*history[2]); + if (tangential_history[itype][jtype]){ + touch[jj] = 1; + history = &allhistory[size_history*jj]; + shrmag = sqrt(history[0]*history[0] + history[1]*history[1] + + history[2]*history[2]); - // Rotate and update displacements. - // See e.g. eq. 17 of Luding, Gran. Matter 2008, v10,p235 - if (historyupdate) { - rsht = history[0]*nx + history[1]*ny + history[2]*nz; - if (fabs(rsht) < EPSILON) rsht = 0; - if (rsht > 0){ - scalefac = shrmag/(shrmag - rsht); //if rhst == shrmag, contacting pair has rotated 90 deg. in one step, in which case you deserve a crash! - history[0] -= rsht*nx; - history[1] -= rsht*ny; - history[2] -= rsht*nz; - //Also rescale to preserve magnitude - history[0] *= scalefac; - history[1] *= scalefac; - history[2] *= scalefac; + // Rotate and update displacements. + // See e.g. eq. 17 of Luding, Gran. Matter 2008, v10,p235 + if (historyupdate) { + rsht = history[0]*nx + history[1]*ny + history[2]*nz; + if (fabs(rsht) < EPSILON) rsht = 0; + if (rsht > 0){ + scalefac = shrmag/(shrmag - rsht); //if rhst == shrmag, contacting pair has rotated 90 deg. in one step, in which case you deserve a crash! + history[0] -= rsht*nx; + history[1] -= rsht*ny; + history[2] -= rsht*nz; + //Also rescale to preserve magnitude + history[0] *= scalefac; + history[1] *= scalefac; + history[2] *= scalefac; + } + //Update history + history[0] += vtr1*dt; + history[1] += vtr2*dt; + history[2] += vtr3*dt; } - //Update history - history[0] += vtr1*dt; - history[1] += vtr2*dt; - history[2] += vtr3*dt; - } - // tangential forces = history + tangential velocity damping - // following Zhao and Marshall Phys Fluids v20, p043302 (2008) - kt=8.0*G[itype][jtype]*a; + // tangential forces = history + tangential velocity damping + if (normal[itype][jtype] == HOOKE) a = sqdR = sqrt(dR); + kt=tangential_coeffs[itype][jtype][0]*a; - eta_T = eta_N; //Based on discussion in Marshall; eta_T can also be an independent parameter - fs1 = -kt*history[0] - eta_T*vtr1; //eq 26 - fs2 = -kt*history[1] - eta_T*vtr2; - fs3 = -kt*history[2] - eta_T*vtr3; + damp_tangential = tangential_coeffs[itype][jtype][1]*damp_normal; + fs1 = -kt*history[0] - damp_tangential*vtr1; + fs2 = -kt*history[1] - damp_tangential*vtr2; + fs3 = -kt*history[2] - damp_tangential*vtr3; - // rescale frictional displacements and forces if needed - Fscrit = muS[itype][jtype] * fabs(Fne + 2*F_C); - // For JKR, use eq 43 of Marshall. For DMT, use Fne instead + // rescale frictional displacements and forces if needed + if (normal[itype][jtype] == JKR){ + double Fpulloff = -3*M_PI*coh*Reff; + Fscrit = tangential_coeffs[itype][jtype][2] * fabs(Fne + 2*Fpulloff); + } + else{ + Fscrit = tangential_coeffs[itype][jtype][2] * fabs(Fne); + } + // For JKR, use eq 43 of Marshall. For DMT, use Fne instead fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); if (fs > Fscrit) { if (shrmag != 0.0) { - //history[0] = (Fcrit/fs) * (history[0] + eta_T*vtr1/kt) - eta_T*vtr1/kt; - //history[1] = (Fcrit/fs) * (history[1] + eta_T*vtr1/kt) - eta_T*vtr1/kt; - //history[2] = (Fcrit/fs) * (history[2] + eta_T*vtr1/kt) - eta_T*vtr1/kt; - history[0] = -1.0/kt*(Fscrit*fs1/fs + eta_T*vtr1); //Same as above, but simpler (check!) - history[1] = -1.0/kt*(Fscrit*fs2/fs + eta_T*vtr2); - history[2] = -1.0/kt*(Fscrit*fs3/fs + eta_T*vtr3); + history[0] = -1.0/kt*(Fscrit*fs1/fs + damp_tangential*vtr1); + history[1] = -1.0/kt*(Fscrit*fs2/fs + damp_tangential*vtr2); + history[2] = -1.0/kt*(Fscrit*fs3/fs + damp_tangential*vtr3); fs1 *= Fscrit/fs; fs2 *= Fscrit/fs; fs3 *= Fscrit/fs; @@ -715,6 +555,7 @@ void PairGranular::allocate() setflag[i][j] = 0; memory->create(cutsq,n+1,n+1,"pair:cutsq"); + memory->create(cut,n+1,n+1,"pair:cut"); memory->create(normal_coeffs,n+1,n+1,4,"pair:normal_coeffs"); memory->create(tangential_coeffs,n+1,n+1,3,"pair:tangential_coeffs"); memory->create(rolling_coeffs,n+1,n+1,3,"pair:rolling_coeffs"); @@ -770,6 +611,7 @@ void PairGranular::settings(int narg, char **arg) normal_global = HERTZ; memory->create(normal_coeffs_global, num_coeffs, "pair:normal_coeffs_global"); normal_coeffs_global[0] = force->numeric(FLERR,arg[iarg+1]); //kn or E + if (coeff_types == STIFFNESS) normal_coeffs_global[0] /= FOURTHIRDS; normal_coeffs_global[1] = force->numeric(FLERR,arg[iarg+2]); //damping if (coeff_types == MATERIAL) normal_coeffs_global[2] = force->numeric(FLERR,arg[iarg+3]); //G (if 'material') iarg += num_coeffs+1; @@ -956,6 +798,7 @@ void PairGranular::coeff(int narg, char **arg) if (iarg + offset >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hertz option"); normal_local = HERTZ; normal_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1]); //kn or E + if (coeff_types == STIFFNESS) normal_coeffs_local[0] /= FOURTHIRDS; normal_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //damping if (coeff_types == MATERIAL) normal_coeffs_local[2] = force->numeric(FLERR,arg[iarg+3]); //G (if 'material') iarg += num_coeffs+1; @@ -1079,6 +922,8 @@ void PairGranular::coeff(int narg, char **arg) twisting_coeffs[i][j][k] = twisting_coeffs_local[k]; setflag[i][j] = 1; + double cut_one; + count++; } } @@ -1100,18 +945,36 @@ void PairGranular::init_style() if (comm->ghost_velocity == 0) error->all(FLERR,"Pair granular requires ghost atoms store velocity"); - // need a granular neigh list + // Determine whether we need a granular neigh list, how large it needs to be + history_flag = tangential_history || rolling_history || twisting_history; + size_history = 3*tangential_history + 3*rolling_history + twisting_history; + + //Determine location of tangential/rolling/twisting histories in array + if (rolling_history){ + if (tangential_history) rolling_history_index = 3; + else rolling_history_index = 0; + } + if (twisting_history){ + if (tangential_history){ + if (rolling_history) twisting_history_index = 6; + else twisting_history_index = 3; + } + else{ + if (rolling_history) twisting_history_index = 3; + else twisting_history_index = 0; + } + } int irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->size = 1; - if (history) neighbor->requests[irequest]->history = 1; + if (history_flag) neighbor->requests[irequest]->history = 1; dt = update->dt; // if history is stored: // if first init, create Fix needed for storing history - if (history && fix_history == NULL) { + if (history_flag && fix_history == NULL) { char dnumstr[16]; sprintf(dnumstr,"%d",size_history); char **fixarg = new char*[4]; @@ -1159,13 +1022,15 @@ void PairGranular::init_style() onerad_dynamic[i] = onerad_frozen[i] = 0.0; if (ipour >= 0) { itype = i; - onerad_dynamic[i] = - *((double *) modify->fix[ipour]->extract("radius",itype)); + double radmax = *((double *) modify->fix[ipour]->extract("radius",itype)); + if (normal[itype][itype] == JKR) radmax = radmax + 0.5*pulloff_distance(radmax, itype); + onerad_dynamic[i] = radmax; } if (idep >= 0) { itype = i; - onerad_dynamic[i] = - *((double *) modify->fix[idep]->extract("radius",itype)); + double radmax = *((double *) modify->fix[idep]->extract("radius",itype)); + if (normal[itype][itype] == JKR) radmax = radmax + 0.5*pulloff_distance(radmax, itype); + onerad_dynamic[i] = radmax; } } @@ -1174,11 +1039,18 @@ void PairGranular::init_style() int *type = atom->type; int nlocal = atom->nlocal; - for (i = 0; i < nlocal; i++) - if (mask[i] & freeze_group_bit) - onerad_frozen[type[i]] = MAX(onerad_frozen[type[i]],radius[i]); - else - onerad_dynamic[type[i]] = MAX(onerad_dynamic[type[i]],radius[i]); + for (i = 0; i < nlocal; i++){ + double radius_cut = radius[i]; + if (normal[type[i]][type[i]] == JKR){ + radius_cut = radius[i] + 0.5*pulloff_distance(radius[i], type[i]); + } + if (mask[i] & freeze_group_bit){ + onerad_frozen[type[i]] = MAX(onerad_frozen[type[i]],radius_cut); + } + else{ + onerad_dynamic[type[i]] = MAX(onerad_dynamic[type[i]],radius_cut); + } + } MPI_Allreduce(&onerad_dynamic[1],&maxrad_dynamic[1],atom->ntypes, MPI_DOUBLE,MPI_MAX,world); @@ -1187,7 +1059,7 @@ void PairGranular::init_style() // set fix which stores history info - if (size_history > 0) { + if (size_history > 0){ int ifix = modify->find_fix("NEIGH_HISTORY"); if (ifix < 0) error->all(FLERR,"Could not find pair fix neigh history ID"); fix_history = (FixNeighHistory *) modify->fix[ifix]; @@ -1219,10 +1091,11 @@ double PairGranular::init_one(int i, int j) normal_coeffs[i][i][2], normal_coeffs[j][j][2]); } else{ - normal_coeffs[i][j][0] = mix_geom(normal_coeffs[i][i][0], normal_coeffs[j][j][0];) + normal_coeffs[i][j][0] = mix_geom(normal_coeffs[i][i][0], normal_coeffs[j][j][0]); + if (normal[i][j] == HERTZ) normal_coeffs[i][j][0] /= FOURTHIRDS; } - normal_coeffs[i][j][1] = mix_geom(normal_coeffs[i][i][1], normal_coeffs[j][j][1];) + normal_coeffs[i][j][1] = mix_geom(normal_coeffs[i][i][1], normal_coeffs[j][j][1]); if ((normal[i][i] == JKR) || (normal[i][i] == DMT)) normal_coeffs[i][j][3] = mix_geom(normal_coeffs[i][i][3], normal_coeffs[j][j][3]); @@ -1240,32 +1113,31 @@ double PairGranular::init_one(int i, int j) for (int k = 0; k < 3; k++) twisting_coeffs[i][j][k] = mix_geom(twisting_coeffs[i][i][k], twisting_coeffs[j][j][k]); } + } - double cutoff = cut[i][j]; - - // It is likely that cut[i][j] at this point is still 0.0. This can happen when + // It is possible that cut[i][j] at this point is still 0.0. This can happen when // there is a future fix_pour after the current run. A cut[i][j] = 0.0 creates // problems because neighbor.cpp uses min(cut[i][j]) to decide on the bin size - // To avoid this issue,for cases involving cut[i][j] = 0.0 (possible only + // To avoid this issue, for cases involving cut[i][j] = 0.0 (possible only // if there is no current information about radius/cutoff of type i and j). - // we assign cutoff = min(cut[i][j]) for i,j such that cut[i][j] > 0.0. + // we assign cutoff = max(cut[i][j]) for i,j such that cut[i][j] > 0.0. - if (cut[i][j] < 0.0) { - if (((maxrad_dynamic[i] > 0.0) && (maxrad_dynamic[j] > 0.0)) || ((maxrad_dynamic[i] > 0.0) && (maxrad_frozen[j] > 0.0)) || - ((maxrad_frozen[i] > 0.0) && (maxrad_dynamic[j] > 0.0))) { // radius info about both i and j exist - cutoff = maxrad_dynamic[i]+maxrad_dynamic[j]; - cutoff = MAX(cutoff,maxrad_frozen[i]+maxrad_dynamic[j]); - cutoff = MAX(cutoff,maxrad_dynamic[i]+maxrad_frozen[j]); - } - else { // radius info about either i or j does not exist (i.e. not present and not about to get poured; set to largest value to not interfere with neighbor list) - double cutmax = 0.0; - for (int k = 1; k <= atom->ntypes; k++) { - cutmax = MAX(cutmax,2.0*maxrad_dynamic[k]); - cutmax = MAX(cutmax,2.0*maxrad_frozen[k]); - } - cutoff = cutmax; - } + if (((maxrad_dynamic[i] > 0.0) && (maxrad_dynamic[j] > 0.0)) || + ((maxrad_dynamic[i] > 0.0) && (maxrad_frozen[j] > 0.0)) || + ((maxrad_frozen[i] > 0.0) && (maxrad_dynamic[j] > 0.0))) { // radius info about both i and j exist + cutoff = maxrad_dynamic[i]+maxrad_dynamic[j]; + cutoff = MAX(cutoff,maxrad_frozen[i]+maxrad_dynamic[j]); + cutoff = MAX(cutoff,maxrad_dynamic[i]+maxrad_frozen[j]); } + else { // radius info about either i or j does not exist (i.e. not present and not about to get poured; set to largest value to not interfere with neighbor list) + double cutmax = 0.0; + for (int k = 1; k <= atom->ntypes; k++) { + cutmax = MAX(cutmax,2.0*maxrad_dynamic[k]); + cutmax = MAX(cutmax,2.0*maxrad_frozen[k]); + } + cutoff = cutmax; + } + return cutoff; } @@ -1628,9 +1500,25 @@ double PairGranular::mix_stiffnessG(double Eii, double Ejj, double Gii, double G /* ---------------------------------------------------------------------- mixing of everything else - ------------------------------------------------------------------------- */ +------------------------------------------------------------------------- */ double PairGranular::mix_geom(double valii, double valjj) { - return sqrt(valii*valjj); + return sqrt(valii*valjj); } + + +/* ---------------------------------------------------------------------- + Compute pull-off distance (beyond contact) for a given radius and atom type +------------------------------------------------------------------------- */ + +double PairGranular::pulloff_distance(double radius, int itype) +{ + double R, E, coh, a, delta_pulloff; + coh = normal_coeffs[itype][itype][3]; + E = mix_stiffnessE(normal_coeffs[itype][itype][0], normal_coeffs[itype][itype][0], + normal_coeffs[itype][itype][2], normal_coeffs[itype][itype][2]); + a = cbrt(9*M_PI*coh*R*R/(4*E)); + return a*a/R - 2*sqrt(M_PI*coh*a/E); +} + diff --git a/src/GRANULAR/pair_granular.h b/src/GRANULAR/pair_granular.h index 0ad36d85c7..14cc02675b 100644 --- a/src/GRANULAR/pair_granular.h +++ b/src/GRANULAR/pair_granular.h @@ -52,6 +52,7 @@ public: int neighprev; double *onerad_dynamic,*onerad_frozen; double *maxrad_dynamic,*maxrad_frozen; + double **cut; class FixNeighHistory *fix_history; @@ -64,24 +65,7 @@ public: virtual void allocate(); int beyond_contact; - - // comment next line to turn off templating -/*#define TEMPLATED_PAIR_GRANULAR -#ifdef TEMPLATED_PAIR_GRANULAR - template < int Tp_coeff_types, - int Tp_normal, int Tp_damping, int Tp_tangential, - int Tp_rolling, int Tp_twisting > - void compute_templated(int eflag, int vflag); -#else -*/ - void compute_untemplated( - int, - int, int, int, - int, int, - int, int); -//#endif - - private: +private: int coeff_types; int size_history; @@ -91,6 +75,7 @@ public: int normal_global, damping_global; int tangential_global, rolling_global, twisting_global; + int history_flag; int tangential_history, rolling_history, twisting_history; int tangential_history_index; int rolling_history_index; @@ -109,6 +94,7 @@ public: double mix_stiffnessE(double Eii, double Ejj, double Gii, double Gjj); double mix_stiffnessG(double Eii, double Ejj, double Gii, double Gjj); double mix_geom(double valii, double valjj); + double pulloff_distance(double radius, int itype); }; } From 7b4d0092b0d8694fddc9820f74a70ac3a5f77a36 Mon Sep 17 00:00:00 2001 From: dsbolin Date: Sat, 22 Dec 2018 14:33:09 -0700 Subject: [PATCH 09/44] Added type- and form-dependent conditionals in PairGranular::compute, still some issues with overall structure of the code. --- src/GRANULAR/pair_granular.cpp | 296 ++++++++++++++++++++------------- 1 file changed, 178 insertions(+), 118 deletions(-) diff --git a/src/GRANULAR/pair_granular.cpp b/src/GRANULAR/pair_granular.cpp index dd124671e0..ad7759c83a 100644 --- a/src/GRANULAR/pair_granular.cpp +++ b/src/GRANULAR/pair_granular.cpp @@ -97,9 +97,19 @@ PairGranular::~PairGranular() if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); - memory->destroy(cut); + memory->destroy(normal_coeffs); + memory->destroy(tangential_coeffs); + memory->destroy(rolling_coeffs); + memory->destroy(twisting_coeffs); + + memory->destroy(normal); + memory->destroy(damping); + memory->destroy(tangential); + memory->destroy(rolling); + memory->destroy(twisting); + delete [] onerad_dynamic; delete [] onerad_frozen; delete [] maxrad_dynamic; @@ -121,7 +131,7 @@ void PairGranular::compute(int eflag, int vflag) double damp_normal, damp_tangential; double kt; - double Fne, Fdamp, Fntot, Fscrit, Frcrit; + double Fne, Fdamp, Fntot, Fcrit, Fscrit, Frcrit; //For JKR double R2, coh, delta_pulloff, dist_pulloff, a, a2, E; @@ -273,9 +283,8 @@ void PairGranular::compute(int eflag, int vflag) if (mask[j] & freeze_group_bit) meff = mi; delta = radsum - r; - + dR = delta*Reff; if (normal[itype][jtype] == JKR){ - dR = delta*Reff; dR2 = dR*dR; t0 = coh*coh*R2*R2*E; t1 = PI27SQ*t0; @@ -297,8 +306,11 @@ void PairGranular::compute(int eflag, int vflag) a = sqdR = sqrt(dR); knfac = FOURTHIRDS*E*sqdR; Fne = knfac*delta; + if (normal[itype][jtype] == DMT) + Fne -= 4*MY_PI*normal_coeffs[itype][jtype][3]*Reff; } else{ //Hooke + a = sqdR = sqrt(dR); knfac = FOURTHIRDS*E; Fne = knfac*delta; } @@ -340,10 +352,29 @@ void PairGranular::compute(int eflag, int vflag) vrel = vtr1*vtr1 + vtr2*vtr2 + vtr3*vtr3; vrel = sqrt(vrel); - // history effects - if (tangential_history[itype][jtype]){ + // If any history is needed: + if (history_flag){ touch[jj] = 1; history = &allhistory[size_history*jj]; + Fcrit = fabs(Fne); + if (normal[itype][jtype] == JKR){ + Fpulloff = 3*M_PI*coh*Reff; + Fcrit = fabs(Fne + 2*Fpulloff); + } + } + + //------------------------------ + //Tangential forces + //------------------------------ + if (tangential[itype][jtype] == MINDLIN){ + k_tangential = tangential_coeffs[itype][jtype][0]*a; + } + else{ + k_tangential = tangential_coeffs[itype][jtype][0]; + } + damp_tangential = tangential_coeffs[itype][jtype][1]*damp_normal; + + if (tangential_history[itype][jtype]){ shrmag = sqrt(history[0]*history[0] + history[1]*history[1] + history[2]*history[2]); @@ -369,113 +400,138 @@ void PairGranular::compute(int eflag, int vflag) } // tangential forces = history + tangential velocity damping - if (normal[itype][jtype] == HOOKE) a = sqdR = sqrt(dR); - kt=tangential_coeffs[itype][jtype][0]*a; - - damp_tangential = tangential_coeffs[itype][jtype][1]*damp_normal; - fs1 = -kt*history[0] - damp_tangential*vtr1; - fs2 = -kt*history[1] - damp_tangential*vtr2; - fs3 = -kt*history[2] - damp_tangential*vtr3; + fs1 = -k_tangential*history[0] - damp_tangential*vtr1; + fs2 = -k_tangential*history[1] - damp_tangential*vtr2; + fs3 = -k_tangential*history[2] - damp_tangential*vtr3; // rescale frictional displacements and forces if needed - if (normal[itype][jtype] == JKR){ - double Fpulloff = -3*M_PI*coh*Reff; - Fscrit = tangential_coeffs[itype][jtype][2] * fabs(Fne + 2*Fpulloff); + Fscrit = tangential_coeffs[itype][jtype][2] * Fcrit; + fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); + if (fs > Fscrit) { + if (shrmag != 0.0) { + history[0] = -1.0/k_tangential*(Fscrit*fs1/fs + damp_tangential*vtr1); + history[1] = -1.0/k_tangential*(Fscrit*fs2/fs + damp_tangential*vtr2); + history[2] = -1.0/k_tangential*(Fscrit*fs3/fs + damp_tangential*vtr3); + fs1 *= Fscrit/fs; + fs2 *= Fscrit/fs; + fs3 *= Fscrit/fs; + } else fs1 = fs2 = fs3 = 0.0; } - else{ - Fscrit = tangential_coeffs[itype][jtype][2] * fabs(Fne); - } - // For JKR, use eq 43 of Marshall. For DMT, use Fne instead - - fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); - if (fs > Fscrit) { - if (shrmag != 0.0) { - history[0] = -1.0/kt*(Fscrit*fs1/fs + damp_tangential*vtr1); - history[1] = -1.0/kt*(Fscrit*fs2/fs + damp_tangential*vtr2); - history[2] = -1.0/kt*(Fscrit*fs3/fs + damp_tangential*vtr3); - fs1 *= Fscrit/fs; - fs2 *= Fscrit/fs; - fs3 *= Fscrit/fs; - } else fs1 = fs2 = fs3 = 0.0; + } + else{ //Classic pair gran/hooke (no history) + fs = meff*damp_tangential*vrel; + if (vrel != 0.0) ft = MIN(fn,fs) / vrel; + else ft = 0.0; + fs1 = -ft*vtr1; + fs2 = -ft*vtr2; + fs3 = -ft*vtr3; } //**************************************** - // Rolling force, including history history effects + // Rolling resistance //**************************************** - relrot1 = omega[i][0] - omega[j][0]; - relrot2 = omega[i][1] - omega[j][1]; - relrot3 = omega[i][2] - omega[j][2]; + if (rolling[itype][jtype] != NONE){ + relrot1 = omega[i][0] - omega[j][0]; + relrot2 = omega[i][1] - omega[j][1]; + relrot3 = omega[i][2] - omega[j][2]; - // rolling velocity, see eq. 31 of Wang et al, Particuology v 23, p 49 (2015) - // This is different from the Marshall papers, which use the Bagi/Kuhn formulation - // for rolling velocity (see Wang et al for why the latter is wrong) - vrl1 = R*(relrot2*nz - relrot3*ny); //- 0.5*((radj-radi)/radsum)*vtr1; - vrl2 = R*(relrot3*nx - relrot1*nz); //- 0.5*((radj-radi)/radsum)*vtr2; - vrl3 = R*(relrot1*ny - relrot2*nx); //- 0.5*((radj-radi)/radsum)*vtr3; - vrlmag = sqrt(vrl1*vrl1+vrl2*vrl2+vrl3*vrl3); - if (vrlmag != 0.0) vrlmaginv = 1.0/vrlmag; - else vrlmaginv = 0.0; + // rolling velocity, see eq. 31 of Wang et al, Particuology v 23, p 49 (2015) + // This is different from the Marshall papers, which use the Bagi/Kuhn formulation + // for rolling velocity (see Wang et al for why the latter is wrong) + vrl1 = R*(relrot2*nz - relrot3*ny); //- 0.5*((radj-radi)/radsum)*vtr1; + vrl2 = R*(relrot3*nx - relrot1*nz); //- 0.5*((radj-radi)/radsum)*vtr2; + vrl3 = R*(relrot1*ny - relrot2*nx); //- 0.5*((radj-radi)/radsum)*vtr3; + vrlmag = sqrt(vrl1*vrl1+vrl2*vrl2+vrl3*vrl3); + if (vrlmag != 0.0) vrlmaginv = 1.0/vrlmag; + else vrlmaginv = 0.0; - // Rolling displacement - rollmag = sqrt(history[3]*history[3] + history[4]*history[4] + history[5]*history[5]); - rolldotn = history[3]*nx + history[4]*ny + history[5]*nz; + if (rolling_history){ + // Rolling displacement + rollmag = sqrt(history[rhist0]*history[rhist0] + + history[rhist1]*history[rhist1] + + history[rhist2]*history[rhist2]); + rolldotn = history[rhist0]*nx + history[rhist1]*ny + history[rhist2]*nz; - if (historyupdate) { - if (fabs(rolldotn) < EPSILON) rolldotn = 0; - if (rolldotn > 0){ //Rotate into tangential plane - scalefac = rollmag/(rollmag - rolldotn); - history[3] -= rolldotn*nx; - history[4] -= rolldotn*ny; - history[5] -= rolldotn*nz; - //Also rescale to preserve magnitude - history[3] *= scalefac; - history[4] *= scalefac; - history[5] *= scalefac; + int rhist0 = rolling_history_index; + int rhist1 = rhist0 + 1; + int rhist2 = rhist1 + 1; + if (historyupdate) { + if (fabs(rolldotn) < EPSILON) rolldotn = 0; + if (rolldotn > 0){ //Rotate into tangential plane + scalefac = rollmag/(rollmag - rolldotn); + history[rhist0] -= rolldotn*nx; + history[rhist1] -= rolldotn*ny; + history[rhist2] -= rolldotn*nz; + //Also rescale to preserve magnitude + history[rhist0] *= scalefac; + history[rhist1] *= scalefac; + history[rhist2] *= scalefac; + } + history[rhist0] += vrl1*dt; + history[rhist1] += vrl2*dt; + history[rhist2] += vrl3*dt; + } + } + + kR = rolling_coeffs[itype][jtype][0]; + eta_R = rolling_coeffs[itype][jtype][1]; + fr1 = -kR*history[rhist0] - eta_R*vrl1; + fr2 = -kR*history[rhist1] - eta_R*vrl2; + fr3 = -kR*history[rhist2] - eta_R*vrl3; + + // rescale frictional displacements and forces if needed + Frcrit = rolling_coeffs[itype][jtype][2] * Fcrit; + + fr = sqrt(fr1*fr1 + fr2*fr2 + fr3*fr3); + if (fr > Frcrit) { + if (rollmag != 0.0) { + history[rhist0] = -1.0/k_R*(Frcrit*fr1/fr + eta_R*vrl1); + history[rhist1] = -1.0/k_R*(Frcrit*fr2/fr + eta_R*vrl2); + history[rhist2] = -1.0/k_R*(Frcrit*fr3/fr + eta_R*vrl3); + fr1 *= Frcrit/fr; + fr2 *= Frcrit/fr; + fr3 *= Frcrit/fr; + } else fr1 = fr2 = fr3 = 0.0; } - history[3] += vrl1*dt; - history[4] += vrl2*dt; - history[5] += vrl3*dt; } - - k_R = kR[itype][jtype]*4.0*F_C*pow(aovera0,1.5); - if (rollingdamp[itype][jtype] == INDEP) eta_R = etaR[itype][jtype]; - else if (rollingdamp[itype][jtype] == BRILLROLL) eta_R = muR[itype][jtype]*fabs(Fne); - fr1 = -k_R*history[3] - eta_R*vrl1; - fr2 = -k_R*history[4] - eta_R*vrl2; - fr3 = -k_R*history[5] - eta_R*vrl3; - - // rescale frictional displacements and forces if needed - Frcrit = muR[itype][jtype] * fabs(Fne + 2*F_C); - - fr = sqrt(fr1*fr1 + fr2*fr2 + fr3*fr3); - if (fr > Frcrit) { - if (rollmag != 0.0) { - history[3] = -1.0/k_R*(Frcrit*fr1/fr + eta_R*vrl1); - history[4] = -1.0/k_R*(Frcrit*fr2/fr + eta_R*vrl2); - history[5] = -1.0/k_R*(Frcrit*fr3/fr + eta_R*vrl3); - fr1 *= Frcrit/fr; - fr2 *= Frcrit/fr; - fr3 *= Frcrit/fr; - } else fr1 = fr2 = fr3 = 0.0; + else{ // + fr = meff*rolling_coeffs[itype][jtype][1]*vrlmag; + if (vrlmag != 0.0) fr = MIN(fn,fr) / vrlmag; + else fr = 0.0; + fr1 = -fr*vrl1; + fr2 = -fr*vrl2; + fr3 = -fr*vrl3; } - //**************************************** // Twisting torque, including history effects //**************************************** - magtwist = relrot1*nx + relrot2*ny + relrot3*nz; //Omega_T (eq 29 of Marshall) - history[6] += magtwist*dt; - k_Q = 0.5*kt*a*a;; //eq 32 - eta_Q = 0.5*eta_T*a*a; - magtortwist = -k_Q*history[6] - eta_Q*magtwist;//M_t torque (eq 30) - - signtwist = (magtwist > 0) - (magtwist < 0); - Mtcrit=TWOTHIRDS*a*Fscrit;//critical torque (eq 44) - if (fabs(magtortwist) > Mtcrit) { - //history[6] = Mtcrit/k_Q*magtwist/fabs(magtwist); - history[6] = 1.0/k_Q*(Mtcrit*signtwist - eta_Q*magtwist); - magtortwist = -Mtcrit * signtwist; //eq 34 + if (twist[itype][jtype] != NONE){ + magtwist = relrot1*nx + relrot2*ny + relrot3*nz; //Omega_T (eq 29 of Marshall) + if (twist[itype][jtype] == MARSHALL){ + k_twist = 0.5*k_tangential*a*a;; //eq 32 + damp_twist = 0.5*damp_tangential*a*a; + mu_twist = TWOTHIRDS*a; + } + else{ + k_twist = twisting_coeffs[itype][jtype][0]; + damp_twist = twisting_coeffs[itype][jtype][1]; + mu_twist = twisting_coeffs[itype][jtype][2]; + } + if (twist_history){ + history[twist_history_index] += magtwist*dt; + magtortwist = -k_twist*history[twist_history_index] - damp_twist*magtwist;//M_t torque (eq 30) + signtwist = (magtwist > 0) - (magtwist < 0); + Mtcrit = TWOTHIRDS*a*Fscrit;//critical torque (eq 44) + if (fabs(magtortwist) > Mtcrit) { + history[twist_history_index] = 1.0/k_twist*(Mtcrit*signtwist - damp_twist*magtwist); + magtortwist = -Mtcrit * signtwist; //eq 34 + } + } + else{ + if (magtwist > 0) magtortwist = -damp_twist*magtwist; + else magtortwist = 0; } // Apply forces & torques @@ -484,9 +540,6 @@ void PairGranular::compute(int eflag, int vflag) fy = ny*Fntot + fs2; fz = nz*Fntot + fs3; - //if (screen) fprintf(screen,"%16.16g %16.16g %16.16g %16.16g %16.16g %16.16g %16.16g \n",fs1,fs2,fs3,Fntot,nx,ny,nz); - //if (logfile) fprintf(logfile,"%16.16g %16.16g %16.16g %16.16g %16.16g %16.16g %16.16g \n",fs1,fs2,fs3,Fntot,nx,ny,nz); - f[i][0] += fx; f[i][1] += fy; f[i][2] += fz; @@ -499,21 +552,25 @@ void PairGranular::compute(int eflag, int vflag) torque[i][1] -= radi*tor2; torque[i][2] -= radi*tor3; - tortwist1 = magtortwist * nx; - tortwist2 = magtortwist * ny; - tortwist3 = magtortwist * nz; + if (twist[itype][jtype] != NONE){ + tortwist1 = magtortwist * nx; + tortwist2 = magtortwist * ny; + tortwist3 = magtortwist * nz; - torque[i][0] += tortwist1; - torque[i][1] += tortwist2; - torque[i][2] += tortwist3; + torque[i][0] += tortwist1; + torque[i][1] += tortwist2; + torque[i][2] += tortwist3; + } - torroll1 = R*(ny*fr3 - nz*fr2); //n cross fr - torroll2 = R*(nz*fr1 - nx*fr3); - torroll3 = R*(nx*fr2 - ny*fr1); + if (rolling[itype][jtype] != NONE){ + torroll1 = R*(ny*fr3 - nz*fr2); //n cross fr + torroll2 = R*(nz*fr1 - nx*fr3); + torroll3 = R*(nx*fr2 - ny*fr1); - torque[i][0] += torroll1; - torque[i][1] += torroll2; - torque[i][2] += torroll3; + torque[i][0] += torroll1; + torque[i][1] += torroll2; + torque[i][2] += torroll3; + } if (force->newton_pair || j < nlocal) { f[j][0] -= fx; @@ -524,13 +581,16 @@ void PairGranular::compute(int eflag, int vflag) torque[j][1] -= radj*tor2; torque[j][2] -= radj*tor3; - torque[j][0] -= tortwist1; - torque[j][1] -= tortwist2; - torque[j][2] -= tortwist3; - - torque[j][0] -= torroll1; - torque[j][1] -= torroll2; - torque[j][2] -= torroll3; + if (rolling[itype][jtype] != NONE){ + torque[j][0] -= tortwist1; + torque[j][1] -= tortwist2; + torque[j][2] -= tortwist3; + } + if (rolling[itype][jtype] != NONE){ + torque[j][0] -= torroll1; + torque[j][1] -= torroll2; + torque[j][2] -= torroll3; + } } if (evflag) ev_tally_xyz(i,j,nlocal,0, 0.0,0.0,fx,fy,fz,delx,dely,delz); @@ -562,6 +622,7 @@ void PairGranular::allocate() memory->create(twisting_coeffs,n+1,n+1,3,"pair:twisting_coeffs"); memory->create(normal,n+1,n+1,"pair:normal"); + memory->create(damping,n+1,n+1,"pair:damping"); memory->create(tangential,n+1,n+1,"pair:tangential"); memory->create(rolling,n+1,n+1,"pair:rolling"); memory->create(twisting,n+1,n+1,"pair:twisting"); @@ -1137,7 +1198,6 @@ double PairGranular::init_one(int i, int j) } cutoff = cutmax; } - return cutoff; } From dced4c1fca7f30876bc376363289d7ae7c5585c2 Mon Sep 17 00:00:00 2001 From: Dan Stefan Bolintineanu Date: Fri, 4 Jan 2019 17:03:31 -0700 Subject: [PATCH 10/44] More changes, fixed indentation issues --- src/GRANULAR/pair_granular.cpp | 550 +++++++++++++++++---------------- src/GRANULAR/pair_granular.h | 20 +- 2 files changed, 292 insertions(+), 278 deletions(-) diff --git a/src/GRANULAR/pair_granular.cpp b/src/GRANULAR/pair_granular.cpp index ad7759c83a..93f8d514b7 100644 --- a/src/GRANULAR/pair_granular.cpp +++ b/src/GRANULAR/pair_granular.cpp @@ -52,8 +52,8 @@ enum {STIFFNESS, MATERIAL}; enum {VELOCITY, VISCOELASTIC, TSUJI}; enum {HOOKE, HERTZ, DMT, JKR}; enum {TANGENTIAL_MINDLIN, TANGENTIAL_NOHISTORY}; -enum {NONE, TWISTING_NOHISTORY, TWISTING_SDS, TWISTING_MARSHALL}; -enum {NONE, ROLLING_NOHISTORY, ROLLING_SDS}; +enum {NONE, TWIST_NOHISTORY, TWIST_SDS, TWIST_MARSHALL}; +enum {NONE, ROLL_NOHISTORY, ROLL_SDS}; /* ---------------------------------------------------------------------- */ @@ -84,7 +84,7 @@ PairGranular::PairGranular(LAMMPS *lmp) : Pair(lmp) comm_forward = 1; beyond_contact = 0; - rolling_history_index = twisting_history_index = 0; + roll_history_index = twist_history_index = 0; tangential_history_index = -1; } @@ -101,14 +101,14 @@ PairGranular::~PairGranular() memory->destroy(normal_coeffs); memory->destroy(tangential_coeffs); - memory->destroy(rolling_coeffs); - memory->destroy(twisting_coeffs); + memory->destroy(roll_coeffs); + memory->destroy(twist_coeffs); memory->destroy(normal); memory->destroy(damping); memory->destroy(tangential); - memory->destroy(rolling); - memory->destroy(twisting); + memory->destroy(roll); + memory->destroy(twist); delete [] onerad_dynamic; delete [] onerad_frozen; @@ -123,18 +123,19 @@ void PairGranular::compute(int eflag, int vflag) int i,j,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,fx,fy,fz,nx,ny,nz; double radi,radj,radsum,rsq,r,rinv,rsqinv; - double Reff, delta, dR, dR2, sqdR, knfac; + double Reff, delta, dR, dR2, sqdR; double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3; double wr1,wr2,wr3; double vtr1,vtr2,vtr3,vrel; - double damp_normal, damp_tangential; - double kt; - double Fne, Fdamp, Fntot, Fcrit, Fscrit, Frcrit; + double knfac, damp_normal; + double k_tangential, damp_tangential; + double Fne, Ft, Fdamp, Fntot, Fcrit, Fscrit, Frcrit; + double fs, fs1, fs2, fs3; //For JKR - double R2, coh, delta_pulloff, dist_pulloff, a, a2, E; + double R2, coh, F_pulloff, delta_pulloff, dist_pulloff, a, a2, E; double delta, t0, t1, t2, t3, t4, t5, t6; double sqrt1, sqrt2, sqrt3, sqrt4; @@ -142,12 +143,14 @@ void PairGranular::compute(int eflag, int vflag) double relrot1,relrot2,relrot3,vrl1,vrl2,vrl3,vrlmag,vrlmaginv; //Rolling + double k_roll, damp_roll; + double roll1, roll2, roll3, torroll1, torroll2, torroll3; double rollmag, rolldotn, scalefac; double fr, fr1, fr2, fr3; //Twisting + double k_twist, damp_twist, mu_twist; double signtwist, magtwist, magtortwist, Mtcrit; - double fs,fs1,fs2,fs3,roll1,roll2,roll3,torroll1,torroll2,torroll3; double tortwist1, tortwist2, tortwist3; double shrmag,rsht; @@ -226,7 +229,6 @@ void PairGranular::compute(int eflag, int vflag) rsq = delx*delx + dely*dely + delz*delz; radj = radius[j]; radsum = radi + radj; - untouchflag = (rsq >= radsum*radsum); E = normal_coeffs[itype][jtype][0]; Reff = radi*radj/(radi+radj); @@ -236,7 +238,10 @@ void PairGranular::compute(int eflag, int vflag) a = cbrt(9.0*M_PI*coh*R2/(4*E)); delta_pulloff = a*a/Reff - 2*sqrt(M_PI*coh*a/E); dist_pulloff = radsum+delta_pulloff; - untouchflag = (rsq >= (dist_pulloff)*(dist_pulloff)); + untouchflag = (rsq >= dist_pulloff*dist_pulloff); + } + else{ + untouchflag = (rsq >= radsum*radsum); } if (untouchflag){ @@ -247,8 +252,6 @@ void PairGranular::compute(int eflag, int vflag) } else{ r = sqrt(rsq); - rinv = 1.0/r; - rsqinv = 1.0/rsq; nx = delx*rinv; ny = dely*rinv; @@ -301,26 +304,21 @@ void PairGranular::compute(int eflag, int vflag) knfac = FOURTHIRDS*E*a; Fne = knfac*a2/Reff - TWOPI*a2*sqrt(4*coh*E/(M_PI*a)); } - - else if (normal[itype][jtype] != HOOKE){ //HERTZ, DMT - a = sqdR = sqrt(dR); - knfac = FOURTHIRDS*E*sqdR; + else{ + knfac = E; //Hooke Fne = knfac*delta; + if (normal[itype][jtype] != HOOKE) + Fne *= a; if (normal[itype][jtype] == DMT) Fne -= 4*MY_PI*normal_coeffs[itype][jtype][3]*Reff; } - else{ //Hooke - a = sqdR = sqrt(dR); - knfac = FOURTHIRDS*E; - Fne = knfac*delta; - } //Consider restricting Hooke to only have 'velocity' as an option for damping? if (damping[itype][jtype] == VELOCITY){ damp_normal = normal_coeffs[itype][jtype][1]; } else if (damping[itype][jtype] == VISCOELASTIC){ - if (normal[itype][jtype] == HOOKE) sqdR = sqrt(dR); + if (normal[itype][jtype] == HOOKE) a = sqdR = sqrt(dR); damp_normal = normal_coeffs[itype][jtype][1]*sqdR*meff; } else if (damping[itype][jtype] == TSUJI){ @@ -356,21 +354,20 @@ void PairGranular::compute(int eflag, int vflag) if (history_flag){ touch[jj] = 1; history = &allhistory[size_history*jj]; - Fcrit = fabs(Fne); - if (normal[itype][jtype] == JKR){ - Fpulloff = 3*M_PI*coh*Reff; - Fcrit = fabs(Fne + 2*Fpulloff); - } + } + + Fcrit = fabs(Fne); + if (normal[itype][jtype] == JKR){ + F_pulloff = 3*M_PI*coh*Reff; + Fcrit = fabs(Fne + 2*F_pulloff); } //------------------------------ //Tangential forces //------------------------------ - if (tangential[itype][jtype] == MINDLIN){ - k_tangential = tangential_coeffs[itype][jtype][0]*a; - } - else{ - k_tangential = tangential_coeffs[itype][jtype][0]; + k_tangential = tangential_coeffs[itype][jtype][0]; + if (normal[itype][jtype] != HOOKE){ + k_tangential *= a; } damp_tangential = tangential_coeffs[itype][jtype][1]*damp_normal; @@ -420,18 +417,18 @@ void PairGranular::compute(int eflag, int vflag) } else{ //Classic pair gran/hooke (no history) fs = meff*damp_tangential*vrel; - if (vrel != 0.0) ft = MIN(fn,fs) / vrel; - else ft = 0.0; - fs1 = -ft*vtr1; - fs2 = -ft*vtr2; - fs3 = -ft*vtr3; + if (vrel != 0.0) Ft = MIN(Fne,fs) / vrel; + else Ft = 0.0; + fs1 = -Ft*vtr1; + fs2 = -Ft*vtr2; + fs3 = -Ft*vtr3; } //**************************************** // Rolling resistance //**************************************** - if (rolling[itype][jtype] != NONE){ + if (roll[itype][jtype] != NONE){ relrot1 = omega[i][0] - omega[j][0]; relrot2 = omega[i][1] - omega[j][1]; relrot3 = omega[i][2] - omega[j][2]; @@ -439,24 +436,26 @@ void PairGranular::compute(int eflag, int vflag) // rolling velocity, see eq. 31 of Wang et al, Particuology v 23, p 49 (2015) // This is different from the Marshall papers, which use the Bagi/Kuhn formulation // for rolling velocity (see Wang et al for why the latter is wrong) - vrl1 = R*(relrot2*nz - relrot3*ny); //- 0.5*((radj-radi)/radsum)*vtr1; - vrl2 = R*(relrot3*nx - relrot1*nz); //- 0.5*((radj-radi)/radsum)*vtr2; - vrl3 = R*(relrot1*ny - relrot2*nx); //- 0.5*((radj-radi)/radsum)*vtr3; + vrl1 = Reff*(relrot2*nz - relrot3*ny); //- 0.5*((radj-radi)/radsum)*vtr1; + vrl2 = Reff*(relrot3*nx - relrot1*nz); //- 0.5*((radj-radi)/radsum)*vtr2; + vrl3 = Reff*(relrot1*ny - relrot2*nx); //- 0.5*((radj-radi)/radsum)*vtr3; vrlmag = sqrt(vrl1*vrl1+vrl2*vrl2+vrl3*vrl3); if (vrlmag != 0.0) vrlmaginv = 1.0/vrlmag; else vrlmaginv = 0.0; - if (rolling_history){ + if (roll_history){ + int rhist0 = roll_history_index; + int rhist1 = rhist0 + 1; + int rhist2 = rhist1 + 1; + // Rolling displacement rollmag = sqrt(history[rhist0]*history[rhist0] + history[rhist1]*history[rhist1] + history[rhist2]*history[rhist2]); + rolldotn = history[rhist0]*nx + history[rhist1]*ny + history[rhist2]*nz; - int rhist0 = rolling_history_index; - int rhist1 = rhist0 + 1; - int rhist2 = rhist1 + 1; - if (historyupdate) { + if (historyupdate){ if (fabs(rolldotn) < EPSILON) rolldotn = 0; if (rolldotn > 0){ //Rotate into tangential plane scalefac = rollmag/(rollmag - rolldotn); @@ -472,68 +471,69 @@ void PairGranular::compute(int eflag, int vflag) history[rhist1] += vrl2*dt; history[rhist2] += vrl3*dt; } + + + k_roll = roll_coeffs[itype][jtype][0]; + damp_roll = roll_coeffs[itype][jtype][1]; + fr1 = -k_roll*history[rhist0] - damp_roll*vrl1; + fr2 = -k_roll*history[rhist1] - damp_roll*vrl2; + fr3 = -k_roll*history[rhist2] - damp_roll*vrl3; + + // rescale frictional displacements and forces if needed + Frcrit = roll_coeffs[itype][jtype][2] * Fcrit; + + fr = sqrt(fr1*fr1 + fr2*fr2 + fr3*fr3); + if (fr > Frcrit) { + if (rollmag != 0.0) { + history[rhist0] = -1.0/k_roll*(Frcrit*fr1/fr + damp_roll*vrl1); + history[rhist1] = -1.0/k_roll*(Frcrit*fr2/fr + damp_roll*vrl2); + history[rhist2] = -1.0/k_roll*(Frcrit*fr3/fr + damp_roll*vrl3); + fr1 *= Frcrit/fr; + fr2 *= Frcrit/fr; + fr3 *= Frcrit/fr; + } else fr1 = fr2 = fr3 = 0.0; + } } - - kR = rolling_coeffs[itype][jtype][0]; - eta_R = rolling_coeffs[itype][jtype][1]; - fr1 = -kR*history[rhist0] - eta_R*vrl1; - fr2 = -kR*history[rhist1] - eta_R*vrl2; - fr3 = -kR*history[rhist2] - eta_R*vrl3; - - // rescale frictional displacements and forces if needed - Frcrit = rolling_coeffs[itype][jtype][2] * Fcrit; - - fr = sqrt(fr1*fr1 + fr2*fr2 + fr3*fr3); - if (fr > Frcrit) { - if (rollmag != 0.0) { - history[rhist0] = -1.0/k_R*(Frcrit*fr1/fr + eta_R*vrl1); - history[rhist1] = -1.0/k_R*(Frcrit*fr2/fr + eta_R*vrl2); - history[rhist2] = -1.0/k_R*(Frcrit*fr3/fr + eta_R*vrl3); - fr1 *= Frcrit/fr; - fr2 *= Frcrit/fr; - fr3 *= Frcrit/fr; - } else fr1 = fr2 = fr3 = 0.0; + else{ // + fr = meff*roll_coeffs[itype][jtype][1]*vrlmag; + if (vrlmag != 0.0) fr = MIN(Fne, fr) / vrlmag; + else fr = 0.0; + fr1 = -fr*vrl1; + fr2 = -fr*vrl2; + fr3 = -fr*vrl3; } } - else{ // - fr = meff*rolling_coeffs[itype][jtype][1]*vrlmag; - if (vrlmag != 0.0) fr = MIN(fn,fr) / vrlmag; - else fr = 0.0; - fr1 = -fr*vrl1; - fr2 = -fr*vrl2; - fr3 = -fr*vrl3; - } //**************************************** // Twisting torque, including history effects //**************************************** if (twist[itype][jtype] != NONE){ magtwist = relrot1*nx + relrot2*ny + relrot3*nz; //Omega_T (eq 29 of Marshall) - if (twist[itype][jtype] == MARSHALL){ + if (twist[itype][jtype] == TWIST_MARSHALL){ k_twist = 0.5*k_tangential*a*a;; //eq 32 damp_twist = 0.5*damp_tangential*a*a; mu_twist = TWOTHIRDS*a; } else{ - k_twist = twisting_coeffs[itype][jtype][0]; - damp_twist = twisting_coeffs[itype][jtype][1]; - mu_twist = twisting_coeffs[itype][jtype][2]; + k_twist = twist_coeffs[itype][jtype][0]; + damp_twist = twist_coeffs[itype][jtype][1]; + mu_twist = twist_coeffs[itype][jtype][2]; } - if (twist_history){ - history[twist_history_index] += magtwist*dt; - magtortwist = -k_twist*history[twist_history_index] - damp_twist*magtwist;//M_t torque (eq 30) - signtwist = (magtwist > 0) - (magtwist < 0); - Mtcrit = TWOTHIRDS*a*Fscrit;//critical torque (eq 44) - if (fabs(magtortwist) > Mtcrit) { - history[twist_history_index] = 1.0/k_twist*(Mtcrit*signtwist - damp_twist*magtwist); - magtortwist = -Mtcrit * signtwist; //eq 34 + if (twist_history){ + history[twist_history_index] += magtwist*dt; + magtortwist = -k_twist*history[twist_history_index] - damp_twist*magtwist;//M_t torque (eq 30) + signtwist = (magtwist > 0) - (magtwist < 0); + Mtcrit = TWOTHIRDS*a*Fscrit;//critical torque (eq 44) + if (fabs(magtortwist) > Mtcrit) { + history[twist_history_index] = 1.0/k_twist*(Mtcrit*signtwist - damp_twist*magtwist); + magtortwist = -Mtcrit * signtwist; //eq 34 + } + } + else{ + if (magtwist > 0) magtortwist = -damp_twist*magtwist; + else magtortwist = 0; } } - else{ - if (magtwist > 0) magtortwist = -damp_twist*magtwist; - else magtortwist = 0; - } - // Apply forces & torques fx = nx*Fntot + fs1; @@ -562,10 +562,10 @@ void PairGranular::compute(int eflag, int vflag) torque[i][2] += tortwist3; } - if (rolling[itype][jtype] != NONE){ - torroll1 = R*(ny*fr3 - nz*fr2); //n cross fr - torroll2 = R*(nz*fr1 - nx*fr3); - torroll3 = R*(nx*fr2 - ny*fr1); + if (roll[itype][jtype] != NONE){ + torroll1 = Reff*(ny*fr3 - nz*fr2); //n cross fr + torroll2 = Reff*(nz*fr1 - nx*fr3); + torroll3 = Reff*(nx*fr2 - ny*fr1); torque[i][0] += torroll1; torque[i][1] += torroll2; @@ -581,12 +581,12 @@ void PairGranular::compute(int eflag, int vflag) torque[j][1] -= radj*tor2; torque[j][2] -= radj*tor3; - if (rolling[itype][jtype] != NONE){ + if (roll[itype][jtype] != NONE){ torque[j][0] -= tortwist1; torque[j][1] -= tortwist2; torque[j][2] -= tortwist3; } - if (rolling[itype][jtype] != NONE){ + if (roll[itype][jtype] != NONE){ torque[j][0] -= torroll1; torque[j][1] -= torroll2; torque[j][2] -= torroll3; @@ -618,14 +618,14 @@ void PairGranular::allocate() memory->create(cut,n+1,n+1,"pair:cut"); memory->create(normal_coeffs,n+1,n+1,4,"pair:normal_coeffs"); memory->create(tangential_coeffs,n+1,n+1,3,"pair:tangential_coeffs"); - memory->create(rolling_coeffs,n+1,n+1,3,"pair:rolling_coeffs"); - memory->create(twisting_coeffs,n+1,n+1,3,"pair:twisting_coeffs"); + memory->create(roll_coeffs,n+1,n+1,3,"pair:roll_coeffs"); + memory->create(twist_coeffs,n+1,n+1,3,"pair:twist_coeffs"); memory->create(normal,n+1,n+1,"pair:normal"); memory->create(damping,n+1,n+1,"pair:damping"); memory->create(tangential,n+1,n+1,"pair:tangential"); - memory->create(rolling,n+1,n+1,"pair:rolling"); - memory->create(twisting,n+1,n+1,"pair:twisting"); + memory->create(roll,n+1,n+1,"pair:roll"); + memory->create(twist,n+1,n+1,"pair:twist"); onerad_dynamic = new double[n+1]; onerad_frozen = new double[n+1]; @@ -647,9 +647,9 @@ void PairGranular::settings(int narg, char **arg) damping_global = VISCOELASTIC; coeff_types = STIFFNESS; tangential_global = -1; //Needs to be explicitly set, since it requires parameters - rolling_global = NONE; - twisting_global = NONE; - tangential_history = rolling_history = twisting_history = 0; + roll_global = NONE; + twist_global = NONE; + tangential_history = roll_history = twist_history = 0; if (strcmp(arg[iarg], "material") == 0){ coeff_types = MATERIAL; @@ -668,11 +668,11 @@ void PairGranular::settings(int narg, char **arg) else if (strcmp(arg[iarg], "hertz") == 0){ int num_coeffs = 2; if (coeff_types == MATERIAL) num_coeffs += 1; - if (iarg + offset >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for Hertz option"); + if (iarg + num_coeffs >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for Hertz option"); normal_global = HERTZ; memory->create(normal_coeffs_global, num_coeffs, "pair:normal_coeffs_global"); normal_coeffs_global[0] = force->numeric(FLERR,arg[iarg+1]); //kn or E - if (coeff_types == STIFFNESS) normal_coeffs_global[0] /= FOURTHIRDS; + if (coeff_types == MATERIAL) normal_coeffs_global[0] *= FOURTHIRDS; normal_coeffs_global[1] = force->numeric(FLERR,arg[iarg+2]); //damping if (coeff_types == MATERIAL) normal_coeffs_global[2] = force->numeric(FLERR,arg[iarg+3]); //G (if 'material') iarg += num_coeffs+1; @@ -682,7 +682,7 @@ void PairGranular::settings(int narg, char **arg) if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for Hertz option"); normal_global = DMT; memory->create(normal_coeffs_global, 4, "pair:normal_coeffs_global"); - normal_coeffs_global[0] = force->numeric(FLERR,arg[iarg+1]); //E + normal_coeffs_global[0] = force->numeric(FLERR,arg[iarg+1])*FOURTHIRDS; //4/3 E normal_coeffs_global[1] = force->numeric(FLERR,arg[iarg+2]); //damping normal_coeffs_global[2] = force->numeric(FLERR,arg[iarg+3]); //G normal_coeffs_global[3] = force->numeric(FLERR,arg[iarg+3]); //cohesion @@ -727,58 +727,63 @@ void PairGranular::settings(int narg, char **arg) tangential_coeffs_global[2] = force->numeric(FLERR,arg[iarg+3]); //friction coeff. iarg += 4; } - else if (strstr(arg[iarg], "rolling") != NULL){ + else if (strstr(arg[iarg], "roll") != NULL){ if (iarg + 3 >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for rolling model"); if (strstr(arg[iarg], "nohistory") != NULL){ - rolling_global = ROLLING_NOHISTORY; + roll_global = ROLL_NOHISTORY; } else{ - rolling_global = ROLLING_SDS; - rolling_history = 1; + roll_global = ROLL_SDS; + roll_history = 1; } - memory->create(rolling_coeffs_global, 3, "pair:rolling_coeffs_global"); - rolling_coeffs_global[0] = force->numeric(FLERR,arg[iarg+1]); //kt - rolling_coeffs_global[1] = force->numeric(FLERR,arg[iarg+2]); //gammat - rolling_coeffs_global[2] = force->numeric(FLERR,arg[iarg+3]); //friction coeff. + memory->create(roll_coeffs_global, 3, "pair:roll_coeffs_global"); + roll_coeffs_global[0] = force->numeric(FLERR,arg[iarg+1]); //kt + roll_coeffs_global[1] = force->numeric(FLERR,arg[iarg+2]); //gammat + roll_coeffs_global[2] = force->numeric(FLERR,arg[iarg+3]); //friction coeff. iarg += 4; } - else if (strstr(arg[iarg], "twisting") != NULL){ + else if (strstr(arg[iarg], "twist") != NULL){ if (strstr(arg[iarg], "marshall") != NULL){ - twisting_global = TWISTING_MARSHALL; - twisting_history = 1; - memory->create(twisting_coeffs_global, 3, "pair:twisting_coeffs_global"); //To be filled later + twist_global = TWIST_MARSHALL; + twist_history = 1; + memory->create(twist_coeffs_global, 3, "pair:twist_coeffs_global"); //To be filled later } else{ - if (iarg + 3 >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for twisting model"); + if (iarg + 3 >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for twist model"); if (strstr(arg[iarg], "nohistory") != NULL){ - twisting_global = TWISTING_NOHISTORY; + twist_global = TWIST_NOHISTORY; } else{ - twisting_global = TWISTING_SDS; - twisting_history = 1; + twist_global = TWIST_SDS; + twist_history = 1; } - memory->create(twisting_coeffs_global, 3, "pair:twisting_coeffs_global"); - twisting_coeffs_global[0] = force->numeric(FLERR,arg[iarg+1]); //kt - twisting_coeffs_global[1] = force->numeric(FLERR,arg[iarg+2]); //gammat - twisting_coeffs_global[2] = force->numeric(FLERR,arg[iarg+3]); //friction coeff. + memory->create(twist_coeffs_global, 3, "pair:twist_coeffs_global"); + twist_coeffs_global[0] = force->numeric(FLERR,arg[iarg+1]); //kt + twist_coeffs_global[1] = force->numeric(FLERR,arg[iarg+2]); //gammat + twist_coeffs_global[2] = force->numeric(FLERR,arg[iarg+3]); //friction coeff. iarg += 4; } } } - //Set all i-i entrie, which may be replaced by pair coeff commands + //Set all i-i entries, which may be replaced by pair coeff commands //It may also make sense to consider removing all of the above, and only // having the option for pair_coeff to set the parameters, similar to most LAMMPS pair styles - // The reason for the current setup is to keep true to existing pair gran/hooke etc. syntax, + // The reason for the current setup is to remain true to existing pair gran/hooke etc. syntax, // where coeffs are set in the pair_style command, and a pair_coeff * * command is issued. + + + //Other option is to have two pair styles, e.g. pair gran and pair gran/multi, + // where gran/multi allows per-type coefficients, pair gran does not (would also + // allow minor speed-up for pair gran) allocate(); double damp; for (int i = 1; i <= atom->ntypes; i++){ normal[i][i] = normal_global; damping[i][i] = damping_global; tangential[i][i] = tangential_global; - rolling[i][i] = rolling_global; - twisting[i][i] = twisting_global; + roll[i][i] = roll_global; + twist[i][i] = twist_global; if (damping_global == TSUJI){ double cor = normal_coeffs_global[1]; @@ -798,15 +803,15 @@ void PairGranular::settings(int narg, char **arg) for (int k = 0; k < 3; k++) tangential_coeffs[i][i][k] = tangential_coeffs_global[k]; - rolling[i][i] = rolling_global; - if (rolling_global != NONE) + roll[i][i] = roll_global; + if (roll_global != NONE) for (int k = 0; k < 3; k++) - rolling_coeffs[i][i][k] = rolling_coeffs_global[k]; + roll_coeffs[i][i][k] = roll_coeffs_global[k]; - twisting[i][i] = twisting_global; - if (twisting_global != NONE) + twist[i][i] = twist_global; + if (twist_global != NONE) for (int k = 0; k < 3; k++) - twisting_coeffs[i][i][k] = twisting_coeffs_local[k]; + twist_coeffs[i][i][k] = twist_coeffs_global[k]; setflag[i][i] = 1; } @@ -823,16 +828,16 @@ void PairGranular::settings(int narg, char **arg) void PairGranular::coeff(int narg, char **arg) { - int normal_local, damping_local, tangential_local, rolling_local, twisting_local; + int normal_local, damping_local, tangential_local, roll_local, twist_local; double *normal_coeffs_local; double *tangential_coeffs_local; - double *rolling_coeffs_local; - double *twisting_coeffs_local; + double *roll_coeffs_local; + double *twist_coeffs_local; normal_coeffs_local = new double[4]; tangential_coeffs_local = new double[4]; - rolling_coeffs_local = new double[4]; - twisting_coeffs_local = new double[4]; + roll_coeffs_local = new double[4]; + twist_coeffs_local = new double[4]; if (narg < 2) error->all(FLERR,"Incorrect args for pair coefficients"); @@ -914,35 +919,35 @@ void PairGranular::coeff(int narg, char **arg) else if (strstr(arg[iarg], "rolling") != NULL){ if (iarg + 3 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for rolling model"); if (strstr(arg[iarg], "nohistory") != NULL){ - rolling_local = ROLLING_NOHISTORY; + roll_local = ROLL_NOHISTORY; } else{ - rolling_local = ROLLING_SDS; - rolling_history = 1; + roll_local = ROLL_SDS; + roll_history = 1; } - rolling_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1]); //kt - rolling_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //gammat - rolling_coeffs_local[2] = force->numeric(FLERR,arg[iarg+3]); //friction coeff. + roll_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1]); //kt + roll_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //gammat + roll_coeffs_local[2] = force->numeric(FLERR,arg[iarg+3]); //friction coeff. iarg += 4; } - else if (strstr(arg[iarg], "twisting") != NULL){ + else if (strstr(arg[iarg], "twist") != NULL){ if (strstr(arg[iarg], "marshall") != NULL){ - twisting_local = TWISTING_MARSHALL; - twisting_history = 1; + twist_local = TWIST_MARSHALL; + twist_history = 1; } else{ - if (iarg + 3 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for twisting model"); + if (iarg + 3 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for twist model"); if (strstr(arg[iarg], "nohistory") != NULL){ - twisting_local = TWISTING_NOHISTORY; + twist_local = TWIST_NOHISTORY; } else{ - twisting_local = TWISTING_SDS; - twisting_history = 1; + twist_local = TWIST_SDS; + twist_history = 1; size_history += 1; } - twisting_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1]); //kt - twisting_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //gammat - twisting_coeffs_local[2] = force->numeric(FLERR,arg[iarg+3]); //friction coeff. + twist_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1]); //kt + twist_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //gammat + twist_coeffs_local[2] = force->numeric(FLERR,arg[iarg+3]); //friction coeff. iarg += 4; } } @@ -972,22 +977,27 @@ void PairGranular::coeff(int narg, char **arg) for (int k = 0; k < 3; k++) tangential_coeffs[i][j][k] = tangential_coeffs_local[k]; - rolling[i][j] = rolling_local; - if (rolling_local != NONE) + roll[i][j] = roll_local; + if (roll_local != NONE) for (int k = 0; k < 3; k++) - rolling_coeffs[i][j][k] = rolling_coeffs_local[k]; + roll_coeffs[i][j][k] = roll_coeffs_local[k]; - twisting[i][j] = twisting_local; - if (twisting_local != NONE) + twist[i][j] = twist_local; + if (twist_local != NONE) for (int k = 0; k < 3; k++) - twisting_coeffs[i][j][k] = twisting_coeffs_local[k]; + twist_coeffs[i][j][k] = twist_coeffs_local[k]; setflag[i][j] = 1; - double cut_one; count++; } } + + delete[] normal_coeffs_local; + delete[] tangential_coeffs_local; + delete[] roll_coeffs_local; + delete[] twist_coeffs_local; + if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); } @@ -1007,22 +1017,22 @@ void PairGranular::init_style() error->all(FLERR,"Pair granular requires ghost atoms store velocity"); // Determine whether we need a granular neigh list, how large it needs to be - history_flag = tangential_history || rolling_history || twisting_history; - size_history = 3*tangential_history + 3*rolling_history + twisting_history; + history_flag = tangential_history || roll_history || twist_history; + size_history = 3*tangential_history + 3*roll_history + twist_history; - //Determine location of tangential/rolling/twisting histories in array - if (rolling_history){ - if (tangential_history) rolling_history_index = 3; - else rolling_history_index = 0; + //Determine location of tangential/roll/twist histories in array + if (roll_history){ + if (tangential_history) roll_history_index = 3; + else roll_history_index = 0; } - if (twisting_history){ + if (twist_history){ if (tangential_history){ - if (rolling_history) twisting_history_index = 6; - else twisting_history_index = 3; + if (roll_history) twist_history_index = 6; + else twist_history_index = 3; } else{ - if (rolling_history) twisting_history_index = 3; - else twisting_history_index = 0; + if (roll_history) twist_history_index = 3; + else twist_history_index = 0; } } @@ -1137,8 +1147,8 @@ double PairGranular::init_one(int i, int j) if ((normal[i] != normal[j]) || (damping[i] != damping[j]) || (tangential[i] != tangential[j]) || - (rolling[i] != rolling[j]) || - (twisting[i] != twisting[j])){ + (roll[i] != roll[j]) || + (twist[i] != twist[j])){ char str[512]; sprintf(str,"Granular pair style functional forms are different, cannot mix coefficients for types %d and %d. \nThis combination must be set explicitly via pair_coeff command.",i,j); @@ -1165,14 +1175,14 @@ double PairGranular::init_one(int i, int j) tangential_coeffs[i][j][k] = mix_geom(tangential_coeffs[i][i][k], tangential_coeffs[j][j][k]); } - if (rolling[i][i] != NONE){ + if (roll[i][i] != NONE){ for (int k = 0; k < 3; k++) - rolling_coeffs[i][j][k] = mix_geom(rolling_coeffs[i][i][k], rolling_coeffs[j][j][k]); + roll_coeffs[i][j][k] = mix_geom(roll_coeffs[i][i][k], roll_coeffs[j][j][k]); } - if (twisting[i][i] != NONE){ + if (twist[i][i] != NONE){ for (int k = 0; k < 3; k++) - twisting_coeffs[i][j][k] = mix_geom(twisting_coeffs[i][i][k], twisting_coeffs[j][j][k]); + twist_coeffs[i][j][k] = mix_geom(twist_coeffs[i][i][k], twist_coeffs[j][j][k]); } } @@ -1208,24 +1218,20 @@ double PairGranular::init_one(int i, int j) void PairGranular::write_restart(FILE *fp) { - write_restart_settings(fp); - int i,j; for (i = 1; i <= atom->ntypes; i++) { for (j = i; j <= atom->ntypes; j++) { fwrite(&setflag[i][j],sizeof(int),1,fp); if (setflag[i][j]) { - fwrite(&E[i][j],sizeof(double),1,fp); - fwrite(&G[i][j],sizeof(double),1,fp); - fwrite(&normaldamp[i][j],sizeof(int),1,fp); - fwrite(&rollingdamp[i][j],sizeof(int),1,fp); - fwrite(&alpha[i][j],sizeof(double),1,fp); - fwrite(&gamman[i][j],sizeof(double),1,fp); - fwrite(&muS[i][j],sizeof(double),1,fp); - fwrite(&Ecoh[i][j],sizeof(double),1,fp); - fwrite(&kR[i][j],sizeof(double),1,fp); - fwrite(&muR[i][j],sizeof(double),1,fp); - fwrite(&etaR[i][j],sizeof(double),1,fp); + fwrite(&normal[i][j],sizeof(int),1,fp); + fwrite(&damping[i][j],sizeof(int),1,fp); + fwrite(&tangential[i][j],sizeof(int),1,fp); + fwrite(&roll[i][j],sizeof(int),1,fp); + fwrite(&twist[i][j],sizeof(int),1,fp); + fwrite(&normal_coeffs[i][j],sizeof(double),4,fp); + fwrite(&tangential_coeffs[i][j],sizeof(double),3,fp); + fwrite(&roll_coeffs[i][j],sizeof(double),3,fp); + fwrite(&twist_coeffs[i][j],sizeof(double),3,fp); fwrite(&cut[i][j],sizeof(double),1,fp); } } @@ -1238,9 +1244,7 @@ void PairGranular::write_restart(FILE *fp) void PairGranular::read_restart(FILE *fp) { - read_restart_settings(fp); allocate(); - int i,j; int me = comm->me; for (i = 1; i <= atom->ntypes; i++) { @@ -1249,56 +1253,32 @@ void PairGranular::read_restart(FILE *fp) MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world); if (setflag[i][j]) { if (me == 0) { - fread(&E[i][j],sizeof(double),1,fp); - fread(&G[i][j],sizeof(double),1,fp); - fread(&normaldamp[i][j],sizeof(int),1,fp); - fread(&rollingdamp[i][j],sizeof(int),1,fp); - fread(&alpha[i][j],sizeof(double),1,fp); - fread(&gamman[i][j],sizeof(double),1,fp); - fread(&muS[i][j],sizeof(double),1,fp); - fread(&Ecoh[i][j],sizeof(double),1,fp); - fread(&kR[i][j],sizeof(double),1,fp); - fread(&muR[i][j],sizeof(double),1,fp); - fread(&etaR[i][j],sizeof(double),1,fp); + fread(&normal[i][j],sizeof(int),1,fp); + fread(&damping[i][j],sizeof(int),1,fp); + fread(&tangential[i][j],sizeof(int),1,fp); + fread(&roll[i][j],sizeof(int),1,fp); + fread(&twist[i][j],sizeof(int),1,fp); + fread(&normal_coeffs[i][j],sizeof(double),4,fp); + fread(&tangential_coeffs[i][j],sizeof(double),3,fp); + fread(&roll_coeffs[i][j],sizeof(double),3,fp); + fread(&twist_coeffs[i][j],sizeof(double),3,fp); fread(&cut[i][j],sizeof(double),1,fp); } - MPI_Bcast(&E[i][j],1,MPI_DOUBLE,0,world); - MPI_Bcast(&G[i][j],1,MPI_DOUBLE,0,world); - MPI_Bcast(&normaldamp[i][j],1,MPI_INT,0,world); - MPI_Bcast(&rollingdamp[i][j],1,MPI_INT,0,world); - MPI_Bcast(&alpha[i][j],1,MPI_DOUBLE,0,world); - MPI_Bcast(&gamman[i][j],1,MPI_DOUBLE,0,world); - MPI_Bcast(&muS[i][j],1,MPI_DOUBLE,0,world); - MPI_Bcast(&Ecoh[i][j],1,MPI_DOUBLE,0,world); - MPI_Bcast(&kR[i][j],1,MPI_DOUBLE,0,world); - MPI_Bcast(&muR[i][j],1,MPI_DOUBLE,0,world); - MPI_Bcast(&etaR[i][j],1,MPI_DOUBLE,0,world); + MPI_Bcast(&normal[i][j],1,MPI_INT,0,world); + MPI_Bcast(&damping[i][j],1,MPI_INT,0,world); + MPI_Bcast(&tangential[i][j],1,MPI_INT,0,world); + MPI_Bcast(&roll[i][j],1,MPI_INT,0,world); + MPI_Bcast(&twist[i][j],1,MPI_INT,0,world); + MPI_Bcast(&normal_coeffs[i][j],4,MPI_DOUBLE,0,world); + MPI_Bcast(&tangential_coeffs[i][j],3,MPI_DOUBLE,0,world); + MPI_Bcast(&roll_coeffs[i][j],3,MPI_DOUBLE,0,world); + MPI_Bcast(&twist_coeffs[i][j],3,MPI_DOUBLE,0,world); MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); } } } } -/* ---------------------------------------------------------------------- - proc 0 writes to restart file - ------------------------------------------------------------------------- */ - -void PairGranular::write_restart_settings(FILE *fp) -{ - fwrite(&cut_global,sizeof(double),1,fp); -} - -/* ---------------------------------------------------------------------- - proc 0 reads from restart file, bcasts - ------------------------------------------------------------------------- */ - -void PairGranular::read_restart_settings(FILE *fp) -{ - if (comm->me == 0) { - fread(&cut_global,sizeof(double),1,fp); - } - MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world); -} /* ---------------------------------------------------------------------- */ @@ -1312,40 +1292,76 @@ void PairGranular::reset_dt() double PairGranular::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { - // feenableexcept(FE_INVALID | FE_OVERFLOW); double radi,radj,radsum; - double r,rinv,rsqinv,delx,dely,delz, nx, ny, nz, R; + double r,rinv,rsqinv,delx,dely,delz, nx, ny, nz, Reff; double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3,wr1,wr2,wr3; - double overlap, a; - double mi,mj,meff,damp,kn,kt; - double Fdamp,Fne,Fntot,Fscrit; - double eta_N,eta_T; double vtr1,vtr2,vtr3,vrel; - double fs1,fs2,fs3,fs; - double shrmag; - double F_C, delta_C, olapsq, olapcubed, sqrtterm, tmp, a0; - double keyterm, keyterm2, keyterm3, aovera0, foverFc; + + double knfac, damp_normal; + double k_tangential, damp_tangential; + double Fne, Ft, Fdamp, Fntot, Fcrit, Fscrit, Frcrit; + double fs, fs1, fs2, fs3; + + //For JKR + double R2, coh, F_pulloff, delta_pulloff, dist_pulloff, a, a2, E; + double delta, t0, t1, t2, t3, t4, t5, t6; + double sqrt1, sqrt2, sqrt3, sqrt4; + + double mi,mj,meff,damp,ccel,tor1,tor2,tor3; + double relrot1,relrot2,relrot3,vrl1,vrl2,vrl3,vrlmag,vrlmaginv; + + //Rolling + double k_roll, damp_roll; + double roll1, roll2, roll3, torroll1, torroll2, torroll3; + double rollmag, rolldotn, scalefac; + double fr, fr1, fr2, fr3; + + //Twisting + double k_twist, damp_twist, mu_twist; + double signtwist, magtwist, magtortwist, Mtcrit; + double tortwist1, tortwist2, tortwist3; + + double shrmag,rsht; + int *ilist,*jlist,*numneigh,**firstneigh; + int *touch,**firsttouch; + double *history,*allhistory,**firsthistory; double *radius = atom->radius; radi = radius[i]; radj = radius[j]; radsum = radi + radj; + Reff = radi*radj/(radi+radj); - r = sqrt(rsq); - rinv = 1.0/r; - rsqinv = 1.0/rsq; - R = radi*radj/(radi+radj); - a0 = pow(9.0*M_PI*Ecoh[itype][jtype]*R*R/E[itype][jtype],ONETHIRD); - delta_C = 0.5*a0*a0*POW6ONE/R; + bool untouchflag; + if (normal[itype][jtype] == JKR){ + R2 = Reff*Reff; + coh = normal_coeffs[itype][jtype][3]; + a = cbrt(9.0*M_PI*coh*R2/(4*E)); + delta_pulloff = a*a/Reff - 2*sqrt(M_PI*coh*a/E); + dist_pulloff = radsum+delta_pulloff; + untouchflag = (rsq >= dist_pulloff*dist_pulloff); + } + else{ + untouchflag = (rsq >= radsum*radsum); + } - int *touch = fix_history->firstflag[i]; - if ((rsq >= (radsum+delta_C)*(radsum+delta_C) )|| - (rsq >= radsum*radsum && touch[j])){ + if (untouchflag){ fforce = 0.0; - svector[0] = svector[1] = svector[2] = svector[3] = 0.0; + for (int m = 0; m < single_extra; m++) svector[m] = 0.0; return 0.0; } + double **x = atom->x; + delx = x[i][0] - x[j][0]; + dely = x[i][1] - x[j][1]; + delz = x[i][2] - x[j][2]; + r = sqrt(rsq); + rinv = 1.0/r; + + nx = delx*rinv; + ny = dely*rinv; + nz = delz*rinv; + // relative translational velocity double **v = atom->v; @@ -1574,11 +1590,11 @@ double PairGranular::mix_geom(double valii, double valjj) double PairGranular::pulloff_distance(double radius, int itype) { - double R, E, coh, a, delta_pulloff; + double E, coh, a, delta_pulloff; coh = normal_coeffs[itype][itype][3]; E = mix_stiffnessE(normal_coeffs[itype][itype][0], normal_coeffs[itype][itype][0], normal_coeffs[itype][itype][2], normal_coeffs[itype][itype][2]); - a = cbrt(9*M_PI*coh*R*R/(4*E)); - return a*a/R - 2*sqrt(M_PI*coh*a/E); + a = cbrt(9*M_PI*coh*radius*radius/(4*E)); + return a*a/radius - 2*sqrt(M_PI*coh*a/E); } diff --git a/src/GRANULAR/pair_granular.h b/src/GRANULAR/pair_granular.h index 14cc02675b..449b4d8474 100644 --- a/src/GRANULAR/pair_granular.h +++ b/src/GRANULAR/pair_granular.h @@ -35,8 +35,6 @@ public: double init_one(int, int); void write_restart(FILE *); void read_restart(FILE *); - void write_restart_settings(FILE *); - void read_restart_settings(FILE *); void reset_dt(); virtual double single(int, int, int, int, double, double, double, double &); int pack_forward_comm(int, int *, double *, int, int *); @@ -70,26 +68,26 @@ private: int size_history; //Per-type models - int **normal, **damping, **tangential, **rolling, **twisting; + int **normal, **damping, **tangential, **roll, **twist; int normal_global, damping_global; - int tangential_global, rolling_global, twisting_global; + int tangential_global, roll_global, twist_global; int history_flag; - int tangential_history, rolling_history, twisting_history; + int tangential_history, roll_history, twist_history; int tangential_history_index; - int rolling_history_index; - int twisting_history_index; + int roll_history_index; + int twist_history_index; double *normal_coeffs_global; double *tangential_coeffs_global; - double *rolling_coeffs_global; - double *twisting_coeffs_global; + double *roll_coeffs_global; + double *twist_coeffs_global; double ***normal_coeffs; double ***tangential_coeffs; - double ***rolling_coeffs; - double ***twisting_coeffs; + double ***roll_coeffs; + double ***twist_coeffs; double mix_stiffnessE(double Eii, double Ejj, double Gii, double Gjj); double mix_stiffnessG(double Eii, double Ejj, double Gii, double Gjj); From faa716e348d081e989189afc7888f94cf5f1835f Mon Sep 17 00:00:00 2001 From: Dan Stefan Bolintineanu Date: Mon, 7 Jan 2019 16:27:04 -0700 Subject: [PATCH 11/44] Added PairGranular::single method --- src/GRANULAR/pair_granular.cpp | 317 ++++++++++++++++++++++++--------- src/GRANULAR/pair_granular.h | 1 - 2 files changed, 231 insertions(+), 87 deletions(-) diff --git a/src/GRANULAR/pair_granular.cpp b/src/GRANULAR/pair_granular.cpp index 93f8d514b7..72b5f7867e 100644 --- a/src/GRANULAR/pair_granular.cpp +++ b/src/GRANULAR/pair_granular.cpp @@ -61,11 +61,10 @@ PairGranular::PairGranular(LAMMPS *lmp) : Pair(lmp) { single_enable = 1; no_virial_fdotr_compute = 1; - use_history = 1; fix_history = NULL; - single_extra = 10; - svector = new double[10]; + single_extra = 9; + svector = new double[single_extra]; neighprev = 0; @@ -83,6 +82,7 @@ PairGranular::PairGranular(LAMMPS *lmp) : Pair(lmp) comm_forward = 1; + use_history = 0; beyond_contact = 0; roll_history_index = twist_history_index = 0; tangential_history_index = -1; @@ -351,7 +351,7 @@ void PairGranular::compute(int eflag, int vflag) vrel = sqrt(vrel); // If any history is needed: - if (history_flag){ + if (use_history){ touch[jj] = 1; history = &allhistory[size_history*jj]; } @@ -520,7 +520,9 @@ void PairGranular::compute(int eflag, int vflag) mu_twist = twist_coeffs[itype][jtype][2]; } if (twist_history){ - history[twist_history_index] += magtwist*dt; + if (historyupdate){ + history[twist_history_index] += magtwist*dt; + } magtortwist = -k_twist*history[twist_history_index] - damp_twist*magtwist;//M_t torque (eq 30) signtwist = (magtwist > 0) - (magtwist < 0); Mtcrit = TWOTHIRDS*a*Fscrit;//critical torque (eq 44) @@ -1017,7 +1019,7 @@ void PairGranular::init_style() error->all(FLERR,"Pair granular requires ghost atoms store velocity"); // Determine whether we need a granular neigh list, how large it needs to be - history_flag = tangential_history || roll_history || twist_history; + use_history = tangential_history || roll_history || twist_history; size_history = 3*tangential_history + 3*roll_history + twist_history; //Determine location of tangential/roll/twist histories in array @@ -1038,14 +1040,14 @@ void PairGranular::init_style() int irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->size = 1; - if (history_flag) neighbor->requests[irequest]->history = 1; + if (use_history) neighbor->requests[irequest]->history = 1; dt = update->dt; // if history is stored: // if first init, create Fix needed for storing history - if (history_flag && fix_history == NULL) { + if (use_history && fix_history == NULL) { char dnumstr[16]; sprintf(dnumstr,"%d",size_history); char **fixarg = new char*[4]; @@ -1294,8 +1296,11 @@ double PairGranular::single(int i, int j, int itype, int jtype, { double radi,radj,radsum; double r,rinv,rsqinv,delx,dely,delz, nx, ny, nz, Reff; + double dR, dR2, sqdR; double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3,wr1,wr2,wr3; double vtr1,vtr2,vtr3,vrel; + double mi,mj,meff,damp,ccel,tor1,tor2,tor3; + double relrot1,relrot2,relrot3,vrl1,vrl2,vrl3,vrlmag,vrlmaginv; double knfac, damp_normal; double k_tangential, damp_tangential; @@ -1307,8 +1312,6 @@ double PairGranular::single(int i, int j, int itype, int jtype, double delta, t0, t1, t2, t3, t4, t5, t6; double sqrt1, sqrt2, sqrt3, sqrt4; - double mi,mj,meff,damp,ccel,tor1,tor2,tor3; - double relrot1,relrot2,relrot3,vrl1,vrl2,vrl3,vrlmag,vrlmaginv; //Rolling double k_roll, damp_roll; @@ -1371,21 +1374,27 @@ double PairGranular::single(int i, int j, int itype, int jtype, // normal component - double **x = atom->x; - delx = x[i][0] - x[j][0]; - dely = x[i][1] - x[j][1]; - delz = x[i][2] - x[j][2]; - - nx = delx*rinv; - ny = dely*rinv; - nz = delz*rinv; - - vnnr = vr1*nx + vr2*ny + vr3*nz; vn1 = nx*vnnr; vn2 = ny*vnnr; vn3 = nz*vnnr; + double *rmass = atom->rmass; + int *mask = atom->mask; + mi = rmass[i]; + mj = rmass[j]; + if (fix_rigid) { + if (mass_rigid[i] > 0.0) mi = mass_rigid[i]; + if (mass_rigid[j] > 0.0) mj = mass_rigid[j]; + } + + meff = mi*mj / (mi+mj); + if (mask[i] & freeze_group_bit) meff = mj; + if (mask[j] & freeze_group_bit) meff = mi; + + delta = radsum - r; + dR = delta*Reff; + // tangential component vt1 = vr1 - vn1; @@ -1419,86 +1428,223 @@ double PairGranular::single(int i, int j, int itype, int jtype, if (mask[i] & freeze_group_bit) meff = mj; if (mask[j] & freeze_group_bit) meff = mi; + delta = radsum - r; + dR = delta*Reff; + if (normal[itype][jtype] == JKR){ + dR2 = dR*dR; + t0 = coh*coh*R2*R2*E; + t1 = PI27SQ*t0; + t2 = 8*dR*dR2*E*E*E; + t3 = 4*dR2*E; + sqrt1 = MAX(0, t0*(t1+2*t2)); //In case of sqrt(0) < 0 due to precision issues + t4 = cbrt(t1+t2+THREEROOT3*M_PI*sqrt(sqrt1)); + t5 = t3/t4 + t4/E; + sqrt2 = MAX(0, 2*dR + t5); + t6 = sqrt(sqrt2); + sqrt3 = MAX(0, 4*dR - t5 + SIXROOT6*coh*M_PI*R2/(E*t6)); + a = INVROOT6*(t6 + sqrt(sqrt3)); + a2 = a*a; + knfac = FOURTHIRDS*E*a; + Fne = knfac*a2/Reff - TWOPI*a2*sqrt(4*coh*E/(M_PI*a)); + } + else{ + knfac = E; //Hooke + Fne = knfac*delta; + if (normal[itype][jtype] != HOOKE) + Fne *= a; + if (normal[itype][jtype] == DMT) + Fne -= 4*MY_PI*normal_coeffs[itype][jtype][3]*Reff; + } - // normal force = JKR - F_C = 3.0*R*M_PI*Ecoh[itype][jtype]; - overlap = radsum - r; - olapsq = overlap*overlap; - olapcubed = olapsq*olapsq; - sqrtterm = sqrt(1.0 + olapcubed); - tmp = 2.0 + olapcubed + 2.0*sqrtterm; - keyterm = pow(tmp,ONETHIRD); - keyterm2 = olapsq/keyterm; - keyterm3 = sqrt(overlap + keyterm2 + keyterm); - aovera0 = POW6TWO * (keyterm3 + - sqrt(2.0*overlap - keyterm2 - keyterm + 4.0/keyterm3));// eq 41 - a = aovera0*a0; - foverFc = 4.0*((aovera0*aovera0*aovera0) - pow(aovera0,1.5));//F_ne/F_C (eq 40) + //Consider restricting Hooke to only have 'velocity' as an option for damping? + if (damping[itype][jtype] == VELOCITY){ + damp_normal = normal_coeffs[itype][jtype][1]; + } + else if (damping[itype][jtype] == VISCOELASTIC){ + if (normal[itype][jtype] == HOOKE) a = sqdR = sqrt(dR); + damp_normal = normal_coeffs[itype][jtype][1]*sqdR*meff; + } + else if (damping[itype][jtype] == TSUJI){ + damp_normal = normal_coeffs[itype][jtype][1]*sqrt(meff*knfac); + } - Fne = F_C*foverFc; - - //Damping - kn = 4.0/3.0*E[itype][jtype]*a; - if (normaldamp[itype][jtype] == BRILLIANTOV) eta_N = a*meff*gamman[itype][jtype]; - else if (normaldamp[itype][jtype] == TSUJI) eta_N=alpha[itype][jtype]*sqrt(meff*kn); - - Fdamp = -eta_N*vnnr; //F_nd eq 23 and Zhao eq 19 + Fdamp = -damp_normal*vnnr; Fntot = Fne + Fdamp; - // relative velocities + int jnum = list->numneigh[i]; + int *jlist = list->firstneigh[i]; + double *allhistory, *history; + if (use_history){ + allhistory = fix_history->firstvalue[i]; + for (int jj = 0; jj < jnum; jj++) { + neighprev++; + if (neighprev >= jnum) neighprev = 0; + if (jlist[neighprev] == j) break; + } + history = &allhistory[size_history*neighprev]; + } + + //**************************************** + //Tangential force, including history effects + //**************************************** + + // tangential component + vt1 = vr1 - vn1; + vt2 = vr2 - vn2; + vt3 = vr3 - vn3; + + // relative rotational velocity + wr1 = (radi*omega[i][0] + radj*omega[j][0]); + wr2 = (radi*omega[i][1] + radj*omega[j][1]); + wr3 = (radi*omega[i][2] + radj*omega[j][2]); + + // relative tangential velocities vtr1 = vt1 - (nz*wr2-ny*wr3); vtr2 = vt2 - (nx*wr3-nz*wr1); vtr3 = vt3 - (ny*wr1-nx*wr2); vrel = vtr1*vtr1 + vtr2*vtr2 + vtr3*vtr3; vrel = sqrt(vrel); - // history effects - // neighprev = index of found neigh on previous call - // search entire jnum list of neighbors of I for neighbor J - // start from neighprev, since will typically be next neighbor - // reset neighprev to 0 as necessary - - int jnum = list->numneigh[i]; - int *jlist = list->firstneigh[i]; - double *allhistory = fix_history->firstvalue[i]; - - for (int jj = 0; jj < jnum; jj++) { - neighprev++; - if (neighprev >= jnum) neighprev = 0; - if (jlist[neighprev] == j) break; + Fcrit = fabs(Fne); + if (normal[itype][jtype] == JKR){ + F_pulloff = 3*M_PI*coh*Reff; + Fcrit = fabs(Fne + 2*F_pulloff); } - double *history = &allhistory[3*neighprev]; - shrmag = sqrt(history[0]*history[0] + history[1]*history[1] + - history[2]*history[2]); + //------------------------------ + //Tangential forces + //------------------------------ + k_tangential = tangential_coeffs[itype][jtype][0]; + if (normal[itype][jtype] != HOOKE){ + k_tangential *= a; + } + damp_tangential = tangential_coeffs[itype][jtype][1]*damp_normal; - // tangential forces = history + tangential velocity damping - kt=8.0*G[itype][jtype]*a; + if (tangential_history[itype][jtype]){ + shrmag = sqrt(history[0]*history[0] + history[1]*history[1] + + history[2]*history[2]); - eta_T = eta_N; - fs1 = -kt*history[0] - eta_T*vtr1; - fs2 = -kt*history[1] - eta_T*vtr2; - fs3 = -kt*history[2] - eta_T*vtr3; + // tangential forces = history + tangential velocity damping + fs1 = -k_tangential*history[0] - damp_tangential*vtr1; + fs2 = -k_tangential*history[1] - damp_tangential*vtr2; + fs3 = -k_tangential*history[2] - damp_tangential*vtr3; - // rescale frictional displacements and forces if needed - - fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); - Fscrit= muS[itype][jtype] * fabs(Fne + 2*F_C); - - if (fs > Fscrit) { - if (shrmag != 0.0) { - fs1 *= Fscrit/fs; - fs2 *= Fscrit/fs; - fs3 *= Fscrit/fs; - fs *= Fscrit/fs; - } else fs1 = fs2 = fs3 = fs = 0.0; + // rescale frictional displacements and forces if needed + Fscrit = tangential_coeffs[itype][jtype][2] * Fcrit; + fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); + if (fs > Fscrit) { + if (shrmag != 0.0) { + history[0] = -1.0/k_tangential*(Fscrit*fs1/fs + damp_tangential*vtr1); + history[1] = -1.0/k_tangential*(Fscrit*fs2/fs + damp_tangential*vtr2); + history[2] = -1.0/k_tangential*(Fscrit*fs3/fs + damp_tangential*vtr3); + fs1 *= Fscrit/fs; + fs2 *= Fscrit/fs; + fs3 *= Fscrit/fs; + } else fs1 = fs2 = fs3 = 0.0; + } + } + else{ //Classic pair gran/hooke (no history) + fs = meff*damp_tangential*vrel; + if (vrel != 0.0) Ft = MIN(Fne,fs) / vrel; + else Ft = 0.0; + fs1 = -Ft*vtr1; + fs2 = -Ft*vtr2; + fs3 = -Ft*vtr3; } - // set all forces and return no energy + //**************************************** + // Rolling resistance + //**************************************** - fforce = Fntot; + if (roll[itype][jtype] != NONE){ + relrot1 = omega[i][0] - omega[j][0]; + relrot2 = omega[i][1] - omega[j][1]; + relrot3 = omega[i][2] - omega[j][2]; + + // rolling velocity, see eq. 31 of Wang et al, Particuology v 23, p 49 (2015) + // This is different from the Marshall papers, which use the Bagi/Kuhn formulation + // for rolling velocity (see Wang et al for why the latter is wrong) + vrl1 = Reff*(relrot2*nz - relrot3*ny); //- 0.5*((radj-radi)/radsum)*vtr1; + vrl2 = Reff*(relrot3*nx - relrot1*nz); //- 0.5*((radj-radi)/radsum)*vtr2; + vrl3 = Reff*(relrot1*ny - relrot2*nx); //- 0.5*((radj-radi)/radsum)*vtr3; + vrlmag = sqrt(vrl1*vrl1+vrl2*vrl2+vrl3*vrl3); + if (vrlmag != 0.0) vrlmaginv = 1.0/vrlmag; + else vrlmaginv = 0.0; + + if (roll_history){ + int rhist0 = roll_history_index; + int rhist1 = rhist0 + 1; + int rhist2 = rhist1 + 1; + + // Rolling displacement + rollmag = sqrt(history[rhist0]*history[rhist0] + + history[rhist1]*history[rhist1] + + history[rhist2]*history[rhist2]); + + rolldotn = history[rhist0]*nx + history[rhist1]*ny + history[rhist2]*nz; + + k_roll = roll_coeffs[itype][jtype][0]; + damp_roll = roll_coeffs[itype][jtype][1]; + fr1 = -k_roll*history[rhist0] - damp_roll*vrl1; + fr2 = -k_roll*history[rhist1] - damp_roll*vrl2; + fr3 = -k_roll*history[rhist2] - damp_roll*vrl3; + + // rescale frictional displacements and forces if needed + Frcrit = roll_coeffs[itype][jtype][2] * Fcrit; + + fr = sqrt(fr1*fr1 + fr2*fr2 + fr3*fr3); + if (fr > Frcrit) { + if (rollmag != 0.0) { + history[rhist0] = -1.0/k_roll*(Frcrit*fr1/fr + damp_roll*vrl1); + history[rhist1] = -1.0/k_roll*(Frcrit*fr2/fr + damp_roll*vrl2); + history[rhist2] = -1.0/k_roll*(Frcrit*fr3/fr + damp_roll*vrl3); + fr1 *= Frcrit/fr; + fr2 *= Frcrit/fr; + fr3 *= Frcrit/fr; + } else fr1 = fr2 = fr3 = 0.0; + } + } + else{ // + fr = meff*roll_coeffs[itype][jtype][1]*vrlmag; + if (vrlmag != 0.0) fr = MIN(Fne, fr) / vrlmag; + else fr = 0.0; + fr1 = -fr*vrl1; + fr2 = -fr*vrl2; + fr3 = -fr*vrl3; + } + } + + //**************************************** + // Twisting torque, including history effects + //**************************************** + if (twist[itype][jtype] != NONE){ + magtwist = relrot1*nx + relrot2*ny + relrot3*nz; //Omega_T (eq 29 of Marshall) + if (twist[itype][jtype] == TWIST_MARSHALL){ + k_twist = 0.5*k_tangential*a*a;; //eq 32 + damp_twist = 0.5*damp_tangential*a*a; + mu_twist = TWOTHIRDS*a; + } + else{ + k_twist = twist_coeffs[itype][jtype][0]; + damp_twist = twist_coeffs[itype][jtype][1]; + mu_twist = twist_coeffs[itype][jtype][2]; + } + if (twist_history){ + magtortwist = -k_twist*history[twist_history_index] - damp_twist*magtwist;//M_t torque (eq 30) + signtwist = (magtwist > 0) - (magtwist < 0); + Mtcrit = TWOTHIRDS*a*Fscrit;//critical torque (eq 44) + if (fabs(magtortwist) > Mtcrit) { + history[twist_history_index] = 1.0/k_twist*(Mtcrit*signtwist - damp_twist*magtwist); + magtortwist = -Mtcrit * signtwist; //eq 34 + } + } + else{ + if (magtwist > 0) magtortwist = -damp_twist*magtwist; + else magtortwist = 0; + } + } // set single_extra quantities @@ -1506,12 +1652,11 @@ double PairGranular::single(int i, int j, int itype, int jtype, svector[1] = fs2; svector[2] = fs3; svector[3] = fs; - svector[4] = vn1; - svector[5] = vn2; - svector[6] = vn3; - svector[7] = vt1; - svector[8] = vt2; - svector[9] = vt3; + svector[4] = fr1; + svector[5] = fr2; + svector[6] = fr3; + svector[7] = fr; + svector[8] = magtortwist; return 0.0; } diff --git a/src/GRANULAR/pair_granular.h b/src/GRANULAR/pair_granular.h index 449b4d8474..957a16af8d 100644 --- a/src/GRANULAR/pair_granular.h +++ b/src/GRANULAR/pair_granular.h @@ -73,7 +73,6 @@ private: int normal_global, damping_global; int tangential_global, roll_global, twist_global; - int history_flag; int tangential_history, roll_history, twist_history; int tangential_history_index; int roll_history_index; From 18f8f68e67502fd7bc9edeccf24bc1145c199662 Mon Sep 17 00:00:00 2001 From: Dan Stefan Bolintineanu Date: Tue, 8 Jan 2019 16:33:24 -0700 Subject: [PATCH 12/44] Fixed several input parsing issues in pair granular; fixed issue with JKR hysteresis and damping with JKR --- src/GRANULAR/pair_gran_hertz_history.cpp | 2 +- src/GRANULAR/pair_gran_hooke_history.cpp | 5 + src/GRANULAR/pair_granular.cpp | 464 ++++++++++++++--------- src/GRANULAR/pair_granular.h | 2 +- 4 files changed, 282 insertions(+), 191 deletions(-) diff --git a/src/GRANULAR/pair_gran_hertz_history.cpp b/src/GRANULAR/pair_gran_hertz_history.cpp index c96d48de69..d1f3c7bbe1 100644 --- a/src/GRANULAR/pair_gran_hertz_history.cpp +++ b/src/GRANULAR/pair_gran_hertz_history.cpp @@ -36,7 +36,7 @@ using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ PairGranHertzHistory::PairGranHertzHistory(LAMMPS *lmp) : - PairGranHookeHistory(lmp, 3) {} + PairGranHookeHistory(lmp) {} /* ---------------------------------------------------------------------- */ diff --git a/src/GRANULAR/pair_gran_hooke_history.cpp b/src/GRANULAR/pair_gran_hooke_history.cpp index cf30e77ccb..04df3b3d9b 100644 --- a/src/GRANULAR/pair_gran_hooke_history.cpp +++ b/src/GRANULAR/pair_gran_hooke_history.cpp @@ -44,6 +44,7 @@ PairGranHookeHistory::PairGranHookeHistory(LAMMPS *lmp) : Pair(lmp) single_enable = 1; no_virial_fdotr_compute = 1; history = 1; + size_history = 3; fix_history = NULL; single_extra = 10; @@ -348,6 +349,10 @@ void PairGranHookeHistory::settings(int narg, char **arg) { if (narg != 6) error->all(FLERR,"Illegal pair_style command"); + + + + kn = force->numeric(FLERR,arg[0]); if (strcmp(arg[1],"NULL") == 0) kt = kn * 2.0/7.0; else kt = force->numeric(FLERR,arg[1]); diff --git a/src/GRANULAR/pair_granular.cpp b/src/GRANULAR/pair_granular.cpp index 72b5f7867e..9ee78686c6 100644 --- a/src/GRANULAR/pair_granular.cpp +++ b/src/GRANULAR/pair_granular.cpp @@ -48,12 +48,11 @@ using namespace MathConst; #define EPSILON 1e-10 -enum {STIFFNESS, MATERIAL}; enum {VELOCITY, VISCOELASTIC, TSUJI}; -enum {HOOKE, HERTZ, DMT, JKR}; +enum {HOOKE, HERTZ, HERTZ_MATERIAL, DMT, JKR}; enum {TANGENTIAL_MINDLIN, TANGENTIAL_NOHISTORY}; -enum {NONE, TWIST_NOHISTORY, TWIST_SDS, TWIST_MARSHALL}; -enum {NONE, ROLL_NOHISTORY, ROLL_SDS}; +enum {TWIST_NONE, TWIST_NOHISTORY, TWIST_SDS, TWIST_MARSHALL}; +enum {ROLL_NONE, ROLL_NOHISTORY, ROLL_SDS}; /* ---------------------------------------------------------------------- */ @@ -84,8 +83,10 @@ PairGranular::PairGranular(LAMMPS *lmp) : Pair(lmp) use_history = 0; beyond_contact = 0; + nondefault_history_transfer = 0; + tangential_history_index = 0; roll_history_index = twist_history_index = 0; - tangential_history_index = -1; + } /* ---------------------------------------------------------------------- */ @@ -136,7 +137,7 @@ void PairGranular::compute(int eflag, int vflag) //For JKR double R2, coh, F_pulloff, delta_pulloff, dist_pulloff, a, a2, E; - double delta, t0, t1, t2, t3, t4, t5, t6; + double t0, t1, t2, t3, t4, t5, t6; double sqrt1, sqrt2, sqrt3, sqrt4; double mi,mj,meff,damp,ccel,tor1,tor2,tor3; @@ -158,7 +159,7 @@ void PairGranular::compute(int eflag, int vflag) int *touch,**firsttouch; double *history,*allhistory,**firsthistory; - bool untouchflag; + bool touchflag; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; @@ -232,19 +233,26 @@ void PairGranular::compute(int eflag, int vflag) E = normal_coeffs[itype][jtype][0]; Reff = radi*radj/(radi+radj); + touchflag = false; + if (normal[itype][jtype] == JKR){ - R2 = Reff*Reff; - coh = normal_coeffs[itype][jtype][3]; - a = cbrt(9.0*M_PI*coh*R2/(4*E)); - delta_pulloff = a*a/Reff - 2*sqrt(M_PI*coh*a/E); - dist_pulloff = radsum+delta_pulloff; - untouchflag = (rsq >= dist_pulloff*dist_pulloff); + if (touch[jj]){ + R2 = Reff*Reff; + coh = normal_coeffs[itype][jtype][3]; + a = cbrt(9.0*M_PI*coh*R2/(4*E)); + delta_pulloff = a*a/Reff - 2*sqrt(M_PI*coh*a/E); + dist_pulloff = radsum-delta_pulloff; + touchflag = (rsq <= dist_pulloff*dist_pulloff); + } + else{ + touchflag = (rsq <= radsum*radsum); + } } else{ - untouchflag = (rsq >= radsum*radsum); + touchflag = (rsq <= radsum*radsum); } - if (untouchflag){ + if (!touchflag){ // unset non-touching neighbors touch[jj] = 0; history = &allhistory[size_history*jj]; @@ -252,6 +260,7 @@ void PairGranular::compute(int eflag, int vflag) } else{ r = sqrt(rsq); + rinv = 1.0/r; nx = delx*rinv; ny = dely*rinv; @@ -288,6 +297,7 @@ void PairGranular::compute(int eflag, int vflag) delta = radsum - r; dR = delta*Reff; if (normal[itype][jtype] == JKR){ + touch[jj] = 1; dR2 = dR*dR; t0 = coh*coh*R2*R2*E; t1 = PI27SQ*t0; @@ -308,6 +318,7 @@ void PairGranular::compute(int eflag, int vflag) knfac = E; //Hooke Fne = knfac*delta; if (normal[itype][jtype] != HOOKE) + a = sqdR = sqrt(dR); Fne *= a; if (normal[itype][jtype] == DMT) Fne -= 4*MY_PI*normal_coeffs[itype][jtype][3]*Reff; @@ -366,12 +377,9 @@ void PairGranular::compute(int eflag, int vflag) //Tangential forces //------------------------------ k_tangential = tangential_coeffs[itype][jtype][0]; - if (normal[itype][jtype] != HOOKE){ - k_tangential *= a; - } damp_tangential = tangential_coeffs[itype][jtype][1]*damp_normal; - if (tangential_history[itype][jtype]){ + if (tangential_history){ shrmag = sqrt(history[0]*history[0] + history[1]*history[1] + history[2]*history[2]); @@ -428,7 +436,7 @@ void PairGranular::compute(int eflag, int vflag) // Rolling resistance //**************************************** - if (roll[itype][jtype] != NONE){ + if (roll[itype][jtype] != ROLL_NONE){ relrot1 = omega[i][0] - omega[j][0]; relrot2 = omega[i][1] - omega[j][1]; relrot3 = omega[i][2] - omega[j][2]; @@ -507,7 +515,7 @@ void PairGranular::compute(int eflag, int vflag) //**************************************** // Twisting torque, including history effects //**************************************** - if (twist[itype][jtype] != NONE){ + if (twist[itype][jtype] != TWIST_NONE){ magtwist = relrot1*nx + relrot2*ny + relrot3*nz; //Omega_T (eq 29 of Marshall) if (twist[itype][jtype] == TWIST_MARSHALL){ k_twist = 0.5*k_tangential*a*a;; //eq 32 @@ -554,7 +562,7 @@ void PairGranular::compute(int eflag, int vflag) torque[i][1] -= radi*tor2; torque[i][2] -= radi*tor3; - if (twist[itype][jtype] != NONE){ + if (twist[itype][jtype] != TWIST_NONE){ tortwist1 = magtortwist * nx; tortwist2 = magtortwist * ny; tortwist3 = magtortwist * nz; @@ -564,7 +572,7 @@ void PairGranular::compute(int eflag, int vflag) torque[i][2] += tortwist3; } - if (roll[itype][jtype] != NONE){ + if (roll[itype][jtype] != ROLL_NONE){ torroll1 = Reff*(ny*fr3 - nz*fr2); //n cross fr torroll2 = Reff*(nz*fr1 - nx*fr3); torroll3 = Reff*(nx*fr2 - ny*fr1); @@ -583,12 +591,12 @@ void PairGranular::compute(int eflag, int vflag) torque[j][1] -= radj*tor2; torque[j][2] -= radj*tor3; - if (roll[itype][jtype] != NONE){ + if (twist[itype][jtype] != TWIST_NONE){ torque[j][0] -= tortwist1; torque[j][1] -= tortwist2; torque[j][2] -= tortwist3; } - if (roll[itype][jtype] != NONE){ + if (roll[itype][jtype] != ROLL_NONE){ torque[j][0] -= torroll1; torque[j][1] -= torroll2; torque[j][2] -= torroll3; @@ -646,22 +654,21 @@ void PairGranular::settings(int narg, char **arg) int iarg = 0; //Some defaults + normal_global = HERTZ; damping_global = VISCOELASTIC; - coeff_types = STIFFNESS; - tangential_global = -1; //Needs to be explicitly set, since it requires parameters - roll_global = NONE; - twist_global = NONE; + tangential_global = TANGENTIAL_MINDLIN; + roll_global = ROLL_NONE; + twist_global = TWIST_NONE; tangential_history = roll_history = twist_history = 0; - if (strcmp(arg[iarg], "material") == 0){ - coeff_types = MATERIAL; - iarg += 1; - } + int normal_set, tangential_set; + normal_set = tangential_set = 0; + while (iarg < narg){ if (strcmp(arg[iarg], "hooke") == 0){ - if (coeff_types == MATERIAL) error->all(FLERR,"Illegal pair_coeff command, 'stiffness' coefficients required for Hooke"); if (iarg + 2 >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for Hooke option"); normal_global = HOOKE; + normal_set = 1; memory->create(normal_coeffs_global, 2, "pair:normal_coeffs_global"); normal_coeffs_global[0] = force->numeric(FLERR,arg[iarg+1]); //kn normal_coeffs_global[1] = force->numeric(FLERR,arg[iarg+2]); //damping @@ -669,20 +676,29 @@ void PairGranular::settings(int narg, char **arg) } else if (strcmp(arg[iarg], "hertz") == 0){ int num_coeffs = 2; - if (coeff_types == MATERIAL) num_coeffs += 1; if (iarg + num_coeffs >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for Hertz option"); normal_global = HERTZ; + normal_set = 1; memory->create(normal_coeffs_global, num_coeffs, "pair:normal_coeffs_global"); - normal_coeffs_global[0] = force->numeric(FLERR,arg[iarg+1]); //kn or E - if (coeff_types == MATERIAL) normal_coeffs_global[0] *= FOURTHIRDS; + normal_coeffs_global[0] = force->numeric(FLERR,arg[iarg+1]); //kn normal_coeffs_global[1] = force->numeric(FLERR,arg[iarg+2]); //damping - if (coeff_types == MATERIAL) normal_coeffs_global[2] = force->numeric(FLERR,arg[iarg+3]); //G (if 'material') + iarg += num_coeffs+1; + } + else if (strcmp(arg[iarg], "hertz/material") == 0){ + int num_coeffs = 3; + if (iarg + num_coeffs >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for Hertz option"); + normal_global = HERTZ_MATERIAL; + normal_set = 1; + memory->create(normal_coeffs_global, num_coeffs, "pair:normal_coeffs_global"); + normal_coeffs_global[0] = force->numeric(FLERR,arg[iarg+1])*FOURTHIRDS; //E (Young's modulus) + normal_coeffs_global[1] = force->numeric(FLERR,arg[iarg+2]); //damping + normal_coeffs_global[2] = force->numeric(FLERR,arg[iarg+3]); //G (shear modulus) iarg += num_coeffs+1; } else if (strcmp(arg[iarg], "dmt") == 0){ - if (coeff_types == STIFFNESS) error->all(FLERR,"Illegal pair_style command, 'material' coefficients required for DMT"); if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for Hertz option"); normal_global = DMT; + normal_set = 1; memory->create(normal_coeffs_global, 4, "pair:normal_coeffs_global"); normal_coeffs_global[0] = force->numeric(FLERR,arg[iarg+1])*FOURTHIRDS; //4/3 E normal_coeffs_global[1] = force->numeric(FLERR,arg[iarg+2]); //damping @@ -692,9 +708,9 @@ void PairGranular::settings(int narg, char **arg) } else if (strcmp(arg[iarg], "jkr") == 0){ if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for JKR option"); - if (coeff_types == STIFFNESS) error->all(FLERR,"Illegal pair_style command, 'material' coefficients required for JKR"); beyond_contact = 1; normal_global = JKR; + normal_set = 1; memory->create(normal_coeffs_global, 4, "pair:normal_coeffs_global"); normal_coeffs_global[0] = force->numeric(FLERR,arg[iarg+1]); //E normal_coeffs_global[1] = force->numeric(FLERR,arg[iarg+2]); //damping @@ -715,57 +731,80 @@ void PairGranular::settings(int narg, char **arg) iarg += 1; } else if (strstr(arg[iarg], "tangential") != NULL){ - if (iarg + 3 >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for tangential model"); - if (strstr(arg[iarg], "nohistory") != NULL){ + if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for tangential model"); + if (strstr(arg[iarg+1], "nohistory") != NULL){ tangential_global = TANGENTIAL_NOHISTORY; + tangential_set = 1; } - else{ + else if (strstr(arg[iarg+1], "mindlin") != NULL){ tangential_global = TANGENTIAL_MINDLIN; tangential_history = 1; + tangential_set = 1; + } + else{ + error->all(FLERR, "Illegal pair_style command, unrecognized sliding friction model"); } memory->create(tangential_coeffs_global, 3, "pair:tangential_coeffs_global"); - tangential_coeffs_global[0] = force->numeric(FLERR,arg[iarg+1]); //kt - tangential_coeffs_global[1] = force->numeric(FLERR,arg[iarg+2]); //gammat - tangential_coeffs_global[2] = force->numeric(FLERR,arg[iarg+3]); //friction coeff. - iarg += 4; + tangential_coeffs_global[0] = force->numeric(FLERR,arg[iarg+2]); //kt + tangential_coeffs_global[1] = force->numeric(FLERR,arg[iarg+3]); //gammat + tangential_coeffs_global[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. + iarg += 5; } else if (strstr(arg[iarg], "roll") != NULL){ - if (iarg + 3 >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for rolling model"); - if (strstr(arg[iarg], "nohistory") != NULL){ - roll_global = ROLL_NOHISTORY; + if (strstr(arg[iarg+1], "none") != NULL){ + roll_global = ROLL_NONE; + iarg += 2; } else{ - roll_global = ROLL_SDS; - roll_history = 1; - } - memory->create(roll_coeffs_global, 3, "pair:roll_coeffs_global"); - roll_coeffs_global[0] = force->numeric(FLERR,arg[iarg+1]); //kt - roll_coeffs_global[1] = force->numeric(FLERR,arg[iarg+2]); //gammat - roll_coeffs_global[2] = force->numeric(FLERR,arg[iarg+3]); //friction coeff. - iarg += 4; - } - else if (strstr(arg[iarg], "twist") != NULL){ - if (strstr(arg[iarg], "marshall") != NULL){ - twist_global = TWIST_MARSHALL; - twist_history = 1; - memory->create(twist_coeffs_global, 3, "pair:twist_coeffs_global"); //To be filled later - } - else{ - if (iarg + 3 >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for twist model"); - if (strstr(arg[iarg], "nohistory") != NULL){ - twist_global = TWIST_NOHISTORY; + if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for rolling model"); + if (strstr(arg[iarg+1], "nohistory") != NULL){ + roll_global = ROLL_NOHISTORY; + } + else if (strstr(arg[iarg+1], "sds") != NULL){ + roll_global = ROLL_SDS; + roll_history = 1; } else{ + error->all(FLERR, "Illegal pair_style command, unrecognized rolling friction model"); + } + memory->create(roll_coeffs_global, 3, "pair:roll_coeffs_global"); + roll_coeffs_global[0] = force->numeric(FLERR,arg[iarg+2]); //kR + roll_coeffs_global[1] = force->numeric(FLERR,arg[iarg+3]); //gammaR + roll_coeffs_global[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. + iarg += 5; + } + } + else if (strstr(arg[iarg], "twist") != NULL){ + if (strstr(arg[iarg+1], "none") != NULL){ + twist_global = TWIST_NONE; + iarg += 2; + } + else if (strstr(arg[iarg+1], "marshall") != NULL){ + twist_global = TWIST_MARSHALL; + twist_history = 1; + iarg += 2; + } + else{ + if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for twist model"); + memory->create(twist_coeffs_global, 3, "pair:twist_coeffs_global"); //To be filled later + if (strstr(arg[iarg+1], "nohistory") != NULL){ + twist_global = TWIST_NOHISTORY; + } + else if (strstr(arg[iarg+1], "sds") != NULL){ twist_global = TWIST_SDS; twist_history = 1; } + else{ + error->all(FLERR, "Illegal pair_style command, unrecognized twisting friction model"); + } memory->create(twist_coeffs_global, 3, "pair:twist_coeffs_global"); - twist_coeffs_global[0] = force->numeric(FLERR,arg[iarg+1]); //kt - twist_coeffs_global[1] = force->numeric(FLERR,arg[iarg+2]); //gammat - twist_coeffs_global[2] = force->numeric(FLERR,arg[iarg+3]); //friction coeff. - iarg += 4; + twist_coeffs_global[0] = force->numeric(FLERR,arg[iarg+2]); //ktwist + twist_coeffs_global[1] = force->numeric(FLERR,arg[iarg+3]); //gammatwist + twist_coeffs_global[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. + iarg += 5; } } + else error->all(FLERR, "Illegal pair_style granular command"); } //Set all i-i entries, which may be replaced by pair coeff commands @@ -774,10 +813,9 @@ void PairGranular::settings(int narg, char **arg) // The reason for the current setup is to remain true to existing pair gran/hooke etc. syntax, // where coeffs are set in the pair_style command, and a pair_coeff * * command is issued. - - //Other option is to have two pair styles, e.g. pair gran and pair gran/multi, - // where gran/multi allows per-type coefficients, pair gran does not (would also - // allow minor speed-up for pair gran) + //Other option is to have two pair styles, e.g. pair granular and pair granular/multi, + // where granular/multi allows per-type coefficients, pair granular does not (this would also + // allow minor speed-up by templating pair granular) allocate(); double damp; for (int i = 1; i <= atom->ntypes; i++){ @@ -787,40 +825,38 @@ void PairGranular::settings(int narg, char **arg) roll[i][i] = roll_global; twist[i][i] = twist_global; - if (damping_global == TSUJI){ - double cor = normal_coeffs_global[1]; - damp = 1.2728-4.2783*cor+11.087*pow(cor,2)-22.348*pow(cor,3)+ - 27.467*pow(cor,4)-18.022*pow(cor,5)+ - 4.8218*pow(cor,6); + if (normal_set){ + if (damping_global == TSUJI){ + double cor = normal_coeffs_global[1]; + damp = 1.2728-4.2783*cor+11.087*pow(cor,2)-22.348*pow(cor,3)+ + 27.467*pow(cor,4)-18.022*pow(cor,5)+ + 4.8218*pow(cor,6); + } + else damp = normal_coeffs_global[1]; + normal_coeffs[i][i][0] = normal_coeffs_global[0]; + normal_coeffs[i][i][1] = damp; + if (normal[i][i] != HOOKE && normal[i][i] != HERTZ){ + normal_coeffs[i][i][2] = normal_coeffs_global[2]; + } + if ((normal_global == JKR) || (normal_global == DMT)) + normal_coeffs[i][i][3] = normal_coeffs_global[3]; } - else damp = normal_coeffs_global[1]; - normal_coeffs[i][i][0] = normal_coeffs_global[0]; - normal_coeffs[i][i][1] = damp; - if (coeff_types == MATERIAL) normal_coeffs[i][i][2] = normal_coeffs_global[2]; - if ((normal_global == JKR) || (normal_global == DMT)) - normal_coeffs[i][i][3] = normal_coeffs_global[3]; - - tangential[i][i] = tangential_global; - if (tangential_global != NONE) + if(tangential_set){ + tangential[i][i] = tangential_global; for (int k = 0; k < 3; k++) tangential_coeffs[i][i][k] = tangential_coeffs_global[k]; - + } roll[i][i] = roll_global; - if (roll_global != NONE) + if (roll_global != ROLL_NONE) for (int k = 0; k < 3; k++) roll_coeffs[i][i][k] = roll_coeffs_global[k]; twist[i][i] = twist_global; - if (twist_global != NONE) + if (twist_global != TWIST_NONE && twist_global != TWIST_MARSHALL) for (int k = 0; k < 3; k++) twist_coeffs[i][i][k] = twist_coeffs_global[k]; - setflag[i][i] = 1; - } - - //Additional checks - if (tangential_global == -1){ - error->all(FLERR, "Illegal pair_style command: must specify tangential model"); + if (normal_set && tangential_set) setflag[i][i] = 1; } } @@ -850,10 +886,12 @@ void PairGranular::coeff(int narg, char **arg) force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); + normal_local = tangential_local = roll_local = twist_local = -1; + damping_local = -1; + int iarg = 2; while (iarg < narg){ if (strcmp(arg[iarg], "hooke") == 0){ - if (coeff_types == MATERIAL) error->all(FLERR,"Illegal pair_coeff command, 'stiffness' coefficients required for Hooke"); if (iarg + 2 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hooke option"); normal_local = HOOKE; normal_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1]); //kn @@ -862,20 +900,25 @@ void PairGranular::coeff(int narg, char **arg) } else if (strcmp(arg[iarg], "hertz") == 0){ int num_coeffs = 2; - if (coeff_types == MATERIAL) num_coeffs += 1; - if (iarg + offset >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hertz option"); + if (iarg + num_coeffs >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hertz option"); normal_local = HERTZ; - normal_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1]); //kn or E - if (coeff_types == STIFFNESS) normal_coeffs_local[0] /= FOURTHIRDS; + normal_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1]); //kn normal_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //damping - if (coeff_types == MATERIAL) normal_coeffs_local[2] = force->numeric(FLERR,arg[iarg+3]); //G (if 'material') + iarg += num_coeffs+1; + } + else if (strcmp(arg[iarg], "hertz/material") == 0){ + int num_coeffs = 3; + if (iarg + num_coeffs >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hertz option"); + normal_local = HERTZ; + normal_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1])*FOURTHIRDS; //E + normal_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //damping + normal_coeffs_local[2] = force->numeric(FLERR,arg[iarg+3]); //G iarg += num_coeffs+1; } else if (strcmp(arg[iarg], "dmt") == 0){ - if (coeff_types == STIFFNESS) error->all(FLERR,"Illegal pair_coeff command, 'material' coefficients required for DMT"); if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hertz option"); normal_local = DMT; - normal_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1]); //E + normal_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1])*FOURTHIRDS; //E normal_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //damping normal_coeffs_local[2] = force->numeric(FLERR,arg[iarg+3]); //G normal_coeffs_local[3] = force->numeric(FLERR,arg[iarg+3]); //cohesion @@ -883,7 +926,6 @@ void PairGranular::coeff(int narg, char **arg) } else if (strcmp(arg[iarg], "jkr") == 0){ if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for JKR option"); - if (coeff_types == STIFFNESS) error->all(FLERR,"Illegal pair_coeff command, 'material' coefficients required for JKR"); beyond_contact = 1; normal_local = JKR; normal_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1]); //E @@ -905,91 +947,128 @@ void PairGranular::coeff(int narg, char **arg) iarg += 1; } else if (strstr(arg[iarg], "tangential") != NULL){ - if (iarg + 3 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for tangential model"); - if (strstr(arg[iarg], "nohistory") != NULL){ + if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for tangential model"); + if (strstr(arg[iarg+1], "nohistory") != NULL){ tangential_local = TANGENTIAL_NOHISTORY; } - else{ + else if (strstr(arg[iarg+1], "mindlin") != NULL){ tangential_local = TANGENTIAL_MINDLIN; tangential_history = 1; } - tangential_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1]); //kt - tangential_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //gammat - tangential_coeffs_local[2] = force->numeric(FLERR,arg[iarg+3]); //friction coeff. - iarg += 4; + else{ + error->all(FLERR, "Illegal pair_coeff command, tangential model not recognized"); + } + tangential_coeffs_local[0] = force->numeric(FLERR,arg[iarg+2]); //kt + tangential_coeffs_local[1] = force->numeric(FLERR,arg[iarg+3]); //gammat + tangential_coeffs_local[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. + iarg += 5; } else if (strstr(arg[iarg], "rolling") != NULL){ - if (iarg + 3 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for rolling model"); - if (strstr(arg[iarg], "nohistory") != NULL){ - roll_local = ROLL_NOHISTORY; + if (iarg + 1 >= narg) error->all(FLERR, "Illegal pair_coeff command, not enough parameters"); + if (strstr(arg[iarg+1], "none") != NULL){ + roll_local = ROLL_NONE; + iarg += 2; } else{ - roll_local = ROLL_SDS; - roll_history = 1; - } - roll_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1]); //kt - roll_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //gammat - roll_coeffs_local[2] = force->numeric(FLERR,arg[iarg+3]); //friction coeff. - iarg += 4; - } - else if (strstr(arg[iarg], "twist") != NULL){ - if (strstr(arg[iarg], "marshall") != NULL){ - twist_local = TWIST_MARSHALL; - twist_history = 1; - } - else{ - if (iarg + 3 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for twist model"); - if (strstr(arg[iarg], "nohistory") != NULL){ - twist_local = TWIST_NOHISTORY; + if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for rolling model"); + if (strstr(arg[iarg+1], "nohistory") != NULL){ + roll_local = ROLL_NOHISTORY; + } + else if (strstr(arg[iarg+1], "sds") != NULL){ + roll_local = ROLL_SDS; + roll_history = 1; } else{ - twist_local = TWIST_SDS; - twist_history = 1; - size_history += 1; + error->all(FLERR, "Illegal pair_coeff command, rolling friction model not recognized"); } - twist_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1]); //kt - twist_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //gammat - twist_coeffs_local[2] = force->numeric(FLERR,arg[iarg+3]); //friction coeff. - iarg += 4; + roll_coeffs_local[0] = force->numeric(FLERR,arg[iarg+2]); //kt + roll_coeffs_local[1] = force->numeric(FLERR,arg[iarg+3]); //gammat + roll_coeffs_local[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. + iarg += 5; } } + else if (strstr(arg[iarg], "twist") != NULL){ + if (iarg + 1 >= narg) error->all(FLERR, "Illegal pair_coeff command, not enough parameters"); + if (strstr(arg[iarg+1], "none") != NULL){ + twist_local = TWIST_NONE; + iarg += 2; + } + else if (strstr(arg[iarg+1], "marshall") != NULL){ + twist_local = TWIST_MARSHALL; + twist_history = 1; + iarg += 2; + } + else{ + if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for twist model"); + if (strstr(arg[iarg+1], "nohistory") != NULL){ + twist_local = TWIST_NOHISTORY; + } + else if (strstr(arg[iarg+1], "sds") != NULL){ + twist_local = TWIST_SDS; + twist_history = 1; + } + else{ + error->all(FLERR, "Illegal pair_coeff command, twisting friction model not recognized"); + } + twist_coeffs_local[0] = force->numeric(FLERR,arg[iarg+2]); //kt + twist_coeffs_local[1] = force->numeric(FLERR,arg[iarg+3]); //gammat + twist_coeffs_local[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. + iarg += 5; + } + } + else error->all(FLERR, "Illegal pair coeff command"); } int count = 0; double damp; - if (damping_local == TSUJI){ - double cor = normal_coeffs_local[1]; - damp = 1.2728-4.2783*cor+11.087*pow(cor,2)-22.348*pow(cor,3)+ - 27.467*pow(cor,4)-18.022*pow(cor,5)+ - 4.8218*pow(cor,6); + if (damping_local >= 0){ + if (normal_local == -1) + error->all(FLERR, "Illegal pair_coeff command, must specify normal model when setting damping model"); + if (damping_local == TSUJI){ + double cor; + cor = normal_coeffs_local[1]; + damp = 1.2728-4.2783*cor+11.087*pow(cor,2)-22.348*pow(cor,3)+ + 27.467*pow(cor,4)-18.022*pow(cor,5)+ + 4.8218*pow(cor,6); + } + else damp = normal_coeffs_local[1]; } - else damp = normal_coeffs_local[1]; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { - normal[i][j] = normal_local; - normal_coeffs[i][j][0] = normal_coeffs_local[0]; - normal_coeffs[i][j][1] = damp; - if (coeff_types == MATERIAL) normal_coeffs[i][j][2] = normal_coeffs_local[2]; - if ((normal_local == JKR) || (normal_local == DMT)) + if (normal_local >= 0){ + normal[i][j] = normal_local; + normal_coeffs[i][j][0] = normal_coeffs_local[0]; + if (damping_local == -1){ + damp = normal_coeffs_global[1]; + } + normal_coeffs[i][j][1] = damp; + if (normal_local != HERTZ && normal_local != HOOKE) normal_coeffs[i][j][2] = normal_coeffs_local[2]; + if ((normal_local == JKR) || (normal_local == DMT)) normal_coeffs[i][j][3] = normal_coeffs_local[3]; - - tangential[i][j] = tangential_local; - if (tangential_local != NONE) + } + if (damping_local >= 0){ + damping[i][j] = damping_local; + } + if (tangential_local >= 0){ + tangential[i][j] = tangential_local; for (int k = 0; k < 3; k++) tangential_coeffs[i][j][k] = tangential_coeffs_local[k]; + } + if (roll_local >= 0){ + roll[i][j] = roll_local; + if (roll_local != ROLL_NONE) + for (int k = 0; k < 3; k++) + roll_coeffs[i][j][k] = roll_coeffs_local[k]; + } + if (twist_local >= 0){ + twist[i][j] = twist_local; + if (twist_local != TWIST_NONE && twist_local != TWIST_MARSHALL) + for (int k = 0; k < 3; k++) + twist_coeffs[i][j][k] = twist_coeffs_local[k]; + } - roll[i][j] = roll_local; - if (roll_local != NONE) - for (int k = 0; k < 3; k++) - roll_coeffs[i][j][k] = roll_coeffs_local[k]; - - twist[i][j] = twist_local; - if (twist_local != NONE) - for (int k = 0; k < 3; k++) - twist_coeffs[i][j][k] = twist_coeffs_local[k]; - - setflag[i][j] = 1; + if (normal_local >= 0 && tangential_local >= 0) setflag[i][j] = 1; count++; } @@ -1020,6 +1099,12 @@ void PairGranular::init_style() // Determine whether we need a granular neigh list, how large it needs to be use_history = tangential_history || roll_history || twist_history; + + //For JKR, will need fix/neigh/history to keep track of touch arrays + for (int i = 1; i <= atom->ntypes; i++) + for (int j = 1; j <= atom->ntypes; j++) + if (normal[i][j] == JKR) use_history = 1; + size_history = 3*tangential_history + 3*roll_history + twist_history; //Determine location of tangential/roll/twist histories in array @@ -1145,6 +1230,7 @@ void PairGranular::init_style() double PairGranular::init_one(int i, int j) { + double cutoff; if (setflag[i][j] == 0) { if ((normal[i] != normal[j]) || (damping[i] != damping[j]) || @@ -1157,7 +1243,7 @@ double PairGranular::init_one(int i, int j) error->one(FLERR,str); } - if (coeff_types == MATERIAL){ + if (normal[i][j] != HOOKE && normal[i][j] != HERTZ){ normal_coeffs[i][j][0] = mix_stiffnessE(normal_coeffs[i][i][0], normal_coeffs[j][j][0], normal_coeffs[i][i][2], normal_coeffs[j][j][2]); normal_coeffs[i][j][2] = mix_stiffnessG(normal_coeffs[i][i][0], normal_coeffs[j][j][0], @@ -1165,24 +1251,22 @@ double PairGranular::init_one(int i, int j) } else{ normal_coeffs[i][j][0] = mix_geom(normal_coeffs[i][i][0], normal_coeffs[j][j][0]); - if (normal[i][j] == HERTZ) normal_coeffs[i][j][0] /= FOURTHIRDS; } normal_coeffs[i][j][1] = mix_geom(normal_coeffs[i][i][1], normal_coeffs[j][j][1]); if ((normal[i][i] == JKR) || (normal[i][i] == DMT)) normal_coeffs[i][j][3] = mix_geom(normal_coeffs[i][i][3], normal_coeffs[j][j][3]); - if (tangential[i][i] != NONE){ - for (int k = 0; k < 3; k++) - tangential_coeffs[i][j][k] = mix_geom(tangential_coeffs[i][i][k], tangential_coeffs[j][j][k]); - } + for (int k = 0; k < 3; k++) + tangential_coeffs[i][j][k] = mix_geom(tangential_coeffs[i][i][k], tangential_coeffs[j][j][k]); - if (roll[i][i] != NONE){ + + if (roll[i][i] != ROLL_NONE){ for (int k = 0; k < 3; k++) roll_coeffs[i][j][k] = mix_geom(roll_coeffs[i][i][k], roll_coeffs[j][j][k]); } - if (twist[i][i] != NONE){ + if (twist[i][i] != TWIST_NONE && twist[i][i] != TWIST_MARSHALL){ for (int k = 0; k < 3; k++) twist_coeffs[i][j][k] = mix_geom(twist_coeffs[i][i][k], twist_coeffs[j][j][k]); } @@ -1325,6 +1409,7 @@ double PairGranular::single(int i, int j, int itype, int jtype, double tortwist1, tortwist2, tortwist3; double shrmag,rsht; + int jnum; int *ilist,*jlist,*numneigh,**firstneigh; int *touch,**firsttouch; double *history,*allhistory,**firsthistory; @@ -1335,20 +1420,20 @@ double PairGranular::single(int i, int j, int itype, int jtype, radsum = radi + radj; Reff = radi*radj/(radi+radj); - bool untouchflag; + bool touchflag; if (normal[itype][jtype] == JKR){ R2 = Reff*Reff; coh = normal_coeffs[itype][jtype][3]; a = cbrt(9.0*M_PI*coh*R2/(4*E)); delta_pulloff = a*a/Reff - 2*sqrt(M_PI*coh*a/E); dist_pulloff = radsum+delta_pulloff; - untouchflag = (rsq >= dist_pulloff*dist_pulloff); + touchflag = (rsq <= dist_pulloff*dist_pulloff); } else{ - untouchflag = (rsq >= radsum*radsum); + touchflag = (rsq <= radsum*radsum); } - if (untouchflag){ + if (touchflag){ fforce = 0.0; for (int m = 0; m < single_extra; m++) svector[m] = 0.0; return 0.0; @@ -1412,9 +1497,7 @@ double PairGranular::single(int i, int j, int itype, int jtype, // if I or J part of rigid body, use body mass // if I or J is frozen, meff is other particle - double *rmass = atom->rmass; int *type = atom->type; - int *mask = atom->mask; mi = rmass[i]; mj = rmass[j]; @@ -1446,11 +1529,13 @@ double PairGranular::single(int i, int j, int itype, int jtype, a2 = a*a; knfac = FOURTHIRDS*E*a; Fne = knfac*a2/Reff - TWOPI*a2*sqrt(4*coh*E/(M_PI*a)); + if (damping[itype][jtype] == VISCOELASTIC) sqdR = sqrt(dR); } else{ - knfac = E; //Hooke + knfac = E; Fne = knfac*delta; if (normal[itype][jtype] != HOOKE) + a = sqdR = sqrt(dR); Fne *= a; if (normal[itype][jtype] == DMT) Fne -= 4*MY_PI*normal_coeffs[itype][jtype][3]*Reff; @@ -1462,6 +1547,8 @@ double PairGranular::single(int i, int j, int itype, int jtype, } else if (damping[itype][jtype] == VISCOELASTIC){ if (normal[itype][jtype] == HOOKE) a = sqdR = sqrt(dR); + + damp_normal = normal_coeffs[itype][jtype][1]*sqdR*meff; } else if (damping[itype][jtype] == TSUJI){ @@ -1472,9 +1559,8 @@ double PairGranular::single(int i, int j, int itype, int jtype, Fntot = Fne + Fdamp; - int jnum = list->numneigh[i]; - int *jlist = list->firstneigh[i]; - double *allhistory, *history; + jnum = list->numneigh[i]; + jlist = list->firstneigh[i]; if (use_history){ allhistory = fix_history->firstvalue[i]; @@ -1522,7 +1608,7 @@ double PairGranular::single(int i, int j, int itype, int jtype, } damp_tangential = tangential_coeffs[itype][jtype][1]*damp_normal; - if (tangential_history[itype][jtype]){ + if (tangential_history){ shrmag = sqrt(history[0]*history[0] + history[1]*history[1] + history[2]*history[2]); @@ -1558,7 +1644,7 @@ double PairGranular::single(int i, int j, int itype, int jtype, // Rolling resistance //**************************************** - if (roll[itype][jtype] != NONE){ + if (roll[itype][jtype] != ROLL_NONE){ relrot1 = omega[i][0] - omega[j][0]; relrot2 = omega[i][1] - omega[j][1]; relrot3 = omega[i][2] - omega[j][2]; @@ -1619,7 +1705,7 @@ double PairGranular::single(int i, int j, int itype, int jtype, //**************************************** // Twisting torque, including history effects //**************************************** - if (twist[itype][jtype] != NONE){ + if (twist[itype][jtype] != TWIST_NONE){ magtwist = relrot1*nx + relrot2*ny + relrot3*nz; //Omega_T (eq 29 of Marshall) if (twist[itype][jtype] == TWIST_MARSHALL){ k_twist = 0.5*k_tangential*a*a;; //eq 32 diff --git a/src/GRANULAR/pair_granular.h b/src/GRANULAR/pair_granular.h index 957a16af8d..0e6f28c514 100644 --- a/src/GRANULAR/pair_granular.h +++ b/src/GRANULAR/pair_granular.h @@ -62,9 +62,9 @@ public: virtual void allocate(); int beyond_contact; + int nondefault_history_transfer; private: - int coeff_types; int size_history; //Per-type models From 29dcdec8756bf714fc76b6e35026082494bea4d3 Mon Sep 17 00:00:00 2001 From: Dan Stefan Bolintineanu Date: Thu, 10 Jan 2019 16:53:50 -0700 Subject: [PATCH 13/44] Separated templated pair granular from pair granular/multi --- src/GRANULAR/pair_granular.cpp | 1069 ++++++++++++--- src/GRANULAR/pair_granular.h | 33 +- src/GRANULAR/pair_granular_multi.cpp | 1837 ++++++++++++++++++++++++++ src/GRANULAR/pair_granular_multi.h | 108 ++ src/fix_neigh_history.cpp | 8 +- src/pair.h | 4 + 6 files changed, 2850 insertions(+), 209 deletions(-) create mode 100644 src/GRANULAR/pair_granular_multi.cpp create mode 100644 src/GRANULAR/pair_granular_multi.h diff --git a/src/GRANULAR/pair_granular.cpp b/src/GRANULAR/pair_granular.cpp index 9ee78686c6..c75c80fea5 100644 --- a/src/GRANULAR/pair_granular.cpp +++ b/src/GRANULAR/pair_granular.cpp @@ -48,9 +48,9 @@ using namespace MathConst; #define EPSILON 1e-10 -enum {VELOCITY, VISCOELASTIC, TSUJI}; enum {HOOKE, HERTZ, HERTZ_MATERIAL, DMT, JKR}; -enum {TANGENTIAL_MINDLIN, TANGENTIAL_NOHISTORY}; +enum {VELOCITY, VISCOELASTIC, TSUJI}; +enum {TANGENTIAL_NOHISTORY, TANGENTIAL_MINDLIN}; enum {TWIST_NONE, TWIST_NOHISTORY, TWIST_SDS, TWIST_MARSHALL}; enum {ROLL_NONE, ROLL_NOHISTORY, ROLL_SDS}; @@ -105,12 +105,6 @@ PairGranular::~PairGranular() memory->destroy(roll_coeffs); memory->destroy(twist_coeffs); - memory->destroy(normal); - memory->destroy(damping); - memory->destroy(tangential); - memory->destroy(roll); - memory->destroy(twist); - delete [] onerad_dynamic; delete [] onerad_frozen; delete [] maxrad_dynamic; @@ -119,12 +113,730 @@ PairGranular::~PairGranular() memory->destroy(mass_rigid); } -void PairGranular::compute(int eflag, int vflag) +void PairGranular::compute(int eflag, int vflag){ +#ifdef TEMPLATED_PAIR_GRANULAR + if (normal == HOOKE){ + if (damping == VELOCITY){ + if (tangential == TANGENTIAL_NOHISTORY){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<0,0,0,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<0,0,0,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<0,0,0,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<0,0,0,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<0,0,0,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<0,0,0,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<0,0,0,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<0,0,0,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<0,0,0,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<0,0,0,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<0,0,0,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<0,0,0,3,2>(eflag, vflag); + } + } + else if (tangential == TANGENTIAL_MINDLIN){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<0,0,1,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<0,0,1,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<0,0,1,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<0,0,1,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<0,0,1,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<0,0,1,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<0,0,1,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<0,0,1,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<0,0,1,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<0,0,1,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<0,0,1,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<0,0,1,3,2>(eflag, vflag); + } + } + } + else if (damping == VISCOELASTIC){ + if (tangential == TANGENTIAL_NOHISTORY){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<0,1,0,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<0,1,0,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<0,1,0,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<0,1,0,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<0,1,0,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<0,1,0,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<0,1,0,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<0,1,0,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<0,1,0,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<0,1,0,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<0,1,0,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<0,1,0,3,2>(eflag, vflag); + } + } + else if (tangential == TANGENTIAL_MINDLIN){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<0,1,1,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<0,1,1,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<0,1,1,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<0,1,1,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<0,1,1,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<0,1,1,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<0,1,1,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<0,1,1,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<0,1,1,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<0,1,1,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<0,1,1,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<0,1,1,3,2>(eflag, vflag); + } + } + } + else if (damping == TSUJI){ + if (tangential == TANGENTIAL_NOHISTORY){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<0,2,0,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<0,2,0,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<0,2,0,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<0,2,0,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<0,2,0,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<0,2,0,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<0,2,0,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<0,2,0,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<0,2,0,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<0,2,0,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<0,2,0,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<0,2,0,3,2>(eflag, vflag); + } + } + else if (tangential == TANGENTIAL_MINDLIN){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<0,2,1,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<0,2,1,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<0,2,1,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<0,2,1,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<0,2,1,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<0,2,1,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<0,2,1,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<0,2,1,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<0,2,1,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<0,2,1,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<0,2,1,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<0,2,1,3,2>(eflag, vflag); + } + } + } + } + else if (normal == HERTZ){ + if (damping == VELOCITY){ + if (tangential == TANGENTIAL_NOHISTORY){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<1,0,0,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<1,0,0,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<1,0,0,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<1,0,0,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<1,0,0,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<1,0,0,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<1,0,0,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<1,0,0,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<1,0,0,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<1,0,0,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<1,0,0,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<1,0,0,3,2>(eflag, vflag); + } + } + else if (tangential == TANGENTIAL_MINDLIN){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<1,0,1,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<1,0,1,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<1,0,1,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<1,0,1,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<1,0,1,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<1,0,1,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<1,0,1,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<1,0,1,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<1,0,1,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<1,0,1,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<1,0,1,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<1,0,1,3,2>(eflag, vflag); + } + } + } + else if (damping == VISCOELASTIC){ + if (tangential == TANGENTIAL_NOHISTORY){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<1,1,0,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<1,1,0,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<1,1,0,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<1,1,0,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<1,1,0,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<1,1,0,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<1,1,0,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<1,1,0,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<1,1,0,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<1,1,0,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<1,1,0,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<1,1,0,3,2>(eflag, vflag); + } + } + else if (tangential == TANGENTIAL_MINDLIN){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<1,1,1,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<1,1,1,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<1,1,1,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<1,1,1,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<1,1,1,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<1,1,1,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<1,1,1,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<1,1,1,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<1,1,1,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<1,1,1,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<1,1,1,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<1,1,1,3,2>(eflag, vflag); + } + } + } + else if (damping == TSUJI){ + if (tangential == TANGENTIAL_NOHISTORY){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<1,2,0,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<1,2,0,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<1,2,0,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<1,2,0,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<1,2,0,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<1,2,0,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<1,2,0,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<1,2,0,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<1,2,0,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<1,2,0,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<1,2,0,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<1,2,0,3,2>(eflag, vflag); + } + } + else if (tangential == TANGENTIAL_MINDLIN){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<1,2,1,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<1,2,1,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<1,2,1,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<1,2,1,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<1,2,1,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<1,2,1,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<1,2,1,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<1,2,1,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<1,2,1,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<1,2,1,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<1,2,1,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<1,2,1,3,2>(eflag, vflag); + } + } + } + } + else if (normal == HERTZ_MATERIAL){ + if (damping == VELOCITY){ + if (tangential == TANGENTIAL_NOHISTORY){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<2,0,0,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<2,0,0,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<2,0,0,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<2,0,0,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<2,0,0,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<2,0,0,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<2,0,0,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<2,0,0,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<2,0,0,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<2,0,0,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<2,0,0,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<2,0,0,3,2>(eflag, vflag); + } + } + else if (tangential == TANGENTIAL_MINDLIN){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<2,0,1,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<2,0,1,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<2,0,1,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<2,0,1,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<2,0,1,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<2,0,1,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<2,0,1,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<2,0,1,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<2,0,1,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<2,0,1,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<2,0,1,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<2,0,1,3,2>(eflag, vflag); + } + } + } + else if (damping == VISCOELASTIC){ + if (tangential == TANGENTIAL_NOHISTORY){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<2,1,0,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<2,1,0,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<2,1,0,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<2,1,0,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<2,1,0,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<2,1,0,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<2,1,0,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<2,1,0,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<2,1,0,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<2,1,0,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<2,1,0,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<2,1,0,3,2>(eflag, vflag); + } + } + else if (tangential == TANGENTIAL_MINDLIN){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<2,1,1,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<2,1,1,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<2,1,1,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<2,1,1,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<2,1,1,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<2,1,1,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<2,1,1,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<2,1,1,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<2,1,1,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<2,1,1,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<2,1,1,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<2,1,1,3,2>(eflag, vflag); + } + } + } + else if (damping == TSUJI){ + if (tangential == TANGENTIAL_NOHISTORY){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<2,2,0,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<2,2,0,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<2,2,0,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<2,2,0,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<2,2,0,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<2,2,0,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<2,2,0,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<2,2,0,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<2,2,0,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<2,2,0,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<2,2,0,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<2,2,0,3,2>(eflag, vflag); + } + } + else if (tangential == TANGENTIAL_MINDLIN){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<2,2,1,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<2,2,1,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<2,2,1,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<2,2,1,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<2,2,1,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<2,2,1,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<2,2,1,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<2,2,1,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<2,2,1,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<2,2,1,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<2,2,1,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<2,2,1,3,2>(eflag, vflag); + } + } + } + } + else if (normal == DMT){ + if (damping == VELOCITY){ + if (tangential == TANGENTIAL_NOHISTORY){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<3,0,0,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<3,0,0,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<3,0,0,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<3,0,0,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<3,0,0,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<3,0,0,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<3,0,0,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<3,0,0,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<3,0,0,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<3,0,0,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<3,0,0,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<3,0,0,3,2>(eflag, vflag); + } + } + else if (tangential == TANGENTIAL_MINDLIN){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<3,0,1,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<3,0,1,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<3,0,1,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<3,0,1,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<3,0,1,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<3,0,1,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<3,0,1,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<3,0,1,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<3,0,1,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<3,0,1,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<3,0,1,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<3,0,1,3,2>(eflag, vflag); + } + } + } + else if (damping == VISCOELASTIC){ + if (tangential == TANGENTIAL_NOHISTORY){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<3,1,0,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<3,1,0,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<3,1,0,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<3,1,0,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<3,1,0,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<3,1,0,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<3,1,0,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<3,1,0,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<3,1,0,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<3,1,0,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<3,1,0,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<3,1,0,3,2>(eflag, vflag); + } + } + else if (tangential == TANGENTIAL_MINDLIN){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<3,1,1,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<3,1,1,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<3,1,1,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<3,1,1,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<3,1,1,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<3,1,1,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<3,1,1,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<3,1,1,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<3,1,1,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<3,1,1,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<3,1,1,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<3,1,1,3,2>(eflag, vflag); + } + } + } + else if (damping == TSUJI){ + if (tangential == TANGENTIAL_NOHISTORY){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<3,2,0,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<3,2,0,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<3,2,0,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<3,2,0,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<3,2,0,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<3,2,0,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<3,2,0,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<3,2,0,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<3,2,0,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<3,2,0,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<3,2,0,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<3,2,0,3,2>(eflag, vflag); + } + } + else if (tangential == TANGENTIAL_MINDLIN){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<3,2,1,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<3,2,1,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<3,2,1,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<3,2,1,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<3,2,1,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<3,2,1,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<3,2,1,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<3,2,1,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<3,2,1,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<3,2,1,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<3,2,1,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<3,2,1,3,2>(eflag, vflag); + } + } + } + } + else if (normal == JKR){ + if (damping == VELOCITY){ + if (tangential == TANGENTIAL_NOHISTORY){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<4,0,0,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<4,0,0,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<4,0,0,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<4,0,0,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<4,0,0,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<4,0,0,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<4,0,0,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<4,0,0,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<4,0,0,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<4,0,0,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<4,0,0,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<4,0,0,3,2>(eflag, vflag); + } + } + else if (tangential == TANGENTIAL_MINDLIN){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<4,0,1,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<4,0,1,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<4,0,1,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<4,0,1,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<4,0,1,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<4,0,1,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<4,0,1,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<4,0,1,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<4,0,1,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<4,0,1,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<4,0,1,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<4,0,1,3,2>(eflag, vflag); + } + } + } + else if (damping == VISCOELASTIC){ + if (tangential == TANGENTIAL_NOHISTORY){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<4,1,0,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<4,1,0,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<4,1,0,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<4,1,0,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<4,1,0,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<4,1,0,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<4,1,0,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<4,1,0,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<4,1,0,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<4,1,0,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<4,1,0,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<4,1,0,3,2>(eflag, vflag); + } + } + else if (tangential == TANGENTIAL_MINDLIN){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<4,1,1,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<4,1,1,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<4,1,1,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<4,1,1,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<4,1,1,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<4,1,1,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<4,1,1,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<4,1,1,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<4,1,1,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<4,1,1,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<4,1,1,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<4,1,1,3,2>(eflag, vflag); + } + } + } + else if (damping == TSUJI){ + if (tangential == TANGENTIAL_NOHISTORY){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<4,2,0,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<4,2,0,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<4,2,0,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<4,2,0,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<4,2,0,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<4,2,0,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<4,2,0,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<4,2,0,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<4,2,0,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<4,2,0,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<4,2,0,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<4,2,0,3,2>(eflag, vflag); + } + } + else if (tangential == TANGENTIAL_MINDLIN){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<4,2,1,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<4,2,1,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<4,2,1,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<4,2,1,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<4,2,1,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<4,2,1,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<4,2,1,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<4,2,1,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<4,2,1,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<4,2,1,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<4,2,1,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<4,2,1,3,2>(eflag, vflag); + } + } + } + } + +#else + compute_untemplated(Tp_normal, Tp_damping, Tp_tangential, + Tp_roll, Tp_twist, + eflag, vflag); +#endif +} + +#ifdef TEMPLATED_PAIR_GRANULAR +template < int Tp_normal, int Tp_damping, int Tp_tangential, + int Tp_roll, int Tp_twist > +void PairGranular::compute_templated(int eflag, int vflag) +#else +void PairGranular::compute_untemplated + (int Tp_normal, int Tp_damping, int Tp_tangential, + int Tp_roll, int Tp_twist, int eflag, int vflag) +#endif { int i,j,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,fx,fy,fz,nx,ny,nz; double radi,radj,radsum,rsq,r,rinv,rsqinv; - double Reff, delta, dR, dR2, sqdR; + double Reff, delta, dR, dR2; double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3; double wr1,wr2,wr3; @@ -235,21 +947,21 @@ void PairGranular::compute(int eflag, int vflag) Reff = radi*radj/(radi+radj); touchflag = false; - if (normal[itype][jtype] == JKR){ + if (Tp_normal == JKR){ if (touch[jj]){ R2 = Reff*Reff; coh = normal_coeffs[itype][jtype][3]; a = cbrt(9.0*M_PI*coh*R2/(4*E)); delta_pulloff = a*a/Reff - 2*sqrt(M_PI*coh*a/E); dist_pulloff = radsum-delta_pulloff; - touchflag = (rsq <= dist_pulloff*dist_pulloff); + touchflag = (rsq < dist_pulloff*dist_pulloff); } else{ - touchflag = (rsq <= radsum*radsum); + touchflag = (rsq < radsum*radsum); } } else{ - touchflag = (rsq <= radsum*radsum); + touchflag = (rsq < radsum*radsum); } if (!touchflag){ @@ -296,8 +1008,10 @@ void PairGranular::compute(int eflag, int vflag) delta = radsum - r; dR = delta*Reff; - if (normal[itype][jtype] == JKR){ + if (Tp_normal == JKR){ touch[jj] = 1; + R2=Reff*Reff; + coh = normal_coeffs[itype][jtype][3]; dR2 = dR*dR; t0 = coh*coh*R2*R2*E; t1 = PI27SQ*t0; @@ -317,22 +1031,22 @@ void PairGranular::compute(int eflag, int vflag) else{ knfac = E; //Hooke Fne = knfac*delta; - if (normal[itype][jtype] != HOOKE) - a = sqdR = sqrt(dR); + if (Tp_normal != HOOKE) + a = sqrt(dR); Fne *= a; - if (normal[itype][jtype] == DMT) + if (Tp_normal == DMT) Fne -= 4*MY_PI*normal_coeffs[itype][jtype][3]*Reff; } //Consider restricting Hooke to only have 'velocity' as an option for damping? - if (damping[itype][jtype] == VELOCITY){ + if (Tp_damping == VELOCITY){ damp_normal = normal_coeffs[itype][jtype][1]; } - else if (damping[itype][jtype] == VISCOELASTIC){ - if (normal[itype][jtype] == HOOKE) a = sqdR = sqrt(dR); - damp_normal = normal_coeffs[itype][jtype][1]*sqdR*meff; + else if (Tp_damping == VISCOELASTIC){ + if (Tp_normal == HOOKE) a = sqrt(dR); + damp_normal = normal_coeffs[itype][jtype][1]*a*meff; } - else if (damping[itype][jtype] == TSUJI){ + else if (Tp_damping == TSUJI){ damp_normal = normal_coeffs[itype][jtype][1]*sqrt(meff*knfac); } @@ -367,11 +1081,14 @@ void PairGranular::compute(int eflag, int vflag) history = &allhistory[size_history*jj]; } - Fcrit = fabs(Fne); - if (normal[itype][jtype] == JKR){ + + if (Tp_normal == JKR){ F_pulloff = 3*M_PI*coh*Reff; Fcrit = fabs(Fne + 2*F_pulloff); } + else{ + Fcrit = fabs(Fne); + } //------------------------------ //Tangential forces @@ -379,7 +1096,7 @@ void PairGranular::compute(int eflag, int vflag) k_tangential = tangential_coeffs[itype][jtype][0]; damp_tangential = tangential_coeffs[itype][jtype][1]*damp_normal; - if (tangential_history){ + if (Tp_tangential > 0){ shrmag = sqrt(history[0]*history[0] + history[1]*history[1] + history[2]*history[2]); @@ -436,7 +1153,7 @@ void PairGranular::compute(int eflag, int vflag) // Rolling resistance //**************************************** - if (roll[itype][jtype] != ROLL_NONE){ + if (Tp_roll != ROLL_NONE){ relrot1 = omega[i][0] - omega[j][0]; relrot2 = omega[i][1] - omega[j][1]; relrot3 = omega[i][2] - omega[j][2]; @@ -451,7 +1168,7 @@ void PairGranular::compute(int eflag, int vflag) if (vrlmag != 0.0) vrlmaginv = 1.0/vrlmag; else vrlmaginv = 0.0; - if (roll_history){ + if (Tp_roll > 1){ int rhist0 = roll_history_index; int rhist1 = rhist0 + 1; int rhist2 = rhist1 + 1; @@ -515,9 +1232,9 @@ void PairGranular::compute(int eflag, int vflag) //**************************************** // Twisting torque, including history effects //**************************************** - if (twist[itype][jtype] != TWIST_NONE){ + if (Tp_twist != TWIST_NONE){ magtwist = relrot1*nx + relrot2*ny + relrot3*nz; //Omega_T (eq 29 of Marshall) - if (twist[itype][jtype] == TWIST_MARSHALL){ + if (Tp_twist == TWIST_MARSHALL){ k_twist = 0.5*k_tangential*a*a;; //eq 32 damp_twist = 0.5*damp_tangential*a*a; mu_twist = TWOTHIRDS*a; @@ -527,7 +1244,7 @@ void PairGranular::compute(int eflag, int vflag) damp_twist = twist_coeffs[itype][jtype][1]; mu_twist = twist_coeffs[itype][jtype][2]; } - if (twist_history){ + if (Tp_twist > 1){ if (historyupdate){ history[twist_history_index] += magtwist*dt; } @@ -562,7 +1279,7 @@ void PairGranular::compute(int eflag, int vflag) torque[i][1] -= radi*tor2; torque[i][2] -= radi*tor3; - if (twist[itype][jtype] != TWIST_NONE){ + if (Tp_twist != TWIST_NONE){ tortwist1 = magtortwist * nx; tortwist2 = magtortwist * ny; tortwist3 = magtortwist * nz; @@ -572,7 +1289,7 @@ void PairGranular::compute(int eflag, int vflag) torque[i][2] += tortwist3; } - if (roll[itype][jtype] != ROLL_NONE){ + if (Tp_roll != ROLL_NONE){ torroll1 = Reff*(ny*fr3 - nz*fr2); //n cross fr torroll2 = Reff*(nz*fr1 - nx*fr3); torroll3 = Reff*(nx*fr2 - ny*fr1); @@ -591,12 +1308,12 @@ void PairGranular::compute(int eflag, int vflag) torque[j][1] -= radj*tor2; torque[j][2] -= radj*tor3; - if (twist[itype][jtype] != TWIST_NONE){ + if (Tp_twist != TWIST_NONE){ torque[j][0] -= tortwist1; torque[j][1] -= tortwist2; torque[j][2] -= tortwist3; } - if (roll[itype][jtype] != ROLL_NONE){ + if (Tp_roll != ROLL_NONE){ torque[j][0] -= torroll1; torque[j][1] -= torroll2; torque[j][2] -= torroll3; @@ -631,12 +1348,6 @@ void PairGranular::allocate() memory->create(roll_coeffs,n+1,n+1,3,"pair:roll_coeffs"); memory->create(twist_coeffs,n+1,n+1,3,"pair:twist_coeffs"); - memory->create(normal,n+1,n+1,"pair:normal"); - memory->create(damping,n+1,n+1,"pair:damping"); - memory->create(tangential,n+1,n+1,"pair:tangential"); - memory->create(roll,n+1,n+1,"pair:roll"); - memory->create(twist,n+1,n+1,"pair:twist"); - onerad_dynamic = new double[n+1]; onerad_frozen = new double[n+1]; maxrad_dynamic = new double[n+1]; @@ -654,12 +1365,14 @@ void PairGranular::settings(int narg, char **arg) int iarg = 0; //Some defaults - normal_global = HERTZ; - damping_global = VISCOELASTIC; - tangential_global = TANGENTIAL_MINDLIN; - roll_global = ROLL_NONE; - twist_global = TWIST_NONE; - tangential_history = roll_history = twist_history = 0; + normal = HERTZ; + damping = VISCOELASTIC; + tangential = TANGENTIAL_MINDLIN; + roll = ROLL_NONE; + twist = TWIST_NONE; + + tangential_history = 1; + roll_history = twist_history = 0; int normal_set, tangential_set; normal_set = tangential_set = 0; @@ -667,8 +1380,7 @@ void PairGranular::settings(int narg, char **arg) while (iarg < narg){ if (strcmp(arg[iarg], "hooke") == 0){ if (iarg + 2 >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for Hooke option"); - normal_global = HOOKE; - normal_set = 1; + normal = HOOKE; memory->create(normal_coeffs_global, 2, "pair:normal_coeffs_global"); normal_coeffs_global[0] = force->numeric(FLERR,arg[iarg+1]); //kn normal_coeffs_global[1] = force->numeric(FLERR,arg[iarg+2]); //damping @@ -677,7 +1389,7 @@ void PairGranular::settings(int narg, char **arg) else if (strcmp(arg[iarg], "hertz") == 0){ int num_coeffs = 2; if (iarg + num_coeffs >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for Hertz option"); - normal_global = HERTZ; + normal = HERTZ; normal_set = 1; memory->create(normal_coeffs_global, num_coeffs, "pair:normal_coeffs_global"); normal_coeffs_global[0] = force->numeric(FLERR,arg[iarg+1]); //kn @@ -687,7 +1399,7 @@ void PairGranular::settings(int narg, char **arg) else if (strcmp(arg[iarg], "hertz/material") == 0){ int num_coeffs = 3; if (iarg + num_coeffs >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for Hertz option"); - normal_global = HERTZ_MATERIAL; + normal = HERTZ_MATERIAL; normal_set = 1; memory->create(normal_coeffs_global, num_coeffs, "pair:normal_coeffs_global"); normal_coeffs_global[0] = force->numeric(FLERR,arg[iarg+1])*FOURTHIRDS; //E (Young's modulus) @@ -697,7 +1409,7 @@ void PairGranular::settings(int narg, char **arg) } else if (strcmp(arg[iarg], "dmt") == 0){ if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for Hertz option"); - normal_global = DMT; + normal = DMT; normal_set = 1; memory->create(normal_coeffs_global, 4, "pair:normal_coeffs_global"); normal_coeffs_global[0] = force->numeric(FLERR,arg[iarg+1])*FOURTHIRDS; //4/3 E @@ -709,7 +1421,7 @@ void PairGranular::settings(int narg, char **arg) else if (strcmp(arg[iarg], "jkr") == 0){ if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for JKR option"); beyond_contact = 1; - normal_global = JKR; + normal = JKR; normal_set = 1; memory->create(normal_coeffs_global, 4, "pair:normal_coeffs_global"); normal_coeffs_global[0] = force->numeric(FLERR,arg[iarg+1]); //E @@ -719,25 +1431,25 @@ void PairGranular::settings(int narg, char **arg) iarg += 5; } else if (strcmp(arg[iarg], "damp_velocity") == 0){ - damping_global = VELOCITY; + damping = VELOCITY; iarg += 1; } else if (strcmp(arg[iarg], "damp_viscoelastic") == 0){ - damping_global = VISCOELASTIC; + damping = VISCOELASTIC; iarg += 1; } else if (strcmp(arg[iarg], "damp_tsuji") == 0){ - damping_global = TSUJI; + damping = TSUJI; iarg += 1; } else if (strstr(arg[iarg], "tangential") != NULL){ if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for tangential model"); if (strstr(arg[iarg+1], "nohistory") != NULL){ - tangential_global = TANGENTIAL_NOHISTORY; + tangential = TANGENTIAL_NOHISTORY; tangential_set = 1; } else if (strstr(arg[iarg+1], "mindlin") != NULL){ - tangential_global = TANGENTIAL_MINDLIN; + tangential = TANGENTIAL_MINDLIN; tangential_history = 1; tangential_set = 1; } @@ -752,16 +1464,16 @@ void PairGranular::settings(int narg, char **arg) } else if (strstr(arg[iarg], "roll") != NULL){ if (strstr(arg[iarg+1], "none") != NULL){ - roll_global = ROLL_NONE; + roll = ROLL_NONE; iarg += 2; } else{ if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for rolling model"); if (strstr(arg[iarg+1], "nohistory") != NULL){ - roll_global = ROLL_NOHISTORY; + roll = ROLL_NOHISTORY; } else if (strstr(arg[iarg+1], "sds") != NULL){ - roll_global = ROLL_SDS; + roll = ROLL_SDS; roll_history = 1; } else{ @@ -776,11 +1488,11 @@ void PairGranular::settings(int narg, char **arg) } else if (strstr(arg[iarg], "twist") != NULL){ if (strstr(arg[iarg+1], "none") != NULL){ - twist_global = TWIST_NONE; + twist = TWIST_NONE; iarg += 2; } else if (strstr(arg[iarg+1], "marshall") != NULL){ - twist_global = TWIST_MARSHALL; + twist = TWIST_MARSHALL; twist_history = 1; iarg += 2; } @@ -788,10 +1500,10 @@ void PairGranular::settings(int narg, char **arg) if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for twist model"); memory->create(twist_coeffs_global, 3, "pair:twist_coeffs_global"); //To be filled later if (strstr(arg[iarg+1], "nohistory") != NULL){ - twist_global = TWIST_NOHISTORY; + twist = TWIST_NOHISTORY; } else if (strstr(arg[iarg+1], "sds") != NULL){ - twist_global = TWIST_SDS; + twist = TWIST_SDS; twist_history = 1; } else{ @@ -813,46 +1525,35 @@ void PairGranular::settings(int narg, char **arg) // The reason for the current setup is to remain true to existing pair gran/hooke etc. syntax, // where coeffs are set in the pair_style command, and a pair_coeff * * command is issued. - //Other option is to have two pair styles, e.g. pair granular and pair granular/multi, - // where granular/multi allows per-type coefficients, pair granular does not (this would also - // allow minor speed-up by templating pair granular) allocate(); double damp; - for (int i = 1; i <= atom->ntypes; i++){ - normal[i][i] = normal_global; - damping[i][i] = damping_global; - tangential[i][i] = tangential_global; - roll[i][i] = roll_global; - twist[i][i] = twist_global; + if (damping == TSUJI){ + double cor = normal_coeffs_global[1]; + damp = 1.2728-4.2783*cor+11.087*pow(cor,2)-22.348*pow(cor,3)+ + 27.467*pow(cor,4)-18.022*pow(cor,5)+ + 4.8218*pow(cor,6); + } + else damp = normal_coeffs_global[1]; + for (int i = 1; i <= atom->ntypes; i++){ if (normal_set){ - if (damping_global == TSUJI){ - double cor = normal_coeffs_global[1]; - damp = 1.2728-4.2783*cor+11.087*pow(cor,2)-22.348*pow(cor,3)+ - 27.467*pow(cor,4)-18.022*pow(cor,5)+ - 4.8218*pow(cor,6); - } - else damp = normal_coeffs_global[1]; normal_coeffs[i][i][0] = normal_coeffs_global[0]; normal_coeffs[i][i][1] = damp; - if (normal[i][i] != HOOKE && normal[i][i] != HERTZ){ + if (normal != HOOKE && normal != HERTZ){ normal_coeffs[i][i][2] = normal_coeffs_global[2]; } - if ((normal_global == JKR) || (normal_global == DMT)) + if ((normal == JKR) || (normal == DMT)) normal_coeffs[i][i][3] = normal_coeffs_global[3]; } if(tangential_set){ - tangential[i][i] = tangential_global; for (int k = 0; k < 3; k++) tangential_coeffs[i][i][k] = tangential_coeffs_global[k]; } - roll[i][i] = roll_global; - if (roll_global != ROLL_NONE) + if (roll != ROLL_NONE) for (int k = 0; k < 3; k++) roll_coeffs[i][i][k] = roll_coeffs_global[k]; - twist[i][i] = twist_global; - if (twist_global != TWIST_NONE && twist_global != TWIST_MARSHALL) + if (twist != TWIST_NONE && twist != TWIST_MARSHALL) for (int k = 0; k < 3; k++) twist_coeffs[i][i][k] = twist_coeffs_global[k]; @@ -866,7 +1567,7 @@ void PairGranular::settings(int narg, char **arg) void PairGranular::coeff(int narg, char **arg) { - int normal_local, damping_local, tangential_local, roll_local, twist_local; + int normal_set, damping_set, tangential_set, roll_set, twist_set; double *normal_coeffs_local; double *tangential_coeffs_local; double *roll_coeffs_local; @@ -886,78 +1587,83 @@ void PairGranular::coeff(int narg, char **arg) force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); - normal_local = tangential_local = roll_local = twist_local = -1; - damping_local = -1; + normal_set = damping_set = tangential_set = roll_set = twist_set = 0; int iarg = 2; while (iarg < narg){ if (strcmp(arg[iarg], "hooke") == 0){ if (iarg + 2 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hooke option"); - normal_local = HOOKE; + if (normal != HOOKE) error->all(FLERR, "Illegal pair_coeff command, choice of normal contact model must be consistent"); normal_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1]); //kn normal_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //damping + normal_set = 1; iarg += 3; } else if (strcmp(arg[iarg], "hertz") == 0){ int num_coeffs = 2; if (iarg + num_coeffs >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hertz option"); - normal_local = HERTZ; + if (normal != HERTZ) if (normal != HOOKE) error->all(FLERR, "Illegal pair_coeff command, choice of normal contact model must be consistent"); normal_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1]); //kn normal_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //damping + normal_set = 1; iarg += num_coeffs+1; } else if (strcmp(arg[iarg], "hertz/material") == 0){ int num_coeffs = 3; if (iarg + num_coeffs >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hertz option"); - normal_local = HERTZ; + if (normal != HERTZ) if (normal != HOOKE) error->all(FLERR, "Illegal pair_coeff command, choice of normal contact model must be consistent"); normal_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1])*FOURTHIRDS; //E normal_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //damping normal_coeffs_local[2] = force->numeric(FLERR,arg[iarg+3]); //G + normal_set = 1; iarg += num_coeffs+1; } else if (strcmp(arg[iarg], "dmt") == 0){ if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hertz option"); - normal_local = DMT; + if (normal != DMT) if (normal != HERTZ) if (normal != HOOKE) error->all(FLERR, "Illegal pair_coeff command, choice of normal contact model must be consistent"); normal_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1])*FOURTHIRDS; //E normal_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //damping normal_coeffs_local[2] = force->numeric(FLERR,arg[iarg+3]); //G normal_coeffs_local[3] = force->numeric(FLERR,arg[iarg+3]); //cohesion + normal_set = 1; iarg += 5; } else if (strcmp(arg[iarg], "jkr") == 0){ if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for JKR option"); beyond_contact = 1; - normal_local = JKR; + if (normal != JKR) if (normal != HERTZ) if (normal != HOOKE) error->all(FLERR, "Illegal pair_coeff command, choice of normal contact model must be consistent"); normal_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1]); //E normal_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //damping normal_coeffs_local[2] = force->numeric(FLERR,arg[iarg+3]); //G normal_coeffs_local[3] = force->numeric(FLERR,arg[iarg+4]); //cohesion + normal_set = 1; iarg += 5; } else if (strcmp(arg[iarg], "damp_velocity") == 0){ - damping_local = VELOCITY; + if (damping != VELOCITY) error->all(FLERR, "Illegal pair_coeff command, choice of damping contact model must be consistent"); iarg += 1; } else if (strcmp(arg[iarg], "damp_viscoelastic") == 0){ - damping_local = VISCOELASTIC; + if (damping != VISCOELASTIC) error->all(FLERR, "Illegal pair_coeff command, choice of damping contact model must be consistent"); iarg += 1; } else if (strcmp(arg[iarg], "damp_tsuji") == 0){ - damping_local = TSUJI; + if (damping != TSUJI) error->all(FLERR, "Illegal pair_coeff command, choice of damping contact model must be consistent"); iarg += 1; } else if (strstr(arg[iarg], "tangential") != NULL){ if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for tangential model"); if (strstr(arg[iarg+1], "nohistory") != NULL){ - tangential_local = TANGENTIAL_NOHISTORY; + if (tangential != TANGENTIAL_NOHISTORY) error->all(FLERR, "Illegal pair_coeff command, choice of tangential contact model must be consistent"); } else if (strstr(arg[iarg+1], "mindlin") != NULL){ - tangential_local = TANGENTIAL_MINDLIN; + if (tangential != TANGENTIAL_MINDLIN) error->all(FLERR, "Illegal pair_coeff command, choice of tangential contact model must be consistent");; tangential_history = 1; } else{ error->all(FLERR, "Illegal pair_coeff command, tangential model not recognized"); } + tangential_set = 1; tangential_coeffs_local[0] = force->numeric(FLERR,arg[iarg+2]); //kt tangential_coeffs_local[1] = force->numeric(FLERR,arg[iarg+3]); //gammat tangential_coeffs_local[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. @@ -966,21 +1672,22 @@ void PairGranular::coeff(int narg, char **arg) else if (strstr(arg[iarg], "rolling") != NULL){ if (iarg + 1 >= narg) error->all(FLERR, "Illegal pair_coeff command, not enough parameters"); if (strstr(arg[iarg+1], "none") != NULL){ - roll_local = ROLL_NONE; + if (roll != ROLL_NONE) error->all(FLERR, "Illegal pair_coeff command, choice of rolling friction model must be consistent"); iarg += 2; } else{ if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for rolling model"); if (strstr(arg[iarg+1], "nohistory") != NULL){ - roll_local = ROLL_NOHISTORY; + if (roll != ROLL_NOHISTORY) error->all(FLERR, "Illegal pair_coeff command, choice of rolling friction model must be consistent"); } else if (strstr(arg[iarg+1], "sds") != NULL){ - roll_local = ROLL_SDS; + if (roll != ROLL_SDS) error->all(FLERR, "Illegal pair_coeff command, choice of rolling friction model must be consistent"); roll_history = 1; } else{ error->all(FLERR, "Illegal pair_coeff command, rolling friction model not recognized"); } + roll_set =1 ; roll_coeffs_local[0] = force->numeric(FLERR,arg[iarg+2]); //kt roll_coeffs_local[1] = force->numeric(FLERR,arg[iarg+3]); //gammat roll_coeffs_local[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. @@ -990,26 +1697,27 @@ void PairGranular::coeff(int narg, char **arg) else if (strstr(arg[iarg], "twist") != NULL){ if (iarg + 1 >= narg) error->all(FLERR, "Illegal pair_coeff command, not enough parameters"); if (strstr(arg[iarg+1], "none") != NULL){ - twist_local = TWIST_NONE; + if (twist != TWIST_NONE) error->all(FLERR, "Illegal pair_coeff command, choice of twisting friction model must be consistent"); iarg += 2; } else if (strstr(arg[iarg+1], "marshall") != NULL){ - twist_local = TWIST_MARSHALL; + if (twist != TWIST_MARSHALL) error->all(FLERR, "Illegal pair_coeff command, choice of twisting friction model must be consistent"); twist_history = 1; iarg += 2; } else{ if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for twist model"); if (strstr(arg[iarg+1], "nohistory") != NULL){ - twist_local = TWIST_NOHISTORY; + if (twist != TWIST_NOHISTORY) error->all(FLERR, "Illegal pair_coeff command, choice of twisting friction model must be consistent"); } else if (strstr(arg[iarg+1], "sds") != NULL){ - twist_local = TWIST_SDS; + if (twist != TWIST_SDS) error->all(FLERR, "Illegal pair_coeff command, choice of twisting friction model must be consistent"); twist_history = 1; } else{ error->all(FLERR, "Illegal pair_coeff command, twisting friction model not recognized"); } + twist_set = 1; twist_coeffs_local[0] = force->numeric(FLERR,arg[iarg+2]); //kt twist_coeffs_local[1] = force->numeric(FLERR,arg[iarg+3]); //gammat twist_coeffs_local[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. @@ -1021,55 +1729,39 @@ void PairGranular::coeff(int narg, char **arg) int count = 0; double damp; - if (damping_local >= 0){ - if (normal_local == -1) - error->all(FLERR, "Illegal pair_coeff command, must specify normal model when setting damping model"); - if (damping_local == TSUJI){ - double cor; - cor = normal_coeffs_local[1]; - damp = 1.2728-4.2783*cor+11.087*pow(cor,2)-22.348*pow(cor,3)+ - 27.467*pow(cor,4)-18.022*pow(cor,5)+ - 4.8218*pow(cor,6); - } - else damp = normal_coeffs_local[1]; + if (damping == TSUJI){ + double cor; + cor = normal_coeffs_local[1]; + damp = 1.2728-4.2783*cor+11.087*pow(cor,2)-22.348*pow(cor,3)+ + 27.467*pow(cor,4)-18.022*pow(cor,5)+ + 4.8218*pow(cor,6); } + else damp = normal_coeffs_local[1]; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { - if (normal_local >= 0){ - normal[i][j] = normal_local; + if (normal_set){ normal_coeffs[i][j][0] = normal_coeffs_local[0]; - if (damping_local == -1){ - damp = normal_coeffs_global[1]; - } normal_coeffs[i][j][1] = damp; - if (normal_local != HERTZ && normal_local != HOOKE) normal_coeffs[i][j][2] = normal_coeffs_local[2]; - if ((normal_local == JKR) || (normal_local == DMT)) + if (normal != HERTZ && normal != HOOKE) normal_coeffs[i][j][2] = normal_coeffs_local[2]; + if ((normal == JKR) || (normal == DMT)) normal_coeffs[i][j][3] = normal_coeffs_local[3]; } - if (damping_local >= 0){ - damping[i][j] = damping_local; - } - if (tangential_local >= 0){ - tangential[i][j] = tangential_local; + if (tangential_set){ for (int k = 0; k < 3; k++) tangential_coeffs[i][j][k] = tangential_coeffs_local[k]; } - if (roll_local >= 0){ - roll[i][j] = roll_local; - if (roll_local != ROLL_NONE) + if (roll_set){ + if (roll != ROLL_NONE) for (int k = 0; k < 3; k++) roll_coeffs[i][j][k] = roll_coeffs_local[k]; } - if (twist_local >= 0){ - twist[i][j] = twist_local; - if (twist_local != TWIST_NONE && twist_local != TWIST_MARSHALL) + if (twist_set){ + if (twist != TWIST_NONE && twist != TWIST_MARSHALL) for (int k = 0; k < 3; k++) twist_coeffs[i][j][k] = twist_coeffs_local[k]; } - - if (normal_local >= 0 && tangential_local >= 0) setflag[i][j] = 1; - + setflag[i][j] = 1; count++; } } @@ -1101,9 +1793,7 @@ void PairGranular::init_style() use_history = tangential_history || roll_history || twist_history; //For JKR, will need fix/neigh/history to keep track of touch arrays - for (int i = 1; i <= atom->ntypes; i++) - for (int j = 1; j <= atom->ntypes; j++) - if (normal[i][j] == JKR) use_history = 1; + if (normal == JKR) use_history = 1; size_history = 3*tangential_history + 3*roll_history + twist_history; @@ -1181,13 +1871,13 @@ void PairGranular::init_style() if (ipour >= 0) { itype = i; double radmax = *((double *) modify->fix[ipour]->extract("radius",itype)); - if (normal[itype][itype] == JKR) radmax = radmax + 0.5*pulloff_distance(radmax, itype); + if (normal == JKR) radmax = radmax - 0.5*pulloff_distance(radmax, itype); onerad_dynamic[i] = radmax; } if (idep >= 0) { itype = i; double radmax = *((double *) modify->fix[idep]->extract("radius",itype)); - if (normal[itype][itype] == JKR) radmax = radmax + 0.5*pulloff_distance(radmax, itype); + if (normal == JKR) radmax = radmax - 0.5*pulloff_distance(radmax, itype); onerad_dynamic[i] = radmax; } } @@ -1199,8 +1889,8 @@ void PairGranular::init_style() for (i = 0; i < nlocal; i++){ double radius_cut = radius[i]; - if (normal[type[i]][type[i]] == JKR){ - radius_cut = radius[i] + 0.5*pulloff_distance(radius[i], type[i]); + if (normal == JKR){ + radius_cut = radius[i] - 0.5*pulloff_distance(radius[i], type[i]); } if (mask[i] & freeze_group_bit){ onerad_frozen[type[i]] = MAX(onerad_frozen[type[i]],radius_cut); @@ -1232,18 +1922,8 @@ double PairGranular::init_one(int i, int j) { double cutoff; if (setflag[i][j] == 0) { - if ((normal[i] != normal[j]) || - (damping[i] != damping[j]) || - (tangential[i] != tangential[j]) || - (roll[i] != roll[j]) || - (twist[i] != twist[j])){ - char str[512]; - sprintf(str,"Granular pair style functional forms are different, cannot mix coefficients for types %d and %d. \nThis combination must be set explicitly via pair_coeff command.",i,j); - error->one(FLERR,str); - } - - if (normal[i][j] != HOOKE && normal[i][j] != HERTZ){ + if (normal != HOOKE && normal != HERTZ){ normal_coeffs[i][j][0] = mix_stiffnessE(normal_coeffs[i][i][0], normal_coeffs[j][j][0], normal_coeffs[i][i][2], normal_coeffs[j][j][2]); normal_coeffs[i][j][2] = mix_stiffnessG(normal_coeffs[i][i][0], normal_coeffs[j][j][0], @@ -1254,19 +1934,19 @@ double PairGranular::init_one(int i, int j) } normal_coeffs[i][j][1] = mix_geom(normal_coeffs[i][i][1], normal_coeffs[j][j][1]); - if ((normal[i][i] == JKR) || (normal[i][i] == DMT)) + if ((normal == JKR) || (normal == DMT)) normal_coeffs[i][j][3] = mix_geom(normal_coeffs[i][i][3], normal_coeffs[j][j][3]); for (int k = 0; k < 3; k++) tangential_coeffs[i][j][k] = mix_geom(tangential_coeffs[i][i][k], tangential_coeffs[j][j][k]); - if (roll[i][i] != ROLL_NONE){ + if (roll != ROLL_NONE){ for (int k = 0; k < 3; k++) roll_coeffs[i][j][k] = mix_geom(roll_coeffs[i][i][k], roll_coeffs[j][j][k]); } - if (twist[i][i] != TWIST_NONE && twist[i][i] != TWIST_MARSHALL){ + if (twist != TWIST_NONE && twist != TWIST_MARSHALL){ for (int k = 0; k < 3; k++) twist_coeffs[i][j][k] = mix_geom(twist_coeffs[i][i][k], twist_coeffs[j][j][k]); } @@ -1305,15 +1985,15 @@ double PairGranular::init_one(int i, int j) void PairGranular::write_restart(FILE *fp) { int i,j; + fwrite(&normal,sizeof(int),1,fp); + fwrite(&damping,sizeof(int),1,fp); + fwrite(&tangential,sizeof(int),1,fp); + fwrite(&roll,sizeof(int),1,fp); + fwrite(&twist,sizeof(int),1,fp); for (i = 1; i <= atom->ntypes; i++) { for (j = i; j <= atom->ntypes; j++) { fwrite(&setflag[i][j],sizeof(int),1,fp); if (setflag[i][j]) { - fwrite(&normal[i][j],sizeof(int),1,fp); - fwrite(&damping[i][j],sizeof(int),1,fp); - fwrite(&tangential[i][j],sizeof(int),1,fp); - fwrite(&roll[i][j],sizeof(int),1,fp); - fwrite(&twist[i][j],sizeof(int),1,fp); fwrite(&normal_coeffs[i][j],sizeof(double),4,fp); fwrite(&tangential_coeffs[i][j],sizeof(double),3,fp); fwrite(&roll_coeffs[i][j],sizeof(double),3,fp); @@ -1333,28 +2013,30 @@ void PairGranular::read_restart(FILE *fp) allocate(); int i,j; int me = comm->me; + if (me == 0){ + fread(&normal,sizeof(int),1,fp); + fread(&damping,sizeof(int),1,fp); + fread(&tangential,sizeof(int),1,fp); + fread(&roll,sizeof(int),1,fp); + fread(&twist,sizeof(int),1,fp); + } + MPI_Bcast(&normal,1,MPI_INT,0,world); + MPI_Bcast(&damping,1,MPI_INT,0,world); + MPI_Bcast(&tangential,1,MPI_INT,0,world); + MPI_Bcast(&roll,1,MPI_INT,0,world); + MPI_Bcast(&twist,1,MPI_INT,0,world); for (i = 1; i <= atom->ntypes; i++) { for (j = i; j <= atom->ntypes; j++) { if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp); MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world); if (setflag[i][j]) { if (me == 0) { - fread(&normal[i][j],sizeof(int),1,fp); - fread(&damping[i][j],sizeof(int),1,fp); - fread(&tangential[i][j],sizeof(int),1,fp); - fread(&roll[i][j],sizeof(int),1,fp); - fread(&twist[i][j],sizeof(int),1,fp); fread(&normal_coeffs[i][j],sizeof(double),4,fp); fread(&tangential_coeffs[i][j],sizeof(double),3,fp); fread(&roll_coeffs[i][j],sizeof(double),3,fp); fread(&twist_coeffs[i][j],sizeof(double),3,fp); fread(&cut[i][j],sizeof(double),1,fp); } - MPI_Bcast(&normal[i][j],1,MPI_INT,0,world); - MPI_Bcast(&damping[i][j],1,MPI_INT,0,world); - MPI_Bcast(&tangential[i][j],1,MPI_INT,0,world); - MPI_Bcast(&roll[i][j],1,MPI_INT,0,world); - MPI_Bcast(&twist[i][j],1,MPI_INT,0,world); MPI_Bcast(&normal_coeffs[i][j],4,MPI_DOUBLE,0,world); MPI_Bcast(&tangential_coeffs[i][j],3,MPI_DOUBLE,0,world); MPI_Bcast(&roll_coeffs[i][j],3,MPI_DOUBLE,0,world); @@ -1380,7 +2062,7 @@ double PairGranular::single(int i, int j, int itype, int jtype, { double radi,radj,radsum; double r,rinv,rsqinv,delx,dely,delz, nx, ny, nz, Reff; - double dR, dR2, sqdR; + double dR, dR2; double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3,wr1,wr2,wr3; double vtr1,vtr2,vtr3,vrel; double mi,mj,meff,damp,ccel,tor1,tor2,tor3; @@ -1421,7 +2103,7 @@ double PairGranular::single(int i, int j, int itype, int jtype, Reff = radi*radj/(radi+radj); bool touchflag; - if (normal[itype][jtype] == JKR){ + if (normal == JKR){ R2 = Reff*Reff; coh = normal_coeffs[itype][jtype][3]; a = cbrt(9.0*M_PI*coh*R2/(4*E)); @@ -1513,7 +2195,7 @@ double PairGranular::single(int i, int j, int itype, int jtype, delta = radsum - r; dR = delta*Reff; - if (normal[itype][jtype] == JKR){ + if (normal == JKR){ dR2 = dR*dR; t0 = coh*coh*R2*R2*E; t1 = PI27SQ*t0; @@ -1529,29 +2211,26 @@ double PairGranular::single(int i, int j, int itype, int jtype, a2 = a*a; knfac = FOURTHIRDS*E*a; Fne = knfac*a2/Reff - TWOPI*a2*sqrt(4*coh*E/(M_PI*a)); - if (damping[itype][jtype] == VISCOELASTIC) sqdR = sqrt(dR); } else{ knfac = E; Fne = knfac*delta; - if (normal[itype][jtype] != HOOKE) - a = sqdR = sqrt(dR); + if (normal != HOOKE) + a = sqrt(dR); Fne *= a; - if (normal[itype][jtype] == DMT) + if (normal == DMT) Fne -= 4*MY_PI*normal_coeffs[itype][jtype][3]*Reff; } //Consider restricting Hooke to only have 'velocity' as an option for damping? - if (damping[itype][jtype] == VELOCITY){ + if (damping == VELOCITY){ damp_normal = normal_coeffs[itype][jtype][1]; } - else if (damping[itype][jtype] == VISCOELASTIC){ - if (normal[itype][jtype] == HOOKE) a = sqdR = sqrt(dR); - - - damp_normal = normal_coeffs[itype][jtype][1]*sqdR*meff; + else if (damping == VISCOELASTIC){ + if (normal == HOOKE) a = sqrt(dR); + damp_normal = normal_coeffs[itype][jtype][1]*a*meff; } - else if (damping[itype][jtype] == TSUJI){ + else if (damping == TSUJI){ damp_normal = normal_coeffs[itype][jtype][1]*sqrt(meff*knfac); } @@ -1594,7 +2273,7 @@ double PairGranular::single(int i, int j, int itype, int jtype, vrel = sqrt(vrel); Fcrit = fabs(Fne); - if (normal[itype][jtype] == JKR){ + if (normal == JKR){ F_pulloff = 3*M_PI*coh*Reff; Fcrit = fabs(Fne + 2*F_pulloff); } @@ -1603,7 +2282,7 @@ double PairGranular::single(int i, int j, int itype, int jtype, //Tangential forces //------------------------------ k_tangential = tangential_coeffs[itype][jtype][0]; - if (normal[itype][jtype] != HOOKE){ + if (normal != HOOKE){ k_tangential *= a; } damp_tangential = tangential_coeffs[itype][jtype][1]*damp_normal; @@ -1644,7 +2323,7 @@ double PairGranular::single(int i, int j, int itype, int jtype, // Rolling resistance //**************************************** - if (roll[itype][jtype] != ROLL_NONE){ + if (roll != ROLL_NONE){ relrot1 = omega[i][0] - omega[j][0]; relrot2 = omega[i][1] - omega[j][1]; relrot3 = omega[i][2] - omega[j][2]; @@ -1705,9 +2384,9 @@ double PairGranular::single(int i, int j, int itype, int jtype, //**************************************** // Twisting torque, including history effects //**************************************** - if (twist[itype][jtype] != TWIST_NONE){ + if (twist != TWIST_NONE){ magtwist = relrot1*nx + relrot2*ny + relrot3*nz; //Omega_T (eq 29 of Marshall) - if (twist[itype][jtype] == TWIST_MARSHALL){ + if (twist == TWIST_MARSHALL){ k_twist = 0.5*k_tangential*a*a;; //eq 32 damp_twist = 0.5*damp_tangential*a*a; mu_twist = TWOTHIRDS*a; diff --git a/src/GRANULAR/pair_granular.h b/src/GRANULAR/pair_granular.h index 0e6f28c514..897316c907 100644 --- a/src/GRANULAR/pair_granular.h +++ b/src/GRANULAR/pair_granular.h @@ -28,7 +28,19 @@ class PairGranular : public Pair { public: PairGranular(class LAMMPS *); virtual ~PairGranular(); - virtual void compute(int, int); + + void compute(int, int); + // comment next line to turn off templating +#define TEMPLATED_PAIR_GRANULAR +#ifdef TEMPLATED_PAIR_GRANULAR + template < int Tp_normal, int Tp_damping, int Tp_tangential, + int Tp_roll, int Tp_twist> + void compute_templated(int, int); +#else + void compute_untemplated(int, int, int, int, int, + int, int); +#endif + virtual void settings(int, char **); virtual void coeff(int, char **); void init_style(); @@ -61,28 +73,27 @@ public: int nmax; // allocated size of mass_rigid virtual void allocate(); - int beyond_contact; - int nondefault_history_transfer; private: int size_history; - //Per-type models - int **normal, **damping, **tangential, **roll, **twist; - - int normal_global, damping_global; - int tangential_global, roll_global, twist_global; + //Models + int normal, damping, tangential, roll, twist; + //History flags int tangential_history, roll_history, twist_history; - int tangential_history_index; - int roll_history_index; - int twist_history_index; + //Indices of history entries + int tangential_history_index, roll_history_index, twist_history_index; + + //Coefficients declared in pair style command, used as default unless + // overwritten in pair coeff command double *normal_coeffs_global; double *tangential_coeffs_global; double *roll_coeffs_global; double *twist_coeffs_global; + //Per-type coefficients declared in pair coeff command double ***normal_coeffs; double ***tangential_coeffs; double ***roll_coeffs; diff --git a/src/GRANULAR/pair_granular_multi.cpp b/src/GRANULAR/pair_granular_multi.cpp new file mode 100644 index 0000000000..11381444a2 --- /dev/null +++ b/src/GRANULAR/pair_granular_multi.cpp @@ -0,0 +1,1837 @@ +/* ---------------------------------------------------------------------- +http://lammps.sandia.gov, Sandia National Laboratories +Steve Plimpton, sjplimp@sandia.gov + +Copyright (2003) Sandia Corporation. Under the terms of Contract +DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains +certain rights in this software. This software is distributed under +the GNU General Public License. + +See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- +Contributing authors: +Dan Bolintineanu (SNL), Ishan Srivastava (SNL), Jeremy Lechman(SNL) +Leo Silbert (SNL), Gary Grest (SNL) +----------------------------------------------------------------------- */ + +#include +#include +#include +#include +#include "pair_granular_multi.h" +#include "atom.h" +#include "atom_vec.h" +#include "domain.h" +#include "force.h" +#include "update.h" +#include "modify.h" +#include "fix.h" +#include "fix_neigh_history.h" +#include "comm.h" +#include "neighbor.h" +#include "neigh_list.h" +#include "neigh_request.h" +#include "memory.h" +#include "error.h" +#include "math_const.h" + +using namespace LAMMPS_NS; +using namespace MathConst; + +#define PI27SQ 266.47931882941264802866 // 27*PI**2 +#define THREEROOT3 5.19615242270663202362 // 3*sqrt(3) +#define SIXROOT6 14.69693845669906728801 // 6*sqrt(6) +#define INVROOT6 0.40824829046386307274 // 1/sqrt(6) +#define FOURTHIRDS 1.333333333333333 // 4/3 +#define TWOPI 6.28318530717959 // 2*PI + +#define EPSILON 1e-10 + +enum {HOOKE, HERTZ, HERTZ_MATERIAL, DMT, JKR}; +enum {VELOCITY, VISCOELASTIC, TSUJI}; +enum {TANGENTIAL_NOHISTORY, TANGENTIAL_MINDLIN}; +enum {TWIST_NONE, TWIST_NOHISTORY, TWIST_SDS, TWIST_MARSHALL}; +enum {ROLL_NONE, ROLL_NOHISTORY, ROLL_SDS}; + +/* ---------------------------------------------------------------------- */ + +PairGranularMulti::PairGranularMulti(LAMMPS *lmp) : Pair(lmp) +{ + single_enable = 1; + no_virial_fdotr_compute = 1; + fix_history = NULL; + + single_extra = 9; + svector = new double[single_extra]; + + neighprev = 0; + + nmax = 0; + mass_rigid = NULL; + + onerad_dynamic = NULL; + onerad_frozen = NULL; + maxrad_dynamic = NULL; + maxrad_frozen = NULL; + + dt = update->dt; + + // set comm size needed by this Pair if used with fix rigid + + comm_forward = 1; + + use_history = 0; + beyond_contact = 0; + nondefault_history_transfer = 0; + tangential_history_index = 0; + roll_history_index = twist_history_index = 0; + +} + +/* ---------------------------------------------------------------------- */ +PairGranularMulti::~PairGranularMulti() +{ + delete [] svector; + if (fix_history) modify->delete_fix("NEIGH_HISTORY"); + + if (allocated) { + memory->destroy(setflag); + memory->destroy(cutsq); + memory->destroy(cut); + + memory->destroy(normal_coeffs); + memory->destroy(tangential_coeffs); + memory->destroy(roll_coeffs); + memory->destroy(twist_coeffs); + + memory->destroy(normal); + memory->destroy(damping); + memory->destroy(tangential); + memory->destroy(roll); + memory->destroy(twist); + + delete [] onerad_dynamic; + delete [] onerad_frozen; + delete [] maxrad_dynamic; + delete [] maxrad_frozen; + } + memory->destroy(mass_rigid); +} + +void PairGranularMulti::compute(int eflag, int vflag) +{ + int i,j,ii,jj,inum,jnum,itype,jtype; + double xtmp,ytmp,ztmp,delx,dely,delz,fx,fy,fz,nx,ny,nz; + double radi,radj,radsum,rsq,r,rinv,rsqinv; + double Reff, delta, dR, dR2; + + double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3; + double wr1,wr2,wr3; + double vtr1,vtr2,vtr3,vrel; + + double knfac, damp_normal; + double k_tangential, damp_tangential; + double Fne, Ft, Fdamp, Fntot, Fcrit, Fscrit, Frcrit; + double fs, fs1, fs2, fs3; + + //For JKR + double R2, coh, F_pulloff, delta_pulloff, dist_pulloff, a, a2, E; + double t0, t1, t2, t3, t4, t5, t6; + double sqrt1, sqrt2, sqrt3, sqrt4; + + double mi,mj,meff,damp,ccel,tor1,tor2,tor3; + double relrot1,relrot2,relrot3,vrl1,vrl2,vrl3,vrlmag,vrlmaginv; + + //Rolling + double k_roll, damp_roll; + double roll1, roll2, roll3, torroll1, torroll2, torroll3; + double rollmag, rolldotn, scalefac; + double fr, fr1, fr2, fr3; + + //Twisting + double k_twist, damp_twist, mu_twist; + double signtwist, magtwist, magtortwist, Mtcrit; + double tortwist1, tortwist2, tortwist3; + + double shrmag,rsht; + int *ilist,*jlist,*numneigh,**firstneigh; + int *touch,**firsttouch; + double *history,*allhistory,**firsthistory; + + bool touchflag; + + if (eflag || vflag) ev_setup(eflag,vflag); + else evflag = vflag_fdotr = 0; + + int historyupdate = 1; + if (update->setupflag) historyupdate = 0; + + // update rigid body info for owned & ghost atoms if using FixRigid masses + // body[i] = which body atom I is in, -1 if none + // mass_body = mass of each rigid body + + if (fix_rigid && neighbor->ago == 0){ + int tmp; + int *body = (int *) fix_rigid->extract("body",tmp); + double *mass_body = (double *) fix_rigid->extract("masstotal",tmp); + if (atom->nmax > nmax) { + memory->destroy(mass_rigid); + nmax = atom->nmax; + memory->create(mass_rigid,nmax,"pair:mass_rigid"); + } + int nlocal = atom->nlocal; + for (i = 0; i < nlocal; i++) + if (body[i] >= 0) mass_rigid[i] = mass_body[body[i]]; + else mass_rigid[i] = 0.0; + comm->forward_comm_pair(this); + } + + double **x = atom->x; + double **v = atom->v; + double **f = atom->f; + int *type = atom->type; + double **omega = atom->omega; + double **torque = atom->torque; + double *radius = atom->radius; + double *rmass = atom->rmass; + int *mask = atom->mask; + int nlocal = atom->nlocal; + int newton_pair = force->newton_pair; + + inum = list->inum; + ilist = list->ilist; + numneigh = list->numneigh; + firstneigh = list->firstneigh; + firsttouch = fix_history->firstflag; + firsthistory = fix_history->firstvalue; + + for (ii = 0; ii < inum; ii++) { + i = ilist[ii]; + itype = type[i]; + xtmp = x[i][0]; + ytmp = x[i][1]; + ztmp = x[i][2]; + itype = type[i]; + radi = radius[i]; + touch = firsttouch[i]; + allhistory = firsthistory[i]; + jlist = firstneigh[i]; + jnum = numneigh[i]; + + for (jj = 0; jj < jnum; jj++){ + j = jlist[jj]; + j &= NEIGHMASK; + + delx = xtmp - x[j][0]; + dely = ytmp - x[j][1]; + delz = ztmp - x[j][2]; + jtype = type[j]; + rsq = delx*delx + dely*dely + delz*delz; + radj = radius[j]; + radsum = radi + radj; + + E = normal_coeffs[itype][jtype][0]; + Reff = radi*radj/(radi+radj); + touchflag = false; + + if (normal[itype][jtype] == JKR){ + if (touch[jj]){ + R2 = Reff*Reff; + coh = normal_coeffs[itype][jtype][3]; + a = cbrt(9.0*M_PI*coh*R2/(4*E)); + delta_pulloff = a*a/Reff - 2*sqrt(M_PI*coh*a/E); + dist_pulloff = radsum-delta_pulloff; + touchflag = (rsq < dist_pulloff*dist_pulloff); + } + else{ + touchflag = (rsq < radsum*radsum); + } + } + else{ + touchflag = (rsq < radsum*radsum); + } + + if (!touchflag){ + // unset non-touching neighbors + touch[jj] = 0; + history = &allhistory[size_history*jj]; + for (int k = 0; k < size_history; k++) history[k] = 0.0; + } + else{ + r = sqrt(rsq); + rinv = 1.0/r; + + nx = delx*rinv; + ny = dely*rinv; + nz = delz*rinv; + + // relative translational velocity + + vr1 = v[i][0] - v[j][0]; + vr2 = v[i][1] - v[j][1]; + vr3 = v[i][2] - v[j][2]; + + // normal component + + vnnr = vr1*nx + vr2*ny + vr3*nz; //v_R . n + vn1 = nx*vnnr; + vn2 = ny*vnnr; + vn3 = nz*vnnr; + + // meff = effective mass of pair of particles + // if I or J part of rigid body, use body mass + // if I or J is frozen, meff is other particle + + mi = rmass[i]; + mj = rmass[j]; + if (fix_rigid) { + if (mass_rigid[i] > 0.0) mi = mass_rigid[i]; + if (mass_rigid[j] > 0.0) mj = mass_rigid[j]; + } + + meff = mi*mj / (mi+mj); + if (mask[i] & freeze_group_bit) meff = mj; + if (mask[j] & freeze_group_bit) meff = mi; + + delta = radsum - r; + dR = delta*Reff; + if (normal[itype][jtype] == JKR){ + touch[jj] = 1; + R2=Reff*Reff; + coh = normal_coeffs[itype][jtype][3]; + dR2 = dR*dR; + t0 = coh*coh*R2*R2*E; + t1 = PI27SQ*t0; + t2 = 8*dR*dR2*E*E*E; + t3 = 4*dR2*E; + sqrt1 = MAX(0, t0*(t1+2*t2)); //In case of sqrt(0) < 0 due to precision issues + t4 = cbrt(t1+t2+THREEROOT3*M_PI*sqrt(sqrt1)); + t5 = t3/t4 + t4/E; + sqrt2 = MAX(0, 2*dR + t5); + t6 = sqrt(sqrt2); + sqrt3 = MAX(0, 4*dR - t5 + SIXROOT6*coh*M_PI*R2/(E*t6)); + a = INVROOT6*(t6 + sqrt(sqrt3)); + a2 = a*a; + knfac = FOURTHIRDS*E*a; + Fne = knfac*a2/Reff - TWOPI*a2*sqrt(4*coh*E/(M_PI*a)); + } + else{ + knfac = E; //Hooke + Fne = knfac*delta; + if (normal[itype][jtype] != HOOKE) + a = sqrt(dR); + Fne *= a; + if (normal[itype][jtype] == DMT) + Fne -= 4*MY_PI*normal_coeffs[itype][jtype][3]*Reff; + } + + //Consider restricting Hooke to only have 'velocity' as an option for damping? + if (damping[itype][jtype] == VELOCITY){ + damp_normal = normal_coeffs[itype][jtype][1]; + } + else if (damping[itype][jtype] == VISCOELASTIC){ + if (normal[itype][jtype] == HOOKE) a = sqrt(dR); + damp_normal = normal_coeffs[itype][jtype][1]*a*meff; + } + else if (damping[itype][jtype] == TSUJI){ + damp_normal = normal_coeffs[itype][jtype][1]*sqrt(meff*knfac); + } + + Fdamp = -damp_normal*vnnr; + + Fntot = Fne + Fdamp; + + //**************************************** + //Tangential force, including history effects + //**************************************** + + // tangential component + vt1 = vr1 - vn1; + vt2 = vr2 - vn2; + vt3 = vr3 - vn3; + + // relative rotational velocity + wr1 = (radi*omega[i][0] + radj*omega[j][0]); + wr2 = (radi*omega[i][1] + radj*omega[j][1]); + wr3 = (radi*omega[i][2] + radj*omega[j][2]); + + // relative tangential velocities + vtr1 = vt1 - (nz*wr2-ny*wr3); + vtr2 = vt2 - (nx*wr3-nz*wr1); + vtr3 = vt3 - (ny*wr1-nx*wr2); + vrel = vtr1*vtr1 + vtr2*vtr2 + vtr3*vtr3; + vrel = sqrt(vrel); + + // If any history is needed: + if (use_history){ + touch[jj] = 1; + history = &allhistory[size_history*jj]; + } + + if (normal[itype][jtype] == JKR){ + F_pulloff = 3*M_PI*coh*Reff; + Fcrit = fabs(Fne + 2*F_pulloff); + } + else{ + Fcrit = fabs(Fne); + } + + //------------------------------ + //Tangential forces + //------------------------------ + k_tangential = tangential_coeffs[itype][jtype][0]; + damp_tangential = tangential_coeffs[itype][jtype][1]*damp_normal; + + if (tangential_history){ + shrmag = sqrt(history[0]*history[0] + history[1]*history[1] + + history[2]*history[2]); + + // Rotate and update displacements. + // See e.g. eq. 17 of Luding, Gran. Matter 2008, v10,p235 + if (historyupdate) { + rsht = history[0]*nx + history[1]*ny + history[2]*nz; + if (fabs(rsht) < EPSILON) rsht = 0; + if (rsht > 0){ + scalefac = shrmag/(shrmag - rsht); //if rhst == shrmag, contacting pair has rotated 90 deg. in one step, in which case you deserve a crash! + history[0] -= rsht*nx; + history[1] -= rsht*ny; + history[2] -= rsht*nz; + //Also rescale to preserve magnitude + history[0] *= scalefac; + history[1] *= scalefac; + history[2] *= scalefac; + } + //Update history + history[0] += vtr1*dt; + history[1] += vtr2*dt; + history[2] += vtr3*dt; + } + + // tangential forces = history + tangential velocity damping + fs1 = -k_tangential*history[0] - damp_tangential*vtr1; + fs2 = -k_tangential*history[1] - damp_tangential*vtr2; + fs3 = -k_tangential*history[2] - damp_tangential*vtr3; + + // rescale frictional displacements and forces if needed + Fscrit = tangential_coeffs[itype][jtype][2] * Fcrit; + fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); + if (fs > Fscrit) { + if (shrmag != 0.0) { + history[0] = -1.0/k_tangential*(Fscrit*fs1/fs + damp_tangential*vtr1); + history[1] = -1.0/k_tangential*(Fscrit*fs2/fs + damp_tangential*vtr2); + history[2] = -1.0/k_tangential*(Fscrit*fs3/fs + damp_tangential*vtr3); + fs1 *= Fscrit/fs; + fs2 *= Fscrit/fs; + fs3 *= Fscrit/fs; + } else fs1 = fs2 = fs3 = 0.0; + } + } + else{ //Classic pair gran/hooke (no history) + fs = meff*damp_tangential*vrel; + if (vrel != 0.0) Ft = MIN(Fne,fs) / vrel; + else Ft = 0.0; + fs1 = -Ft*vtr1; + fs2 = -Ft*vtr2; + fs3 = -Ft*vtr3; + } + + //**************************************** + // Rolling resistance + //**************************************** + + if (roll[itype][jtype] != ROLL_NONE){ + relrot1 = omega[i][0] - omega[j][0]; + relrot2 = omega[i][1] - omega[j][1]; + relrot3 = omega[i][2] - omega[j][2]; + + // rolling velocity, see eq. 31 of Wang et al, Particuology v 23, p 49 (2015) + // This is different from the Marshall papers, which use the Bagi/Kuhn formulation + // for rolling velocity (see Wang et al for why the latter is wrong) + vrl1 = Reff*(relrot2*nz - relrot3*ny); //- 0.5*((radj-radi)/radsum)*vtr1; + vrl2 = Reff*(relrot3*nx - relrot1*nz); //- 0.5*((radj-radi)/radsum)*vtr2; + vrl3 = Reff*(relrot1*ny - relrot2*nx); //- 0.5*((radj-radi)/radsum)*vtr3; + vrlmag = sqrt(vrl1*vrl1+vrl2*vrl2+vrl3*vrl3); + if (vrlmag != 0.0) vrlmaginv = 1.0/vrlmag; + else vrlmaginv = 0.0; + + if (roll_history){ + int rhist0 = roll_history_index; + int rhist1 = rhist0 + 1; + int rhist2 = rhist1 + 1; + + // Rolling displacement + rollmag = sqrt(history[rhist0]*history[rhist0] + + history[rhist1]*history[rhist1] + + history[rhist2]*history[rhist2]); + + rolldotn = history[rhist0]*nx + history[rhist1]*ny + history[rhist2]*nz; + + if (historyupdate){ + if (fabs(rolldotn) < EPSILON) rolldotn = 0; + if (rolldotn > 0){ //Rotate into tangential plane + scalefac = rollmag/(rollmag - rolldotn); + history[rhist0] -= rolldotn*nx; + history[rhist1] -= rolldotn*ny; + history[rhist2] -= rolldotn*nz; + //Also rescale to preserve magnitude + history[rhist0] *= scalefac; + history[rhist1] *= scalefac; + history[rhist2] *= scalefac; + } + history[rhist0] += vrl1*dt; + history[rhist1] += vrl2*dt; + history[rhist2] += vrl3*dt; + } + + + k_roll = roll_coeffs[itype][jtype][0]; + damp_roll = roll_coeffs[itype][jtype][1]; + fr1 = -k_roll*history[rhist0] - damp_roll*vrl1; + fr2 = -k_roll*history[rhist1] - damp_roll*vrl2; + fr3 = -k_roll*history[rhist2] - damp_roll*vrl3; + + // rescale frictional displacements and forces if needed + Frcrit = roll_coeffs[itype][jtype][2] * Fcrit; + + fr = sqrt(fr1*fr1 + fr2*fr2 + fr3*fr3); + if (fr > Frcrit) { + if (rollmag != 0.0) { + history[rhist0] = -1.0/k_roll*(Frcrit*fr1/fr + damp_roll*vrl1); + history[rhist1] = -1.0/k_roll*(Frcrit*fr2/fr + damp_roll*vrl2); + history[rhist2] = -1.0/k_roll*(Frcrit*fr3/fr + damp_roll*vrl3); + fr1 *= Frcrit/fr; + fr2 *= Frcrit/fr; + fr3 *= Frcrit/fr; + } else fr1 = fr2 = fr3 = 0.0; + } + } + else{ // + fr = meff*roll_coeffs[itype][jtype][1]*vrlmag; + if (vrlmag != 0.0) fr = MIN(Fne, fr) / vrlmag; + else fr = 0.0; + fr1 = -fr*vrl1; + fr2 = -fr*vrl2; + fr3 = -fr*vrl3; + } + } + + //**************************************** + // Twisting torque, including history effects + //**************************************** + if (twist[itype][jtype] != TWIST_NONE){ + magtwist = relrot1*nx + relrot2*ny + relrot3*nz; //Omega_T (eq 29 of Marshall) + if (twist[itype][jtype] == TWIST_MARSHALL){ + k_twist = 0.5*k_tangential*a*a;; //eq 32 + damp_twist = 0.5*damp_tangential*a*a; + mu_twist = TWOTHIRDS*a; + } + else{ + k_twist = twist_coeffs[itype][jtype][0]; + damp_twist = twist_coeffs[itype][jtype][1]; + mu_twist = twist_coeffs[itype][jtype][2]; + } + if (twist[itype][jtype] > 1){ + if (historyupdate){ + history[twist_history_index] += magtwist*dt; + } + magtortwist = -k_twist*history[twist_history_index] - damp_twist*magtwist;//M_t torque (eq 30) + signtwist = (magtwist > 0) - (magtwist < 0); + Mtcrit = TWOTHIRDS*a*Fscrit;//critical torque (eq 44) + if (fabs(magtortwist) > Mtcrit) { + history[twist_history_index] = 1.0/k_twist*(Mtcrit*signtwist - damp_twist*magtwist); + magtortwist = -Mtcrit * signtwist; //eq 34 + } + } + else{ + if (magtwist > 0) magtortwist = -damp_twist*magtwist; + else magtortwist = 0; + } + } + // Apply forces & torques + + fx = nx*Fntot + fs1; + fy = ny*Fntot + fs2; + fz = nz*Fntot + fs3; + + f[i][0] += fx; + f[i][1] += fy; + f[i][2] += fz; + + tor1 = ny*fs3 - nz*fs2; + tor2 = nz*fs1 - nx*fs3; + tor3 = nx*fs2 - ny*fs1; + + torque[i][0] -= radi*tor1; + torque[i][1] -= radi*tor2; + torque[i][2] -= radi*tor3; + + if (twist[itype][jtype] != TWIST_NONE){ + tortwist1 = magtortwist * nx; + tortwist2 = magtortwist * ny; + tortwist3 = magtortwist * nz; + + torque[i][0] += tortwist1; + torque[i][1] += tortwist2; + torque[i][2] += tortwist3; + } + + if (roll[itype][jtype] != ROLL_NONE){ + torroll1 = Reff*(ny*fr3 - nz*fr2); //n cross fr + torroll2 = Reff*(nz*fr1 - nx*fr3); + torroll3 = Reff*(nx*fr2 - ny*fr1); + + torque[i][0] += torroll1; + torque[i][1] += torroll2; + torque[i][2] += torroll3; + } + + if (force->newton_pair || j < nlocal) { + f[j][0] -= fx; + f[j][1] -= fy; + f[j][2] -= fz; + + torque[j][0] -= radj*tor1; + torque[j][1] -= radj*tor2; + torque[j][2] -= radj*tor3; + + if (twist[itype][jtype] != TWIST_NONE){ + torque[j][0] -= tortwist1; + torque[j][1] -= tortwist2; + torque[j][2] -= tortwist3; + } + if (roll[itype][jtype] != ROLL_NONE){ + torque[j][0] -= torroll1; + torque[j][1] -= torroll2; + torque[j][2] -= torroll3; + } + } + if (evflag) ev_tally_xyz(i,j,nlocal,0, + 0.0,0.0,fx,fy,fz,delx,dely,delz); + } + } + } +} + + +/* ---------------------------------------------------------------------- +allocate all arrays +------------------------------------------------------------------------- */ + +void PairGranularMulti::allocate() +{ + allocated = 1; + int n = atom->ntypes; + + memory->create(setflag,n+1,n+1,"pair:setflag"); + for (int i = 1; i <= n; i++) + for (int j = i; j <= n; j++) + setflag[i][j] = 0; + + memory->create(cutsq,n+1,n+1,"pair:cutsq"); + memory->create(cut,n+1,n+1,"pair:cut"); + memory->create(normal_coeffs,n+1,n+1,4,"pair:normal_coeffs"); + memory->create(tangential_coeffs,n+1,n+1,3,"pair:tangential_coeffs"); + memory->create(roll_coeffs,n+1,n+1,3,"pair:roll_coeffs"); + memory->create(twist_coeffs,n+1,n+1,3,"pair:twist_coeffs"); + + memory->create(normal,n+1,n+1,"pair:normal"); + memory->create(damping,n+1,n+1,"pair:damping"); + memory->create(tangential,n+1,n+1,"pair:tangential"); + memory->create(roll,n+1,n+1,"pair:roll"); + memory->create(twist,n+1,n+1,"pair:twist"); + + onerad_dynamic = new double[n+1]; + onerad_frozen = new double[n+1]; + maxrad_dynamic = new double[n+1]; + maxrad_frozen = new double[n+1]; +} + +/* ---------------------------------------------------------------------- + global settings +------------------------------------------------------------------------- */ + +void PairGranularMulti::settings(int narg, char **arg) +{ + if (narg < 5) error->all(FLERR,"Illegal pair_style command"); + + int iarg = 0; + + //Some defaults + normal_global = HERTZ; + damping_global = VISCOELASTIC; + tangential_global = TANGENTIAL_MINDLIN; + roll_global = ROLL_NONE; + twist_global = TWIST_NONE; + + tangential_history = 1; + roll_history = twist_history = 0; + + int normal_set, tangential_set; + normal_set = tangential_set = 0; + + while (iarg < narg){ + if (strcmp(arg[iarg], "hooke") == 0){ + if (iarg + 2 >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for Hooke option"); + normal_global = HOOKE; + normal_set = 1; + memory->create(normal_coeffs_global, 2, "pair:normal_coeffs_global"); + normal_coeffs_global[0] = force->numeric(FLERR,arg[iarg+1]); //kn + normal_coeffs_global[1] = force->numeric(FLERR,arg[iarg+2]); //damping + iarg += 3; + } + else if (strcmp(arg[iarg], "hertz") == 0){ + int num_coeffs = 2; + if (iarg + num_coeffs >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for Hertz option"); + normal_global = HERTZ; + normal_set = 1; + memory->create(normal_coeffs_global, num_coeffs, "pair:normal_coeffs_global"); + normal_coeffs_global[0] = force->numeric(FLERR,arg[iarg+1]); //kn + normal_coeffs_global[1] = force->numeric(FLERR,arg[iarg+2]); //damping + iarg += num_coeffs+1; + } + else if (strcmp(arg[iarg], "hertz/material") == 0){ + int num_coeffs = 3; + if (iarg + num_coeffs >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for Hertz option"); + normal_global = HERTZ_MATERIAL; + normal_set = 1; + memory->create(normal_coeffs_global, num_coeffs, "pair:normal_coeffs_global"); + normal_coeffs_global[0] = force->numeric(FLERR,arg[iarg+1])*FOURTHIRDS; //E (Young's modulus) + normal_coeffs_global[1] = force->numeric(FLERR,arg[iarg+2]); //damping + normal_coeffs_global[2] = force->numeric(FLERR,arg[iarg+3]); //G (shear modulus) + iarg += num_coeffs+1; + } + else if (strcmp(arg[iarg], "dmt") == 0){ + if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for Hertz option"); + normal_global = DMT; + normal_set = 1; + memory->create(normal_coeffs_global, 4, "pair:normal_coeffs_global"); + normal_coeffs_global[0] = force->numeric(FLERR,arg[iarg+1])*FOURTHIRDS; //4/3 E + normal_coeffs_global[1] = force->numeric(FLERR,arg[iarg+2]); //damping + normal_coeffs_global[2] = force->numeric(FLERR,arg[iarg+3]); //G + normal_coeffs_global[3] = force->numeric(FLERR,arg[iarg+3]); //cohesion + iarg += 5; + } + else if (strcmp(arg[iarg], "jkr") == 0){ + if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for JKR option"); + beyond_contact = 1; + normal_global = JKR; + normal_set = 1; + memory->create(normal_coeffs_global, 4, "pair:normal_coeffs_global"); + normal_coeffs_global[0] = force->numeric(FLERR,arg[iarg+1]); //E + normal_coeffs_global[1] = force->numeric(FLERR,arg[iarg+2]); //damping + normal_coeffs_global[2] = force->numeric(FLERR,arg[iarg+3]); //G + normal_coeffs_global[3] = force->numeric(FLERR,arg[iarg+4]); //cohesion + iarg += 5; + } + else if (strcmp(arg[iarg], "damp_velocity") == 0){ + damping_global = VELOCITY; + iarg += 1; + } + else if (strcmp(arg[iarg], "damp_viscoelastic") == 0){ + damping_global = VISCOELASTIC; + iarg += 1; + } + else if (strcmp(arg[iarg], "damp_tsuji") == 0){ + damping_global = TSUJI; + iarg += 1; + } + else if (strstr(arg[iarg], "tangential") != NULL){ + if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for tangential model"); + if (strstr(arg[iarg+1], "nohistory") != NULL){ + tangential_global = TANGENTIAL_NOHISTORY; + tangential_set = 1; + } + else if (strstr(arg[iarg+1], "mindlin") != NULL){ + tangential_global = TANGENTIAL_MINDLIN; + tangential_history = 1; + tangential_set = 1; + } + else{ + error->all(FLERR, "Illegal pair_style command, unrecognized sliding friction model"); + } + memory->create(tangential_coeffs_global, 3, "pair:tangential_coeffs_global"); + tangential_coeffs_global[0] = force->numeric(FLERR,arg[iarg+2]); //kt + tangential_coeffs_global[1] = force->numeric(FLERR,arg[iarg+3]); //gammat + tangential_coeffs_global[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. + iarg += 5; + } + else if (strstr(arg[iarg], "roll") != NULL){ + if (strstr(arg[iarg+1], "none") != NULL){ + roll_global = ROLL_NONE; + iarg += 2; + } + else{ + if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for rolling model"); + if (strstr(arg[iarg+1], "nohistory") != NULL){ + roll_global = ROLL_NOHISTORY; + } + else if (strstr(arg[iarg+1], "sds") != NULL){ + roll_global = ROLL_SDS; + roll_history = 1; + } + else{ + error->all(FLERR, "Illegal pair_style command, unrecognized rolling friction model"); + } + memory->create(roll_coeffs_global, 3, "pair:roll_coeffs_global"); + roll_coeffs_global[0] = force->numeric(FLERR,arg[iarg+2]); //kR + roll_coeffs_global[1] = force->numeric(FLERR,arg[iarg+3]); //gammaR + roll_coeffs_global[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. + iarg += 5; + } + } + else if (strstr(arg[iarg], "twist") != NULL){ + if (strstr(arg[iarg+1], "none") != NULL){ + twist_global = TWIST_NONE; + iarg += 2; + } + else if (strstr(arg[iarg+1], "marshall") != NULL){ + twist_global = TWIST_MARSHALL; + twist_history = 1; + iarg += 2; + } + else{ + if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for twist model"); + memory->create(twist_coeffs_global, 3, "pair:twist_coeffs_global"); //To be filled later + if (strstr(arg[iarg+1], "nohistory") != NULL){ + twist_global = TWIST_NOHISTORY; + } + else if (strstr(arg[iarg+1], "sds") != NULL){ + twist_global = TWIST_SDS; + twist_history = 1; + } + else{ + error->all(FLERR, "Illegal pair_style command, unrecognized twisting friction model"); + } + memory->create(twist_coeffs_global, 3, "pair:twist_coeffs_global"); + twist_coeffs_global[0] = force->numeric(FLERR,arg[iarg+2]); //ktwist + twist_coeffs_global[1] = force->numeric(FLERR,arg[iarg+3]); //gammatwist + twist_coeffs_global[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. + iarg += 5; + } + } + else error->all(FLERR, "Illegal pair_style granular command"); + } + + //Set all i-i entries, which may be replaced by pair coeff commands + //It may also make sense to consider removing all of the above, and only + // having the option for pair_coeff to set the parameters, similar to most LAMMPS pair styles + // The reason for the current setup is to remain true to existing pair gran/hooke etc. syntax, + // where coeffs are set in the pair_style command, and a pair_coeff * * command is issued. + + //Other option is to have two pair styles, e.g. pair granular and pair granular/multi, + // where granular/multi allows per-type coefficients, pair granular does not (this would also + // allow minor speed-up by templating pair granular) + allocate(); + double damp; + for (int i = 1; i <= atom->ntypes; i++){ + normal[i][i] = normal_global; + damping[i][i] = damping_global; + tangential[i][i] = tangential_global; + roll[i][i] = roll_global; + twist[i][i] = twist_global; + + if (normal_set){ + if (damping_global == TSUJI){ + double cor = normal_coeffs_global[1]; + damp = 1.2728-4.2783*cor+11.087*pow(cor,2)-22.348*pow(cor,3)+ + 27.467*pow(cor,4)-18.022*pow(cor,5)+ + 4.8218*pow(cor,6); + } + else damp = normal_coeffs_global[1]; + normal_coeffs[i][i][0] = normal_coeffs_global[0]; + normal_coeffs[i][i][1] = damp; + if (normal[i][i] != HOOKE && normal[i][i] != HERTZ){ + normal_coeffs[i][i][2] = normal_coeffs_global[2]; + } + if ((normal_global == JKR) || (normal_global == DMT)) + normal_coeffs[i][i][3] = normal_coeffs_global[3]; + } + if(tangential_set){ + tangential[i][i] = tangential_global; + for (int k = 0; k < 3; k++) + tangential_coeffs[i][i][k] = tangential_coeffs_global[k]; + } + roll[i][i] = roll_global; + if (roll_global != ROLL_NONE) + for (int k = 0; k < 3; k++) + roll_coeffs[i][i][k] = roll_coeffs_global[k]; + + twist[i][i] = twist_global; + if (twist_global != TWIST_NONE && twist_global != TWIST_MARSHALL) + for (int k = 0; k < 3; k++) + twist_coeffs[i][i][k] = twist_coeffs_global[k]; + + if (normal_set && tangential_set) setflag[i][i] = 1; + } +} + +/* ---------------------------------------------------------------------- + set coeffs for one or more type pairs +------------------------------------------------------------------------- */ + +void PairGranularMulti::coeff(int narg, char **arg) +{ + int normal_local, damping_local, tangential_local, roll_local, twist_local; + double *normal_coeffs_local; + double *tangential_coeffs_local; + double *roll_coeffs_local; + double *twist_coeffs_local; + + normal_coeffs_local = new double[4]; + tangential_coeffs_local = new double[4]; + roll_coeffs_local = new double[4]; + twist_coeffs_local = new double[4]; + + if (narg < 2) + error->all(FLERR,"Incorrect args for pair coefficients"); + + if (!allocated) allocate(); + + int ilo,ihi,jlo,jhi; + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); + + normal_local = tangential_local = roll_local = twist_local = -1; + damping_local = -1; + + int iarg = 2; + while (iarg < narg){ + if (strcmp(arg[iarg], "hooke") == 0){ + if (iarg + 2 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hooke option"); + normal_local = HOOKE; + normal_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1]); //kn + normal_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //damping + iarg += 3; + } + else if (strcmp(arg[iarg], "hertz") == 0){ + int num_coeffs = 2; + if (iarg + num_coeffs >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hertz option"); + normal_local = HERTZ; + normal_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1]); //kn + normal_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //damping + iarg += num_coeffs+1; + } + else if (strcmp(arg[iarg], "hertz/material") == 0){ + int num_coeffs = 3; + if (iarg + num_coeffs >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hertz option"); + normal_local = HERTZ; + normal_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1])*FOURTHIRDS; //E + normal_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //damping + normal_coeffs_local[2] = force->numeric(FLERR,arg[iarg+3]); //G + iarg += num_coeffs+1; + } + else if (strcmp(arg[iarg], "dmt") == 0){ + if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hertz option"); + normal_local = DMT; + normal_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1])*FOURTHIRDS; //E + normal_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //damping + normal_coeffs_local[2] = force->numeric(FLERR,arg[iarg+3]); //G + normal_coeffs_local[3] = force->numeric(FLERR,arg[iarg+3]); //cohesion + iarg += 5; + } + else if (strcmp(arg[iarg], "jkr") == 0){ + if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for JKR option"); + beyond_contact = 1; + normal_local = JKR; + normal_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1]); //E + normal_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //damping + normal_coeffs_local[2] = force->numeric(FLERR,arg[iarg+3]); //G + normal_coeffs_local[3] = force->numeric(FLERR,arg[iarg+4]); //cohesion + iarg += 5; + } + else if (strcmp(arg[iarg], "damp_velocity") == 0){ + damping_local = VELOCITY; + iarg += 1; + } + else if (strcmp(arg[iarg], "damp_viscoelastic") == 0){ + damping_local = VISCOELASTIC; + iarg += 1; + } + else if (strcmp(arg[iarg], "damp_tsuji") == 0){ + damping_local = TSUJI; + iarg += 1; + } + else if (strstr(arg[iarg], "tangential") != NULL){ + if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for tangential model"); + if (strstr(arg[iarg+1], "nohistory") != NULL){ + tangential_local = TANGENTIAL_NOHISTORY; + } + else if (strstr(arg[iarg+1], "mindlin") != NULL){ + tangential_local = TANGENTIAL_MINDLIN; + tangential_history = 1; + } + else{ + error->all(FLERR, "Illegal pair_coeff command, tangential model not recognized"); + } + tangential_coeffs_local[0] = force->numeric(FLERR,arg[iarg+2]); //kt + tangential_coeffs_local[1] = force->numeric(FLERR,arg[iarg+3]); //gammat + tangential_coeffs_local[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. + iarg += 5; + } + else if (strstr(arg[iarg], "rolling") != NULL){ + if (iarg + 1 >= narg) error->all(FLERR, "Illegal pair_coeff command, not enough parameters"); + if (strstr(arg[iarg+1], "none") != NULL){ + roll_local = ROLL_NONE; + iarg += 2; + } + else{ + if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for rolling model"); + if (strstr(arg[iarg+1], "nohistory") != NULL){ + roll_local = ROLL_NOHISTORY; + } + else if (strstr(arg[iarg+1], "sds") != NULL){ + roll_local = ROLL_SDS; + roll_history = 1; + } + else{ + error->all(FLERR, "Illegal pair_coeff command, rolling friction model not recognized"); + } + roll_coeffs_local[0] = force->numeric(FLERR,arg[iarg+2]); //kt + roll_coeffs_local[1] = force->numeric(FLERR,arg[iarg+3]); //gammat + roll_coeffs_local[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. + iarg += 5; + } + } + else if (strstr(arg[iarg], "twist") != NULL){ + if (iarg + 1 >= narg) error->all(FLERR, "Illegal pair_coeff command, not enough parameters"); + if (strstr(arg[iarg+1], "none") != NULL){ + twist_local = TWIST_NONE; + iarg += 2; + } + else if (strstr(arg[iarg+1], "marshall") != NULL){ + twist_local = TWIST_MARSHALL; + twist_history = 1; + iarg += 2; + } + else{ + if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for twist model"); + if (strstr(arg[iarg+1], "nohistory") != NULL){ + twist_local = TWIST_NOHISTORY; + } + else if (strstr(arg[iarg+1], "sds") != NULL){ + twist_local = TWIST_SDS; + twist_history = 1; + } + else{ + error->all(FLERR, "Illegal pair_coeff command, twisting friction model not recognized"); + } + twist_coeffs_local[0] = force->numeric(FLERR,arg[iarg+2]); //kt + twist_coeffs_local[1] = force->numeric(FLERR,arg[iarg+3]); //gammat + twist_coeffs_local[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. + iarg += 5; + } + } + else error->all(FLERR, "Illegal pair coeff command"); + } + + int count = 0; + double damp; + if (damping_local >= 0){ + if (normal_local == -1) + error->all(FLERR, "Illegal pair_coeff command, must specify normal model when setting damping model"); + if (damping_local == TSUJI){ + double cor; + cor = normal_coeffs_local[1]; + damp = 1.2728-4.2783*cor+11.087*pow(cor,2)-22.348*pow(cor,3)+ + 27.467*pow(cor,4)-18.022*pow(cor,5)+ + 4.8218*pow(cor,6); + } + else damp = normal_coeffs_local[1]; + } + + for (int i = ilo; i <= ihi; i++) { + for (int j = MAX(jlo,i); j <= jhi; j++) { + if (normal_local >= 0){ + normal[i][j] = normal_local; + normal_coeffs[i][j][0] = normal_coeffs_local[0]; + if (damping_local == -1){ + damp = normal_coeffs_global[1]; + } + normal_coeffs[i][j][1] = damp; + if (normal_local != HERTZ && normal_local != HOOKE) normal_coeffs[i][j][2] = normal_coeffs_local[2]; + if ((normal_local == JKR) || (normal_local == DMT)) + normal_coeffs[i][j][3] = normal_coeffs_local[3]; + } + if (damping_local >= 0){ + damping[i][j] = damping_local; + } + if (tangential_local >= 0){ + tangential[i][j] = tangential_local; + for (int k = 0; k < 3; k++) + tangential_coeffs[i][j][k] = tangential_coeffs_local[k]; + } + if (roll_local >= 0){ + roll[i][j] = roll_local; + if (roll_local != ROLL_NONE) + for (int k = 0; k < 3; k++) + roll_coeffs[i][j][k] = roll_coeffs_local[k]; + } + if (twist_local >= 0){ + twist[i][j] = twist_local; + if (twist_local != TWIST_NONE && twist_local != TWIST_MARSHALL) + for (int k = 0; k < 3; k++) + twist_coeffs[i][j][k] = twist_coeffs_local[k]; + } + + if (normal_local >= 0 && tangential_local >= 0) setflag[i][j] = 1; + + count++; + } + } + + delete[] normal_coeffs_local; + delete[] tangential_coeffs_local; + delete[] roll_coeffs_local; + delete[] twist_coeffs_local; + + if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); +} + +/* ---------------------------------------------------------------------- + init specific to this pair style +------------------------------------------------------------------------- */ + +void PairGranularMulti::init_style() +{ + int i; + + // error and warning checks + + if (!atom->radius_flag || !atom->rmass_flag) + error->all(FLERR,"Pair granular requires atom attributes radius, rmass"); + if (comm->ghost_velocity == 0) + error->all(FLERR,"Pair granular requires ghost atoms store velocity"); + + // Determine whether we need a granular neigh list, how large it needs to be + use_history = tangential_history || roll_history || twist_history; + + //For JKR, will need fix/neigh/history to keep track of touch arrays + for (int i = 1; i <= atom->ntypes; i++) + for (int j = 1; j <= atom->ntypes; j++) + if (normal[i][j] == JKR) use_history = 1; + + size_history = 3*tangential_history + 3*roll_history + twist_history; + + //Determine location of tangential/roll/twist histories in array + if (roll_history){ + if (tangential_history) roll_history_index = 3; + else roll_history_index = 0; + } + if (twist_history){ + if (tangential_history){ + if (roll_history) twist_history_index = 6; + else twist_history_index = 3; + } + else{ + if (roll_history) twist_history_index = 3; + else twist_history_index = 0; + } + } + + int irequest = neighbor->request(this,instance_me); + neighbor->requests[irequest]->size = 1; + if (use_history) neighbor->requests[irequest]->history = 1; + + dt = update->dt; + + // if history is stored: + // if first init, create Fix needed for storing history + + if (use_history && fix_history == NULL) { + char dnumstr[16]; + sprintf(dnumstr,"%d",size_history); + char **fixarg = new char*[4]; + fixarg[0] = (char *) "NEIGH_HISTORY"; + fixarg[1] = (char *) "all"; + fixarg[2] = (char *) "NEIGH_HISTORY"; + fixarg[3] = dnumstr; + modify->add_fix(4,fixarg,1); + delete [] fixarg; + fix_history = (FixNeighHistory *) modify->fix[modify->nfix-1]; + fix_history->pair = this; + } + + // check for FixFreeze and set freeze_group_bit + + for (i = 0; i < modify->nfix; i++) + if (strcmp(modify->fix[i]->style,"freeze") == 0) break; + if (i < modify->nfix) freeze_group_bit = modify->fix[i]->groupbit; + else freeze_group_bit = 0; + + // check for FixRigid so can extract rigid body masses + + fix_rigid = NULL; + for (i = 0; i < modify->nfix; i++) + if (modify->fix[i]->rigid_flag) break; + if (i < modify->nfix) fix_rigid = modify->fix[i]; + + // check for FixPour and FixDeposit so can extract particle radii + + int ipour; + for (ipour = 0; ipour < modify->nfix; ipour++) + if (strcmp(modify->fix[ipour]->style,"pour") == 0) break; + if (ipour == modify->nfix) ipour = -1; + + int idep; + for (idep = 0; idep < modify->nfix; idep++) + if (strcmp(modify->fix[idep]->style,"deposit") == 0) break; + if (idep == modify->nfix) idep = -1; + + // set maxrad_dynamic and maxrad_frozen for each type + // include future FixPour and FixDeposit particles as dynamic + + int itype; + for (i = 1; i <= atom->ntypes; i++) { + onerad_dynamic[i] = onerad_frozen[i] = 0.0; + if (ipour >= 0) { + itype = i; + double radmax = *((double *) modify->fix[ipour]->extract("radius",itype)); + if (normal[itype][itype] == JKR) radmax = radmax - 0.5*pulloff_distance(radmax, itype); + onerad_dynamic[i] = radmax; + } + if (idep >= 0) { + itype = i; + double radmax = *((double *) modify->fix[idep]->extract("radius",itype)); + if (normal[itype][itype] == JKR) radmax = radmax - 0.5*pulloff_distance(radmax, itype); + onerad_dynamic[i] = radmax; + } + } + + double *radius = atom->radius; + int *mask = atom->mask; + int *type = atom->type; + int nlocal = atom->nlocal; + + for (i = 0; i < nlocal; i++){ + double radius_cut = radius[i]; + if (normal[type[i]][type[i]] == JKR){ + radius_cut = radius[i] - 0.5*pulloff_distance(radius[i], type[i]); + } + if (mask[i] & freeze_group_bit){ + onerad_frozen[type[i]] = MAX(onerad_frozen[type[i]],radius_cut); + } + else{ + onerad_dynamic[type[i]] = MAX(onerad_dynamic[type[i]],radius_cut); + } + } + + MPI_Allreduce(&onerad_dynamic[1],&maxrad_dynamic[1],atom->ntypes, + MPI_DOUBLE,MPI_MAX,world); + MPI_Allreduce(&onerad_frozen[1],&maxrad_frozen[1],atom->ntypes, + MPI_DOUBLE,MPI_MAX,world); + + // set fix which stores history info + + if (size_history > 0){ + int ifix = modify->find_fix("NEIGH_HISTORY"); + if (ifix < 0) error->all(FLERR,"Could not find pair fix neigh history ID"); + fix_history = (FixNeighHistory *) modify->fix[ifix]; + } +} + +/* ---------------------------------------------------------------------- + init for one type pair i,j and corresponding j,i +------------------------------------------------------------------------- */ + +double PairGranularMulti::init_one(int i, int j) +{ + double cutoff; + if (setflag[i][j] == 0) { + if ((normal[i][i] != normal[j][j]) || + (damping[i][i] != damping[j][j]) || + (tangential[i][i] != tangential[j][j]) || + (roll[i][i] != roll[j][j]) || + (twist[i][i] != twist[j][j])){ + + char str[512]; + sprintf(str,"Granular pair style functional forms are different, cannot mix coefficients for types %d and %d. \nThis combination must be set explicitly via pair_coeff command.",i,j); + error->one(FLERR,str); + } + + if (normal[i][j] != HOOKE && normal[i][j] != HERTZ){ + normal_coeffs[i][j][0] = mix_stiffnessE(normal_coeffs[i][i][0], normal_coeffs[j][j][0], + normal_coeffs[i][i][2], normal_coeffs[j][j][2]); + normal_coeffs[i][j][2] = mix_stiffnessG(normal_coeffs[i][i][0], normal_coeffs[j][j][0], + normal_coeffs[i][i][2], normal_coeffs[j][j][2]); + } + else{ + normal_coeffs[i][j][0] = mix_geom(normal_coeffs[i][i][0], normal_coeffs[j][j][0]); + } + + normal_coeffs[i][j][1] = mix_geom(normal_coeffs[i][i][1], normal_coeffs[j][j][1]); + if ((normal[i][i] == JKR) || (normal[i][i] == DMT)) + normal_coeffs[i][j][3] = mix_geom(normal_coeffs[i][i][3], normal_coeffs[j][j][3]); + + for (int k = 0; k < 3; k++) + tangential_coeffs[i][j][k] = mix_geom(tangential_coeffs[i][i][k], tangential_coeffs[j][j][k]); + + + if (roll[i][i] != ROLL_NONE){ + for (int k = 0; k < 3; k++) + roll_coeffs[i][j][k] = mix_geom(roll_coeffs[i][i][k], roll_coeffs[j][j][k]); + } + + if (twist[i][i] != TWIST_NONE && twist[i][i] != TWIST_MARSHALL){ + for (int k = 0; k < 3; k++) + twist_coeffs[i][j][k] = mix_geom(twist_coeffs[i][i][k], twist_coeffs[j][j][k]); + } + } + + // It is possible that cut[i][j] at this point is still 0.0. This can happen when + // there is a future fix_pour after the current run. A cut[i][j] = 0.0 creates + // problems because neighbor.cpp uses min(cut[i][j]) to decide on the bin size + // To avoid this issue, for cases involving cut[i][j] = 0.0 (possible only + // if there is no current information about radius/cutoff of type i and j). + // we assign cutoff = max(cut[i][j]) for i,j such that cut[i][j] > 0.0. + + if (((maxrad_dynamic[i] > 0.0) && (maxrad_dynamic[j] > 0.0)) || + ((maxrad_dynamic[i] > 0.0) && (maxrad_frozen[j] > 0.0)) || + ((maxrad_frozen[i] > 0.0) && (maxrad_dynamic[j] > 0.0))) { // radius info about both i and j exist + cutoff = maxrad_dynamic[i]+maxrad_dynamic[j]; + cutoff = MAX(cutoff,maxrad_frozen[i]+maxrad_dynamic[j]); + cutoff = MAX(cutoff,maxrad_dynamic[i]+maxrad_frozen[j]); + } + else { // radius info about either i or j does not exist (i.e. not present and not about to get poured; set to largest value to not interfere with neighbor list) + double cutmax = 0.0; + for (int k = 1; k <= atom->ntypes; k++) { + cutmax = MAX(cutmax,2.0*maxrad_dynamic[k]); + cutmax = MAX(cutmax,2.0*maxrad_frozen[k]); + } + cutoff = cutmax; + } + return cutoff; +} + + +/* ---------------------------------------------------------------------- + proc 0 writes to restart file + ------------------------------------------------------------------------- */ + +void PairGranularMulti::write_restart(FILE *fp) +{ + int i,j; + for (i = 1; i <= atom->ntypes; i++) { + for (j = i; j <= atom->ntypes; j++) { + fwrite(&setflag[i][j],sizeof(int),1,fp); + if (setflag[i][j]) { + fwrite(&normal[i][j],sizeof(int),1,fp); + fwrite(&damping[i][j],sizeof(int),1,fp); + fwrite(&tangential[i][j],sizeof(int),1,fp); + fwrite(&roll[i][j],sizeof(int),1,fp); + fwrite(&twist[i][j],sizeof(int),1,fp); + fwrite(&normal_coeffs[i][j],sizeof(double),4,fp); + fwrite(&tangential_coeffs[i][j],sizeof(double),3,fp); + fwrite(&roll_coeffs[i][j],sizeof(double),3,fp); + fwrite(&twist_coeffs[i][j],sizeof(double),3,fp); + fwrite(&cut[i][j],sizeof(double),1,fp); + } + } + } +} + +/* ---------------------------------------------------------------------- + proc 0 reads from restart file, bcasts + ------------------------------------------------------------------------- */ + +void PairGranularMulti::read_restart(FILE *fp) +{ + allocate(); + int i,j; + int me = comm->me; + for (i = 1; i <= atom->ntypes; i++) { + for (j = i; j <= atom->ntypes; j++) { + if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp); + MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world); + if (setflag[i][j]) { + if (me == 0) { + fread(&normal[i][j],sizeof(int),1,fp); + fread(&damping[i][j],sizeof(int),1,fp); + fread(&tangential[i][j],sizeof(int),1,fp); + fread(&roll[i][j],sizeof(int),1,fp); + fread(&twist[i][j],sizeof(int),1,fp); + fread(&normal_coeffs[i][j],sizeof(double),4,fp); + fread(&tangential_coeffs[i][j],sizeof(double),3,fp); + fread(&roll_coeffs[i][j],sizeof(double),3,fp); + fread(&twist_coeffs[i][j],sizeof(double),3,fp); + fread(&cut[i][j],sizeof(double),1,fp); + } + MPI_Bcast(&normal[i][j],1,MPI_INT,0,world); + MPI_Bcast(&damping[i][j],1,MPI_INT,0,world); + MPI_Bcast(&tangential[i][j],1,MPI_INT,0,world); + MPI_Bcast(&roll[i][j],1,MPI_INT,0,world); + MPI_Bcast(&twist[i][j],1,MPI_INT,0,world); + MPI_Bcast(&normal_coeffs[i][j],4,MPI_DOUBLE,0,world); + MPI_Bcast(&tangential_coeffs[i][j],3,MPI_DOUBLE,0,world); + MPI_Bcast(&roll_coeffs[i][j],3,MPI_DOUBLE,0,world); + MPI_Bcast(&twist_coeffs[i][j],3,MPI_DOUBLE,0,world); + MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); + } + } + } +} + + +/* ---------------------------------------------------------------------- */ + +void PairGranularMulti::reset_dt() +{ + dt = update->dt; +} + +/* ---------------------------------------------------------------------- */ + +double PairGranularMulti::single(int i, int j, int itype, int jtype, + double rsq, double factor_coul, double factor_lj, double &fforce) +{ + double radi,radj,radsum; + double r,rinv,rsqinv,delx,dely,delz, nx, ny, nz, Reff; + double dR, dR2; + double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3,wr1,wr2,wr3; + double vtr1,vtr2,vtr3,vrel; + double mi,mj,meff,damp,ccel,tor1,tor2,tor3; + double relrot1,relrot2,relrot3,vrl1,vrl2,vrl3,vrlmag,vrlmaginv; + + double knfac, damp_normal; + double k_tangential, damp_tangential; + double Fne, Ft, Fdamp, Fntot, Fcrit, Fscrit, Frcrit; + double fs, fs1, fs2, fs3; + + //For JKR + double R2, coh, F_pulloff, delta_pulloff, dist_pulloff, a, a2, E; + double delta, t0, t1, t2, t3, t4, t5, t6; + double sqrt1, sqrt2, sqrt3, sqrt4; + + + //Rolling + double k_roll, damp_roll; + double roll1, roll2, roll3, torroll1, torroll2, torroll3; + double rollmag, rolldotn, scalefac; + double fr, fr1, fr2, fr3; + + //Twisting + double k_twist, damp_twist, mu_twist; + double signtwist, magtwist, magtortwist, Mtcrit; + double tortwist1, tortwist2, tortwist3; + + double shrmag,rsht; + int jnum; + int *ilist,*jlist,*numneigh,**firstneigh; + int *touch,**firsttouch; + double *history,*allhistory,**firsthistory; + + double *radius = atom->radius; + radi = radius[i]; + radj = radius[j]; + radsum = radi + radj; + Reff = radi*radj/(radi+radj); + + bool touchflag; + if (normal[itype][jtype] == JKR){ + R2 = Reff*Reff; + coh = normal_coeffs[itype][jtype][3]; + a = cbrt(9.0*M_PI*coh*R2/(4*E)); + delta_pulloff = a*a/Reff - 2*sqrt(M_PI*coh*a/E); + dist_pulloff = radsum+delta_pulloff; + touchflag = (rsq <= dist_pulloff*dist_pulloff); + } + else{ + touchflag = (rsq <= radsum*radsum); + } + + if (touchflag){ + fforce = 0.0; + for (int m = 0; m < single_extra; m++) svector[m] = 0.0; + return 0.0; + } + + double **x = atom->x; + delx = x[i][0] - x[j][0]; + dely = x[i][1] - x[j][1]; + delz = x[i][2] - x[j][2]; + r = sqrt(rsq); + rinv = 1.0/r; + + nx = delx*rinv; + ny = dely*rinv; + nz = delz*rinv; + + // relative translational velocity + + double **v = atom->v; + vr1 = v[i][0] - v[j][0]; + vr2 = v[i][1] - v[j][1]; + vr3 = v[i][2] - v[j][2]; + + // normal component + + vnnr = vr1*nx + vr2*ny + vr3*nz; + vn1 = nx*vnnr; + vn2 = ny*vnnr; + vn3 = nz*vnnr; + + double *rmass = atom->rmass; + int *mask = atom->mask; + mi = rmass[i]; + mj = rmass[j]; + if (fix_rigid) { + if (mass_rigid[i] > 0.0) mi = mass_rigid[i]; + if (mass_rigid[j] > 0.0) mj = mass_rigid[j]; + } + + meff = mi*mj / (mi+mj); + if (mask[i] & freeze_group_bit) meff = mj; + if (mask[j] & freeze_group_bit) meff = mi; + + delta = radsum - r; + dR = delta*Reff; + + // tangential component + + vt1 = vr1 - vn1; + vt2 = vr2 - vn2; + vt3 = vr3 - vn3; + + // relative rotational velocity + + double **omega = atom->omega; + wr1 = (radi*omega[i][0] + radj*omega[j][0]); + wr2 = (radi*omega[i][1] + radj*omega[j][1]); + wr3 = (radi*omega[i][2] + radj*omega[j][2]); + + // meff = effective mass of pair of particles + // if I or J part of rigid body, use body mass + // if I or J is frozen, meff is other particle + + int *type = atom->type; + + mi = rmass[i]; + mj = rmass[j]; + if (fix_rigid) { + // NOTE: ensure mass_rigid is current for owned+ghost atoms? + if (mass_rigid[i] > 0.0) mi = mass_rigid[i]; + if (mass_rigid[j] > 0.0) mj = mass_rigid[j]; + } + + meff = mi*mj / (mi+mj); + if (mask[i] & freeze_group_bit) meff = mj; + if (mask[j] & freeze_group_bit) meff = mi; + + delta = radsum - r; + dR = delta*Reff; + if (normal[itype][jtype] == JKR){ + dR2 = dR*dR; + t0 = coh*coh*R2*R2*E; + t1 = PI27SQ*t0; + t2 = 8*dR*dR2*E*E*E; + t3 = 4*dR2*E; + sqrt1 = MAX(0, t0*(t1+2*t2)); //In case of sqrt(0) < 0 due to precision issues + t4 = cbrt(t1+t2+THREEROOT3*M_PI*sqrt(sqrt1)); + t5 = t3/t4 + t4/E; + sqrt2 = MAX(0, 2*dR + t5); + t6 = sqrt(sqrt2); + sqrt3 = MAX(0, 4*dR - t5 + SIXROOT6*coh*M_PI*R2/(E*t6)); + a = INVROOT6*(t6 + sqrt(sqrt3)); + a2 = a*a; + knfac = FOURTHIRDS*E*a; + Fne = knfac*a2/Reff - TWOPI*a2*sqrt(4*coh*E/(M_PI*a)); + } + else{ + knfac = E; + Fne = knfac*delta; + if (normal[itype][jtype] != HOOKE) + a = sqrt(dR); + Fne *= a; + if (normal[itype][jtype] == DMT) + Fne -= 4*MY_PI*normal_coeffs[itype][jtype][3]*Reff; + } + + //Consider restricting Hooke to only have 'velocity' as an option for damping? + if (damping[itype][jtype] == VELOCITY){ + damp_normal = normal_coeffs[itype][jtype][1]; + } + else if (damping[itype][jtype] == VISCOELASTIC){ + if (normal[itype][jtype] == HOOKE) a = sqrt(dR); + damp_normal = normal_coeffs[itype][jtype][1]*a*meff; + } + else if (damping[itype][jtype] == TSUJI){ + damp_normal = normal_coeffs[itype][jtype][1]*sqrt(meff*knfac); + } + + Fdamp = -damp_normal*vnnr; + + Fntot = Fne + Fdamp; + + jnum = list->numneigh[i]; + jlist = list->firstneigh[i]; + + if (use_history){ + allhistory = fix_history->firstvalue[i]; + for (int jj = 0; jj < jnum; jj++) { + neighprev++; + if (neighprev >= jnum) neighprev = 0; + if (jlist[neighprev] == j) break; + } + history = &allhistory[size_history*neighprev]; + } + + //**************************************** + //Tangential force, including history effects + //**************************************** + + // tangential component + vt1 = vr1 - vn1; + vt2 = vr2 - vn2; + vt3 = vr3 - vn3; + + // relative rotational velocity + wr1 = (radi*omega[i][0] + radj*omega[j][0]); + wr2 = (radi*omega[i][1] + radj*omega[j][1]); + wr3 = (radi*omega[i][2] + radj*omega[j][2]); + + // relative tangential velocities + vtr1 = vt1 - (nz*wr2-ny*wr3); + vtr2 = vt2 - (nx*wr3-nz*wr1); + vtr3 = vt3 - (ny*wr1-nx*wr2); + vrel = vtr1*vtr1 + vtr2*vtr2 + vtr3*vtr3; + vrel = sqrt(vrel); + + if (normal[itype][jtype] == JKR){ + F_pulloff = 3*M_PI*coh*Reff; + Fcrit = fabs(Fne + 2*F_pulloff); + } + else{ + Fcrit = fabs(Fne); + } + + //------------------------------ + //Tangential forces + //------------------------------ + k_tangential = tangential_coeffs[itype][jtype][0]; + if (normal[itype][jtype] != HOOKE){ + k_tangential *= a; + } + damp_tangential = tangential_coeffs[itype][jtype][1]*damp_normal; + + if (tangential_history){ + shrmag = sqrt(history[0]*history[0] + history[1]*history[1] + + history[2]*history[2]); + + // tangential forces = history + tangential velocity damping + fs1 = -k_tangential*history[0] - damp_tangential*vtr1; + fs2 = -k_tangential*history[1] - damp_tangential*vtr2; + fs3 = -k_tangential*history[2] - damp_tangential*vtr3; + + // rescale frictional displacements and forces if needed + Fscrit = tangential_coeffs[itype][jtype][2] * Fcrit; + fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); + if (fs > Fscrit) { + if (shrmag != 0.0) { + history[0] = -1.0/k_tangential*(Fscrit*fs1/fs + damp_tangential*vtr1); + history[1] = -1.0/k_tangential*(Fscrit*fs2/fs + damp_tangential*vtr2); + history[2] = -1.0/k_tangential*(Fscrit*fs3/fs + damp_tangential*vtr3); + fs1 *= Fscrit/fs; + fs2 *= Fscrit/fs; + fs3 *= Fscrit/fs; + } else fs1 = fs2 = fs3 = 0.0; + } + } + else{ //Classic pair gran/hooke (no history) + fs = meff*damp_tangential*vrel; + if (vrel != 0.0) Ft = MIN(Fne,fs) / vrel; + else Ft = 0.0; + fs1 = -Ft*vtr1; + fs2 = -Ft*vtr2; + fs3 = -Ft*vtr3; + } + + //**************************************** + // Rolling resistance + //**************************************** + + if (roll[itype][jtype] != ROLL_NONE){ + relrot1 = omega[i][0] - omega[j][0]; + relrot2 = omega[i][1] - omega[j][1]; + relrot3 = omega[i][2] - omega[j][2]; + + // rolling velocity, see eq. 31 of Wang et al, Particuology v 23, p 49 (2015) + // This is different from the Marshall papers, which use the Bagi/Kuhn formulation + // for rolling velocity (see Wang et al for why the latter is wrong) + vrl1 = Reff*(relrot2*nz - relrot3*ny); //- 0.5*((radj-radi)/radsum)*vtr1; + vrl2 = Reff*(relrot3*nx - relrot1*nz); //- 0.5*((radj-radi)/radsum)*vtr2; + vrl3 = Reff*(relrot1*ny - relrot2*nx); //- 0.5*((radj-radi)/radsum)*vtr3; + vrlmag = sqrt(vrl1*vrl1+vrl2*vrl2+vrl3*vrl3); + if (vrlmag != 0.0) vrlmaginv = 1.0/vrlmag; + else vrlmaginv = 0.0; + + if (roll_history){ + int rhist0 = roll_history_index; + int rhist1 = rhist0 + 1; + int rhist2 = rhist1 + 1; + + // Rolling displacement + rollmag = sqrt(history[rhist0]*history[rhist0] + + history[rhist1]*history[rhist1] + + history[rhist2]*history[rhist2]); + + rolldotn = history[rhist0]*nx + history[rhist1]*ny + history[rhist2]*nz; + + k_roll = roll_coeffs[itype][jtype][0]; + damp_roll = roll_coeffs[itype][jtype][1]; + fr1 = -k_roll*history[rhist0] - damp_roll*vrl1; + fr2 = -k_roll*history[rhist1] - damp_roll*vrl2; + fr3 = -k_roll*history[rhist2] - damp_roll*vrl3; + + // rescale frictional displacements and forces if needed + Frcrit = roll_coeffs[itype][jtype][2] * Fcrit; + + fr = sqrt(fr1*fr1 + fr2*fr2 + fr3*fr3); + if (fr > Frcrit) { + if (rollmag != 0.0) { + history[rhist0] = -1.0/k_roll*(Frcrit*fr1/fr + damp_roll*vrl1); + history[rhist1] = -1.0/k_roll*(Frcrit*fr2/fr + damp_roll*vrl2); + history[rhist2] = -1.0/k_roll*(Frcrit*fr3/fr + damp_roll*vrl3); + fr1 *= Frcrit/fr; + fr2 *= Frcrit/fr; + fr3 *= Frcrit/fr; + } else fr1 = fr2 = fr3 = 0.0; + } + } + else{ // + fr = meff*roll_coeffs[itype][jtype][1]*vrlmag; + if (vrlmag != 0.0) fr = MIN(Fne, fr) / vrlmag; + else fr = 0.0; + fr1 = -fr*vrl1; + fr2 = -fr*vrl2; + fr3 = -fr*vrl3; + } + } + + //**************************************** + // Twisting torque, including history effects + //**************************************** + if (twist[itype][jtype] != TWIST_NONE){ + magtwist = relrot1*nx + relrot2*ny + relrot3*nz; //Omega_T (eq 29 of Marshall) + if (twist[itype][jtype] == TWIST_MARSHALL){ + k_twist = 0.5*k_tangential*a*a;; //eq 32 + damp_twist = 0.5*damp_tangential*a*a; + mu_twist = TWOTHIRDS*a; + } + else{ + k_twist = twist_coeffs[itype][jtype][0]; + damp_twist = twist_coeffs[itype][jtype][1]; + mu_twist = twist_coeffs[itype][jtype][2]; + } + if (twist_history){ + magtortwist = -k_twist*history[twist_history_index] - damp_twist*magtwist;//M_t torque (eq 30) + signtwist = (magtwist > 0) - (magtwist < 0); + Mtcrit = TWOTHIRDS*a*Fscrit;//critical torque (eq 44) + if (fabs(magtortwist) > Mtcrit) { + history[twist_history_index] = 1.0/k_twist*(Mtcrit*signtwist - damp_twist*magtwist); + magtortwist = -Mtcrit * signtwist; //eq 34 + } + } + else{ + if (magtwist > 0) magtortwist = -damp_twist*magtwist; + else magtortwist = 0; + } + } + + // set single_extra quantities + + svector[0] = fs1; + svector[1] = fs2; + svector[2] = fs3; + svector[3] = fs; + svector[4] = fr1; + svector[5] = fr2; + svector[6] = fr3; + svector[7] = fr; + svector[8] = magtortwist; + return 0.0; +} + +/* ---------------------------------------------------------------------- */ + +int PairGranularMulti::pack_forward_comm(int n, int *list, double *buf, + int pbc_flag, int *pbc) +{ + int i,j,m; + + m = 0; + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = mass_rigid[j]; + } + return m; +} + +/* ---------------------------------------------------------------------- */ + +void PairGranularMulti::unpack_forward_comm(int n, int first, double *buf) +{ + int i,m,last; + + m = 0; + last = first + n; + for (i = first; i < last; i++) + mass_rigid[i] = buf[m++]; +} + +/* ---------------------------------------------------------------------- + memory usage of local atom-based arrays + ------------------------------------------------------------------------- */ + +double PairGranularMulti::memory_usage() +{ + double bytes = nmax * sizeof(double); + return bytes; +} + +/* ---------------------------------------------------------------------- + mixing of Young's modulus (E) +------------------------------------------------------------------------- */ + +double PairGranularMulti::mix_stiffnessE(double Eii, double Ejj, double Gii, double Gjj) +{ + double poisii = Eii/(2.0*Gii) - 1.0; + double poisjj = Ejj/(2.0*Gjj) - 1.0; + return 1/((1-poisii*poisjj)/Eii+(1-poisjj*poisjj)/Ejj); +} + +/* ---------------------------------------------------------------------- + mixing of shear modulus (G) + ------------------------------------------------------------------------- */ + +double PairGranularMulti::mix_stiffnessG(double Eii, double Ejj, double Gii, double Gjj) +{ + double poisii = Eii/(2.0*Gii) - 1.0; + double poisjj = Ejj/(2.0*Gjj) - 1.0; + return 1/((2.0 -poisjj)/Gii+(2.0-poisjj)/Gjj); +} + +/* ---------------------------------------------------------------------- + mixing of everything else +------------------------------------------------------------------------- */ + +double PairGranularMulti::mix_geom(double valii, double valjj) +{ + return sqrt(valii*valjj); +} + + +/* ---------------------------------------------------------------------- + Compute pull-off distance (beyond contact) for a given radius and atom type +------------------------------------------------------------------------- */ + +double PairGranularMulti::pulloff_distance(double radius, int itype) +{ + double E, coh, a, delta_pulloff; + coh = normal_coeffs[itype][itype][3]; + E = mix_stiffnessE(normal_coeffs[itype][itype][0], normal_coeffs[itype][itype][0], + normal_coeffs[itype][itype][2], normal_coeffs[itype][itype][2]); + a = cbrt(9*M_PI*coh*radius*radius/(4*E)); + return a*a/radius - 2*sqrt(M_PI*coh*a/E); +} + diff --git a/src/GRANULAR/pair_granular_multi.h b/src/GRANULAR/pair_granular_multi.h new file mode 100644 index 0000000000..e853e564df --- /dev/null +++ b/src/GRANULAR/pair_granular_multi.h @@ -0,0 +1,108 @@ +/* ---------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain 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(granular/multi,PairGranularMulti) + +#else + +#ifndef LMP_PAIR_GRANULAR_MULTI_H +#define LMP_PAIR_GRANULAR_MULTI_H + +#include "pair.h" + +namespace LAMMPS_NS { + +class PairGranularMulti : public Pair { +public: + PairGranularMulti(class LAMMPS *); + virtual ~PairGranularMulti(); + virtual void compute(int, int); + virtual void settings(int, char **); + virtual void coeff(int, char **); + void init_style(); + double init_one(int, int); + void write_restart(FILE *); + void read_restart(FILE *); + void reset_dt(); + virtual double single(int, int, int, int, double, double, double, double &); + int pack_forward_comm(int, int *, double *, int, int *); + void unpack_forward_comm(int, int, double *); + double memory_usage(); + + protected: + double cut_global; + double dt; + int freeze_group_bit; + int use_history; + + int neighprev; + double *onerad_dynamic,*onerad_frozen; + double *maxrad_dynamic,*maxrad_frozen; + double **cut; + + class FixNeighHistory *fix_history; + + // storage of rigid body masses for use in granular interactions + + class Fix *fix_rigid; // ptr to rigid body fix, NULL if none + double *mass_rigid; // rigid mass for owned+ghost atoms + int nmax; // allocated size of mass_rigid + + virtual void allocate(); + +private: + int size_history; + + //Per-type models + int **normal, **damping, **tangential, **roll, **twist; + + int normal_global, damping_global; + int tangential_global, roll_global, twist_global; + + int tangential_history, roll_history, twist_history; + int tangential_history_index; + int roll_history_index; + int twist_history_index; + + double *normal_coeffs_global; + double *tangential_coeffs_global; + double *roll_coeffs_global; + double *twist_coeffs_global; + + double ***normal_coeffs; + double ***tangential_coeffs; + double ***roll_coeffs; + double ***twist_coeffs; + + double mix_stiffnessE(double Eii, double Ejj, double Gii, double Gjj); + double mix_stiffnessG(double Eii, double Ejj, double Gii, double Gjj); + double mix_geom(double valii, double valjj); + double pulloff_distance(double radius, int itype); +}; + +} + +#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. + + */ diff --git a/src/fix_neigh_history.cpp b/src/fix_neigh_history.cpp index c21b494aa4..e33ebe57dc 100644 --- a/src/fix_neigh_history.cpp +++ b/src/fix_neigh_history.cpp @@ -408,7 +408,8 @@ void FixNeighHistory::pre_exchange_newton() m = npartner[j]++; partner[j][m] = tag[i]; jvalues = &valuepartner[j][dnum*m]; - for (n = 0; n < dnum; n++) jvalues[n] = -onevalues[n]; + if (pair->nondefault_history_transfer) pair->transfer_history(onevalues, jvalues); + else for (n = 0; n < dnum; n++) jvalues[n] = -onevalues[n]; } } } @@ -520,7 +521,8 @@ void FixNeighHistory::pre_exchange_no_newton() m = npartner[j]++; partner[j][m] = tag[i]; jvalues = &valuepartner[j][dnum*m]; - for (n = 0; n < dnum; n++) jvalues[n] = -onevalues[n]; + if (pair->nondefault_history_transfer) pair->transfer_history(onevalues, jvalues); + else for (n = 0; n < dnum; n++) jvalues[n] = -onevalues[n]; } } } @@ -604,7 +606,7 @@ void FixNeighHistory::post_neighbor() for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; - rflag = sbmask(j); + rflag = sbmask(j) | pair->beyond_contact; j &= NEIGHMASK; jlist[jj] = j; diff --git a/src/pair.h b/src/pair.h index 27b6d41eef..0911bff706 100644 --- a/src/pair.h +++ b/src/pair.h @@ -98,6 +98,8 @@ class Pair : protected Pointers { enum{GEOMETRIC,ARITHMETIC,SIXTHPOWER}; // mixing options + int beyond_contact, nondefault_history_transfer; //for granular styles + // KOKKOS host/device flag and data masks ExecutionSpace execution_space; @@ -180,6 +182,7 @@ class Pair : protected Pointers { virtual void min_xf_pointers(int, double **, double **) {} virtual void min_xf_get(int) {} virtual void min_x_set(int) {} + virtual void transfer_history(double *, double*) {} // management of callbacks to be run from ev_tally() @@ -202,6 +205,7 @@ class Pair : protected Pointers { double tabinner; // inner cutoff for Coulomb table double tabinner_disp; // inner cutoff for dispersion table + public: // custom data type for accessing Coulomb tables From ef803be08e65999b2b1c657d32ec6187ec774569 Mon Sep 17 00:00:00 2001 From: dsbolin Date: Tue, 15 Jan 2019 10:18:46 -0700 Subject: [PATCH 14/44] Moved all model option syntax for pair granular to pair coeff command; added global cutoff option for pair style granular command; initial write-up of documentation. --- doc/src/pair_granular.txt | 332 +++++++++++++++++++++++ src/GRANULAR/pair_granular.cpp | 392 ++++++++------------------- src/GRANULAR/pair_granular.h | 13 +- src/GRANULAR/pair_granular_multi.cpp | 379 ++++++-------------------- src/GRANULAR/pair_granular_multi.h | 17 +- 5 files changed, 538 insertions(+), 595 deletions(-) create mode 100644 doc/src/pair_granular.txt diff --git a/doc/src/pair_granular.txt b/doc/src/pair_granular.txt new file mode 100644 index 0000000000..19c16cc6ea --- /dev/null +++ b/doc/src/pair_granular.txt @@ -0,0 +1,332 @@ +"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c + +:link(lws,http://lammps.sandia.gov) +:link(ld,Manual.html) +:link(lc,Commands_all.html) + +:line + +pair_style granular command :h3 +pair_style granular/multi command :h3 + +[Syntax:] + +pair_style style cutoff :pre + +style = {granular} or {granular/multi} :ulb,l +cutoff = global cutoff (optional). See discussion below. + +[Examples:] + +pair_style granular +pair coeff 1 1 hertz 1000.0 50.0 tangential mindlin 800.0 50.0 0.5 rolling sds 500.0 200.0 0.5 twisting marshall +pair coeff 2 2 hertz 200.0 20.0 tangential mindlin 300.0 50.0 0.1 rolling sds 200.0 100.0 0.1 twisting marshall + +pair_style granular/multi +pair coeff 1 1 hertz 1000.0 50.0 tangential mindlin 800.0 50.0 0.5 rolling sds 500.0 200.0 0.5 twisting marshall +pair coeff 2 2 dmt 1000.0 50.0 800.0 10.0 tangential mindlin 800.0 50.0 0.1 roll sds 500.0 200.0 0.1 twisting marshall +pair coeff 1 2 dmt 1000.0 50.0 800.0 10.0 tangential mindlin 800.0 50.0 0.1 roll sds 500.0 200.0 0.1 twisting marshall + + +[Description:] + +The {granular} styles support a variety of options for the normal, tangential, rolling and twisting +forces resulting from contact between two granular particles. The computed force depends on the combination +of choices for these models. + +All model options and parameters are entered in the "pair_coeff"_pair_coeff.html command, as described below. +Unlike e.g. "pair gran/hooke"_pair_gran.html, coefficient values are not global, but can be set to different values for +various combinations of particle types, as determined by the "pair_coeff"_pair_coeff.html command. +In the case of {granular}, coefficients +can vary between particle types, but model choices cannot. For instance, in the first +example above, the stiffness, damping, and tangential friction are different for type 1 - type 1 and type 2 - type 2 interactions, but +both 1-1 and 2-2 interactions must have the same model form, hence all keywords are identical between the two types. Cross-coefficients +for 1-2 interactions for the case of the {hertz} model above are set via simple geometric mixing rules. The {granular/multi} +style removes this restriction at a small cost in computational efficiency, so that different particle types +can potentially interact via different model forms. As shown in the second example, +1-1 interactions are based on a Hertzian contact model and 2-2 interactions are based on a {dmt} model (see below). +In the case that 1-1 and 2-2 interactions have different model forms, mixing of coefficients cannot be +determined, so 1-2 interactions must be explicitly defined via the pair coeff command, otherwise an error results. + +The first required keyword for the pair coeff command is the normal contact model. Currently supported options and +the required arguments are: + +{hooke} : k_n, damping +{hertz} : k_n, damping +{hertz/material} : E, damping, G +{dmt} : E, damping, G, cohesion +{jkr} : E, damping, G, cohesion + +Here, k_n is spring stiffness, damping is a damping constant or a coefficient of restitution, depending on +the choice of damping model (see below), E and G are Young's modulus and shear modulus, in units of pressure, +and cohesion is a surface energy density, in units of energy/length^2. + +For the {hooke} model, the normal component of force is given by: +:c,image(Eqs/hooke_normal.jpg) + +For {hertz}, the normal force is given by: +:c,image{Eqs/hertz_normal.jpg} + +For both [hooke] and [hertz], stiffness for unspecified cross-terms is given by simple geometric mixing +(e.g. if stiffness is specified for type 1 and type 2 particles as k_n_1 and k_n_2, respectively, +type 1 - type 2 contacts use a stiffness given by k_n_{12} = sqrt(k_n_1*k_n_2)) + +For {hertz/material}, the form is the same as above, but coefficients are computed differently, and mixing follows +a different rule based on shear modulus: +:c,image{Eqs/hertz_material_normal.jpg} + +For {dmt}, the normal force is given by: +:c,image{Eqs/dmt_normal.jpg} + +Where gamma is cohesion. + +For {jkr}, the normal force is given by: +:c,image{Eqs/jkr_normal.jpg} + +The same mixing rule for stiffness as for {hertz/material} is used by both the {dmt} and {jkr} models. + +The tangential contact model must also be specified, which follows +the required {tangential} keyword. Currently supported options +and their required arguments are: + +{no_history}: k_t, tangential_damping, friction coefficient +{mindlin}: k_t, tangential_damping, friction coefficient + +For {no_history}, the tangential force is computed according to + +The total force on a particle is the sum of the normal and tangential forces from all interactions. The tangential +force also induces a torque on both particles in a contacting pair. Additionally, rolling and twisting friction +models can also be applied, which may induce additional torques (but no force). The following options are +supported for the rolling friction model + + +The first required keyword +in the pair coeff command is the choice +of normal force contact model, for which current opitons are {hooke}, {hertz} + +The {gran} styles use the following formulas for the frictional force +between two granular particles, as described in +"(Brilliantov)"_#Brilliantov, "(Silbert)"_#Silbert, and +"(Zhang)"_#Zhang3, when the distance r between two particles of radii +Ri and Rj is less than their contact distance d = Ri + Rj. There is +no force between the particles when r > d. + +The two Hookean styles use this formula: + +:c,image(Eqs/pair_gran_hooke.jpg) + +The Hertzian style uses this formula: + +:c,image(Eqs/pair_gran_hertz.jpg) + +In both equations the first parenthesized term is the normal force +between the two particles and the second parenthesized term is the +tangential force. The normal force has 2 terms, a contact force and a +damping force. The tangential force also has 2 terms: a shear force +and a damping force. The shear force is a "history" effect that +accounts for the tangential displacement between the particles for the +duration of the time they are in contact. This term is included in +pair styles {hooke/history} and {hertz/history}, but is not included +in pair style {hooke}. The tangential damping force term is included +in all three pair styles if {dampflag} is set to 1; it is not included +if {dampflag} is set to 0. + +The other quantities in the equations are as follows: + +delta = d - r = overlap distance of 2 particles +Kn = elastic constant for normal contact +Kt = elastic constant for tangential contact +gamma_n = viscoelastic damping constant for normal contact +gamma_t = viscoelastic damping constant for tangential contact +m_eff = Mi Mj / (Mi + Mj) = effective mass of 2 particles of mass Mi and Mj +Delta St = tangential displacement vector between 2 particles \ + which is truncated to satisfy a frictional yield criterion +n_ij = unit vector along the line connecting the centers of the 2 particles +Vn = normal component of the relative velocity of the 2 particles +Vt = tangential component of the relative velocity of the 2 particles :ul + +The Kn, Kt, gamma_n, and gamma_t coefficients are specified as +parameters to the pair_style command. If a NULL is used for Kt, then +a default value is used where Kt = 2/7 Kn. If a NULL is used for +gamma_t, then a default value is used where gamma_t = 1/2 gamma_n. + +The interpretation and units for these 4 coefficients are different in +the Hookean versus Hertzian equations. + +The Hookean model is one where the normal push-back force for two +overlapping particles is a linear function of the overlap distance. +Thus the specified Kn is in units of (force/distance). Note that this +push-back force is independent of absolute particle size (in the +monodisperse case) and of the relative sizes of the two particles (in +the polydisperse case). This model also applies to the other terms in +the force equation so that the specified gamma_n is in units of +(1/time), Kt is in units of (force/distance), and gamma_t is in units +of (1/time). + +The Hertzian model is one where the normal push-back force for two +overlapping particles is proportional to the area of overlap of the +two particles, and is thus a non-linear function of overlap distance. +Thus Kn has units of force per area and is thus specified in units of +(pressure). The effects of absolute particle size (monodispersity) +and relative size (polydispersity) are captured in the radii-dependent +pre-factors. When these pre-factors are carried through to the other +terms in the force equation it means that the specified gamma_n is in +units of (1/(time*distance)), Kt is in units of (pressure), and +gamma_t is in units of (1/(time*distance)). + +Note that in the Hookean case, Kn can be thought of as a linear spring +constant with units of force/distance. In the Hertzian case, Kn is +like a non-linear spring constant with units of force/area or +pressure, and as shown in the "(Zhang)"_#Zhang3 paper, Kn = 4G / +(3(1-nu)) where nu = the Poisson ratio, G = shear modulus = E / +(2(1+nu)), and E = Young's modulus. Similarly, Kt = 4G / (2-nu). +(NOTE: in an earlier version of the manual, we incorrectly stated that +Kt = 8G / (2-nu).) + +Thus in the Hertzian case Kn and Kt can be set to values that +corresponds to properties of the material being modeled. This is also +true in the Hookean case, except that a spring constant must be chosen +that is appropriate for the absolute size of particles in the model. +Since relative particle sizes are not accounted for, the Hookean +styles may not be a suitable model for polydisperse systems. + +NOTE: In versions of LAMMPS before 9Jan09, the equation for Hertzian +interactions did not include the sqrt(RiRj/Ri+Rj) term and thus was +not as accurate for polydisperse systems. For monodisperse systems, +sqrt(RiRj/Ri+Rj) is a constant factor that effectively scales all 4 +coefficients: Kn, Kt, gamma_n, gamma_t. Thus you can set the values +of these 4 coefficients appropriately in the current code to reproduce +the results of a previous Hertzian monodisperse calculation. For +example, for the common case of a monodisperse system with particles +of diameter 1, all 4 of these coefficients should now be set 2x larger +than they were previously. + +Xmu is also specified in the pair_style command and is the upper limit +of the tangential force through the Coulomb criterion Ft = xmu*Fn, +where Ft and Fn are the total tangential and normal force components +in the formulas above. Thus in the Hookean case, the tangential force +between 2 particles grows according to a tangential spring and +dash-pot model until Ft/Fn = xmu and is then held at Ft = Fn*xmu until +the particles lose contact. In the Hertzian case, a similar analogy +holds, though the spring is no longer linear. + +NOTE: Normally, xmu should be specified as a fractional value between +0.0 and 1.0, however LAMMPS allows large values (up to 1.0e4) to allow +for modeling of systems which can sustain very large tangential +forces. + +The effective mass {m_eff} is given by the formula above for two +isolated particles. If either particle is part of a rigid body, its +mass is replaced by the mass of the rigid body in the formula above. +This is determined by searching for a "fix rigid"_fix_rigid.html +command (or its variants). + +For granular styles there are no additional coefficients to set for +each pair of atom types via the "pair_coeff"_pair_coeff.html command. +All settings are global and are made via the pair_style command. +However you must still use the "pair_coeff"_pair_coeff.html for all +pairs of granular atom types. For example the command + +pair_coeff * * :pre + +should be used if all atoms in the simulation interact via a granular +potential (i.e. one of the pair styles above is used). If a granular +potential is used as a sub-style of "pair_style +hybrid"_pair_hybrid.html, then specific atom types can be used in the +pair_coeff command to determine which atoms interact via a granular +potential. + +:line + +Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are +functionally the same as the corresponding style without the suffix. +They have been optimized to run faster, depending on your available +hardware, as discussed on the "Speed packages"_Speed_packages.html doc +page. The accelerated styles take the same arguments and should +produce the same results, except for round-off and precision issues. + +These accelerated styles are part of the GPU, USER-INTEL, KOKKOS, +USER-OMP and OPT packages, respectively. They are only enabled if +LAMMPS was built with those packages. See the "Build +package"_Build_package.html doc page for more info. + +You can specify the accelerated styles explicitly in your input script +by including their suffix, or you can use the "-suffix command-line +switch"_Run_options.html when you invoke LAMMPS, or you can use the +"suffix"_suffix.html command in your input script. + +See the "Speed packages"_Speed_packages.html doc page for more +instructions on how to use the accelerated styles effectively. + +:line + +[Mixing, shift, table, tail correction, restart, rRESPA info]: + +The "pair_modify"_pair_modify.html mix, shift, table, and tail options +are not relevant for granular pair styles. + +These pair styles write their information to "binary restart +files"_restart.html, so a pair_style command does not need to be +specified in an input script that reads a restart file. + +These pair styles can only be used via the {pair} keyword of the +"run_style respa"_run_style.html command. They do not support the +{inner}, {middle}, {outer} keywords. + +The single() function of these pair styles returns 0.0 for the energy +of a pairwise interaction, since energy is not conserved in these +dissipative potentials. It also returns only the normal component of +the pairwise interaction force. However, the single() function also +calculates 10 extra pairwise quantities. The first 3 are the +components of the tangential force between particles I and J, acting +on particle I. The 4th is the magnitude of this tangential force. +The next 3 (5-7) are the components of the relative velocity in the +normal direction (along the line joining the 2 sphere centers). The +last 3 (8-10) the components of the relative velocity in the +tangential direction. + +These extra quantities can be accessed by the "compute +pair/local"_compute_pair_local.html command, as {p1}, {p2}, ..., +{p10}. + +:line + +[Restrictions:] + +All the granular pair styles are part of the GRANULAR package. It is +only enabled if LAMMPS was built with that package. See the "Build +package"_Build_package.html doc page for more info. + +These pair styles require that atoms store torque and angular velocity +(omega) as defined by the "atom_style"_atom_style.html. They also +require a per-particle radius is stored. The {sphere} atom style does +all of this. + +This pair style requires you to use the "comm_modify vel +yes"_comm_modify.html command so that velocities are stored by ghost +atoms. + +These pair styles will not restart exactly when using the +"read_restart"_read_restart.html command, though they should provide +statistically similar results. This is because the forces they +compute depend on atom velocities. See the +"read_restart"_read_restart.html command for more details. + +[Related commands:] + +"pair_coeff"_pair_coeff.html + +[Default:] none + +:line + +:link(Brilliantov) +[(Brilliantov)] Brilliantov, Spahn, Hertzsch, Poschel, Phys Rev E, 53, +p 5382-5392 (1996). + +:link(Silbert) +[(Silbert)] Silbert, Ertas, Grest, Halsey, Levine, Plimpton, Phys Rev +E, 64, p 051302 (2001). + +:link(Zhang3) +[(Zhang)] Zhang and Makse, Phys Rev E, 72, p 011301 (2005). diff --git a/src/GRANULAR/pair_granular.cpp b/src/GRANULAR/pair_granular.cpp index c75c80fea5..9fe4bd8415 100644 --- a/src/GRANULAR/pair_granular.cpp +++ b/src/GRANULAR/pair_granular.cpp @@ -1360,205 +1360,15 @@ void PairGranular::allocate() void PairGranular::settings(int narg, char **arg) { - if (narg < 5) error->all(FLERR,"Illegal pair_style command"); - - int iarg = 0; - - //Some defaults - normal = HERTZ; - damping = VISCOELASTIC; - tangential = TANGENTIAL_MINDLIN; - roll = ROLL_NONE; - twist = TWIST_NONE; - - tangential_history = 1; + if (narg == 1){ + cutoff_global = force->numeric(FLERR,arg[0]) + } + else{ + cutoff_global = -1; //Will be set based on particle sizes, model choice + } + tangential_history = 0; roll_history = twist_history = 0; - - int normal_set, tangential_set; - normal_set = tangential_set = 0; - - while (iarg < narg){ - if (strcmp(arg[iarg], "hooke") == 0){ - if (iarg + 2 >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for Hooke option"); - normal = HOOKE; - memory->create(normal_coeffs_global, 2, "pair:normal_coeffs_global"); - normal_coeffs_global[0] = force->numeric(FLERR,arg[iarg+1]); //kn - normal_coeffs_global[1] = force->numeric(FLERR,arg[iarg+2]); //damping - iarg += 3; - } - else if (strcmp(arg[iarg], "hertz") == 0){ - int num_coeffs = 2; - if (iarg + num_coeffs >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for Hertz option"); - normal = HERTZ; - normal_set = 1; - memory->create(normal_coeffs_global, num_coeffs, "pair:normal_coeffs_global"); - normal_coeffs_global[0] = force->numeric(FLERR,arg[iarg+1]); //kn - normal_coeffs_global[1] = force->numeric(FLERR,arg[iarg+2]); //damping - iarg += num_coeffs+1; - } - else if (strcmp(arg[iarg], "hertz/material") == 0){ - int num_coeffs = 3; - if (iarg + num_coeffs >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for Hertz option"); - normal = HERTZ_MATERIAL; - normal_set = 1; - memory->create(normal_coeffs_global, num_coeffs, "pair:normal_coeffs_global"); - normal_coeffs_global[0] = force->numeric(FLERR,arg[iarg+1])*FOURTHIRDS; //E (Young's modulus) - normal_coeffs_global[1] = force->numeric(FLERR,arg[iarg+2]); //damping - normal_coeffs_global[2] = force->numeric(FLERR,arg[iarg+3]); //G (shear modulus) - iarg += num_coeffs+1; - } - else if (strcmp(arg[iarg], "dmt") == 0){ - if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for Hertz option"); - normal = DMT; - normal_set = 1; - memory->create(normal_coeffs_global, 4, "pair:normal_coeffs_global"); - normal_coeffs_global[0] = force->numeric(FLERR,arg[iarg+1])*FOURTHIRDS; //4/3 E - normal_coeffs_global[1] = force->numeric(FLERR,arg[iarg+2]); //damping - normal_coeffs_global[2] = force->numeric(FLERR,arg[iarg+3]); //G - normal_coeffs_global[3] = force->numeric(FLERR,arg[iarg+3]); //cohesion - iarg += 5; - } - else if (strcmp(arg[iarg], "jkr") == 0){ - if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for JKR option"); - beyond_contact = 1; - normal = JKR; - normal_set = 1; - memory->create(normal_coeffs_global, 4, "pair:normal_coeffs_global"); - normal_coeffs_global[0] = force->numeric(FLERR,arg[iarg+1]); //E - normal_coeffs_global[1] = force->numeric(FLERR,arg[iarg+2]); //damping - normal_coeffs_global[2] = force->numeric(FLERR,arg[iarg+3]); //G - normal_coeffs_global[3] = force->numeric(FLERR,arg[iarg+4]); //cohesion - iarg += 5; - } - else if (strcmp(arg[iarg], "damp_velocity") == 0){ - damping = VELOCITY; - iarg += 1; - } - else if (strcmp(arg[iarg], "damp_viscoelastic") == 0){ - damping = VISCOELASTIC; - iarg += 1; - } - else if (strcmp(arg[iarg], "damp_tsuji") == 0){ - damping = TSUJI; - iarg += 1; - } - else if (strstr(arg[iarg], "tangential") != NULL){ - if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for tangential model"); - if (strstr(arg[iarg+1], "nohistory") != NULL){ - tangential = TANGENTIAL_NOHISTORY; - tangential_set = 1; - } - else if (strstr(arg[iarg+1], "mindlin") != NULL){ - tangential = TANGENTIAL_MINDLIN; - tangential_history = 1; - tangential_set = 1; - } - else{ - error->all(FLERR, "Illegal pair_style command, unrecognized sliding friction model"); - } - memory->create(tangential_coeffs_global, 3, "pair:tangential_coeffs_global"); - tangential_coeffs_global[0] = force->numeric(FLERR,arg[iarg+2]); //kt - tangential_coeffs_global[1] = force->numeric(FLERR,arg[iarg+3]); //gammat - tangential_coeffs_global[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. - iarg += 5; - } - else if (strstr(arg[iarg], "roll") != NULL){ - if (strstr(arg[iarg+1], "none") != NULL){ - roll = ROLL_NONE; - iarg += 2; - } - else{ - if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for rolling model"); - if (strstr(arg[iarg+1], "nohistory") != NULL){ - roll = ROLL_NOHISTORY; - } - else if (strstr(arg[iarg+1], "sds") != NULL){ - roll = ROLL_SDS; - roll_history = 1; - } - else{ - error->all(FLERR, "Illegal pair_style command, unrecognized rolling friction model"); - } - memory->create(roll_coeffs_global, 3, "pair:roll_coeffs_global"); - roll_coeffs_global[0] = force->numeric(FLERR,arg[iarg+2]); //kR - roll_coeffs_global[1] = force->numeric(FLERR,arg[iarg+3]); //gammaR - roll_coeffs_global[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. - iarg += 5; - } - } - else if (strstr(arg[iarg], "twist") != NULL){ - if (strstr(arg[iarg+1], "none") != NULL){ - twist = TWIST_NONE; - iarg += 2; - } - else if (strstr(arg[iarg+1], "marshall") != NULL){ - twist = TWIST_MARSHALL; - twist_history = 1; - iarg += 2; - } - else{ - if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for twist model"); - memory->create(twist_coeffs_global, 3, "pair:twist_coeffs_global"); //To be filled later - if (strstr(arg[iarg+1], "nohistory") != NULL){ - twist = TWIST_NOHISTORY; - } - else if (strstr(arg[iarg+1], "sds") != NULL){ - twist = TWIST_SDS; - twist_history = 1; - } - else{ - error->all(FLERR, "Illegal pair_style command, unrecognized twisting friction model"); - } - memory->create(twist_coeffs_global, 3, "pair:twist_coeffs_global"); - twist_coeffs_global[0] = force->numeric(FLERR,arg[iarg+2]); //ktwist - twist_coeffs_global[1] = force->numeric(FLERR,arg[iarg+3]); //gammatwist - twist_coeffs_global[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. - iarg += 5; - } - } - else error->all(FLERR, "Illegal pair_style granular command"); - } - - //Set all i-i entries, which may be replaced by pair coeff commands - //It may also make sense to consider removing all of the above, and only - // having the option for pair_coeff to set the parameters, similar to most LAMMPS pair styles - // The reason for the current setup is to remain true to existing pair gran/hooke etc. syntax, - // where coeffs are set in the pair_style command, and a pair_coeff * * command is issued. - - allocate(); - double damp; - if (damping == TSUJI){ - double cor = normal_coeffs_global[1]; - damp = 1.2728-4.2783*cor+11.087*pow(cor,2)-22.348*pow(cor,3)+ - 27.467*pow(cor,4)-18.022*pow(cor,5)+ - 4.8218*pow(cor,6); - } - else damp = normal_coeffs_global[1]; - - for (int i = 1; i <= atom->ntypes; i++){ - if (normal_set){ - normal_coeffs[i][i][0] = normal_coeffs_global[0]; - normal_coeffs[i][i][1] = damp; - if (normal != HOOKE && normal != HERTZ){ - normal_coeffs[i][i][2] = normal_coeffs_global[2]; - } - if ((normal == JKR) || (normal == DMT)) - normal_coeffs[i][i][3] = normal_coeffs_global[3]; - } - if(tangential_set){ - for (int k = 0; k < 3; k++) - tangential_coeffs[i][i][k] = tangential_coeffs_global[k]; - } - if (roll != ROLL_NONE) - for (int k = 0; k < 3; k++) - roll_coeffs[i][i][k] = roll_coeffs_global[k]; - - if (twist != TWIST_NONE && twist != TWIST_MARSHALL) - for (int k = 0; k < 3; k++) - twist_coeffs[i][i][k] = twist_coeffs_global[k]; - - if (normal_set && tangential_set) setflag[i][i] = 1; - } + normal_set = tangential_set = damping_set = roll_set = twist_set = 0; } /* ---------------------------------------------------------------------- @@ -1567,12 +1377,6 @@ void PairGranular::settings(int narg, char **arg) void PairGranular::coeff(int narg, char **arg) { - int normal_set, damping_set, tangential_set, roll_set, twist_set; - double *normal_coeffs_local; - double *tangential_coeffs_local; - double *roll_coeffs_local; - double *twist_coeffs_local; - normal_coeffs_local = new double[4]; tangential_coeffs_local = new double[4]; roll_coeffs_local = new double[4]; @@ -1587,13 +1391,12 @@ void PairGranular::coeff(int narg, char **arg) force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); - normal_set = damping_set = tangential_set = roll_set = twist_set = 0; - int iarg = 2; while (iarg < narg){ if (strcmp(arg[iarg], "hooke") == 0){ if (iarg + 2 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hooke option"); - if (normal != HOOKE) error->all(FLERR, "Illegal pair_coeff command, choice of normal contact model must be consistent"); + if (!normal_set) normal = HOOKE; + else if (normal != HOOKE) error->all(FLERR, "Illegal pair_coeff command, choice of normal contact model must be the same for all types"); normal_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1]); //kn normal_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //damping normal_set = 1; @@ -1602,7 +1405,8 @@ void PairGranular::coeff(int narg, char **arg) else if (strcmp(arg[iarg], "hertz") == 0){ int num_coeffs = 2; if (iarg + num_coeffs >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hertz option"); - if (normal != HERTZ) if (normal != HOOKE) error->all(FLERR, "Illegal pair_coeff command, choice of normal contact model must be consistent"); + if (!normal_set) normal = HERTZ; + else if (normal_set && normal != HERTZ) if (normal != HOOKE) error->all(FLERR, "Illegal pair_coeff command, choice of normal contact model must be the same for all types"); normal_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1]); //kn normal_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //damping normal_set = 1; @@ -1611,7 +1415,8 @@ void PairGranular::coeff(int narg, char **arg) else if (strcmp(arg[iarg], "hertz/material") == 0){ int num_coeffs = 3; if (iarg + num_coeffs >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hertz option"); - if (normal != HERTZ) if (normal != HOOKE) error->all(FLERR, "Illegal pair_coeff command, choice of normal contact model must be consistent"); + if (!normal_set) normal = HERTZ/MATERIAL; + else if (normal != HERTZ) if (normal != HOOKE) error->all(FLERR, "Illegal pair_coeff command, choice of normal contact model must be the same for all types"); normal_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1])*FOURTHIRDS; //E normal_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //damping normal_coeffs_local[2] = force->numeric(FLERR,arg[iarg+3]); //G @@ -1620,7 +1425,8 @@ void PairGranular::coeff(int narg, char **arg) } else if (strcmp(arg[iarg], "dmt") == 0){ if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hertz option"); - if (normal != DMT) if (normal != HERTZ) if (normal != HOOKE) error->all(FLERR, "Illegal pair_coeff command, choice of normal contact model must be consistent"); + if (!normal_set) normal = DMT; + else if (normal != DMT) error->all(FLERR, "Illegal pair_coeff command, choice of normal contact model must be the same for all types"); normal_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1])*FOURTHIRDS; //E normal_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //damping normal_coeffs_local[2] = force->numeric(FLERR,arg[iarg+3]); //G @@ -1631,7 +1437,8 @@ void PairGranular::coeff(int narg, char **arg) else if (strcmp(arg[iarg], "jkr") == 0){ if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for JKR option"); beyond_contact = 1; - if (normal != JKR) if (normal != HERTZ) if (normal != HOOKE) error->all(FLERR, "Illegal pair_coeff command, choice of normal contact model must be consistent"); + if (!normal_set) normal = JKR; + else if (normal != JKR) error->all(FLERR, "Illegal pair_coeff command, choice of normal contact model must be the same for all types"); normal_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1]); //E normal_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //damping normal_coeffs_local[2] = force->numeric(FLERR,arg[iarg+3]); //G @@ -1639,25 +1446,32 @@ void PairGranular::coeff(int narg, char **arg) normal_set = 1; iarg += 5; } - else if (strcmp(arg[iarg], "damp_velocity") == 0){ - if (damping != VELOCITY) error->all(FLERR, "Illegal pair_coeff command, choice of damping contact model must be consistent"); - iarg += 1; - } - else if (strcmp(arg[iarg], "damp_viscoelastic") == 0){ - if (damping != VISCOELASTIC) error->all(FLERR, "Illegal pair_coeff command, choice of damping contact model must be consistent"); - iarg += 1; - } - else if (strcmp(arg[iarg], "damp_tsuji") == 0){ - if (damping != TSUJI) error->all(FLERR, "Illegal pair_coeff command, choice of damping contact model must be consistent"); - iarg += 1; - } - else if (strstr(arg[iarg], "tangential") != NULL){ - if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for tangential model"); - if (strstr(arg[iarg+1], "nohistory") != NULL){ - if (tangential != TANGENTIAL_NOHISTORY) error->all(FLERR, "Illegal pair_coeff command, choice of tangential contact model must be consistent"); + else if (strcmp(arg[iarg], "damp") == 0){ + if (iarg+1 >= narg) error->all(FLERR, "Illegal pair_coeff command, not enough parameters provided for damping model"); + if (strcmp(arg[iarg+1]), "velocity") == 0){ + if (!damping_set) damping = VELOCITY; + else if (damping != VELOCITY) error->all(FLERR, "Illegal pair_coeff command, choice of damping contact model must be the same for all types"); } - else if (strstr(arg[iarg+1], "mindlin") != NULL){ - if (tangential != TANGENTIAL_MINDLIN) error->all(FLERR, "Illegal pair_coeff command, choice of tangential contact model must be consistent");; + else if (strcmp(arg[iarg+1], "viscoelastic") == 0){ + if (!damping_set) damping = VISCOELASTIC; + else if (damping != VISCOELASTIC) error->all(FLERR, "Illegal pair_coeff command, choice of damping contact model must be the same for all types"); + } + else if (strcmp(arg[iarg+1], "tsuji") == 0){ + if (!damping_set) damping = TSUJI; + if (damping != TSUJI) error->all(FLERR, "Illegal pair_coeff command, choice of damping contact model must be the same for all types"); + } + damping_set = 1; + iarg += 1; + } + else if (strcmp(arg[iarg], "tangential") == 0){ + if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for tangential model"); + if (strcmp(arg[iarg+1], "nohistory") == 0){ + if (!tangential_set) tangential = TANGENTIAL_NOHISTORY; + else if (tangential != TANGENTIAL_NOHISTORY) error->all(FLERR, "Illegal pair_coeff command, choice of tangential contact model must be the same for all types"); + } + else if (strcmp(arg[iarg+1], "mindlin") == 0){ + if (!tangential_set) tangential = TANGENTIAL_MINDLIN; + else if (tangential != TANGENTIAL_MINDLIN) error->all(FLERR, "Illegal pair_coeff command, choice of tangential contact model must be the same for all types");; tangential_history = 1; } else{ @@ -1669,19 +1483,22 @@ void PairGranular::coeff(int narg, char **arg) tangential_coeffs_local[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. iarg += 5; } - else if (strstr(arg[iarg], "rolling") != NULL){ + else if (strcmp(arg[iarg], "rolling") == 0){ if (iarg + 1 >= narg) error->all(FLERR, "Illegal pair_coeff command, not enough parameters"); - if (strstr(arg[iarg+1], "none") != NULL){ - if (roll != ROLL_NONE) error->all(FLERR, "Illegal pair_coeff command, choice of rolling friction model must be consistent"); + if (strcmp(arg[iarg+1], "none") == 0){ + if (!roll_set) roll = ROLL_NONE; + else if (roll != ROLL_NONE) error->all(FLERR, "Illegal pair_coeff command, choice of rolling friction model must be the same for all types"); iarg += 2; } else{ if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for rolling model"); - if (strstr(arg[iarg+1], "nohistory") != NULL){ - if (roll != ROLL_NOHISTORY) error->all(FLERR, "Illegal pair_coeff command, choice of rolling friction model must be consistent"); + if (strcmp(arg[iarg+1], "nohistory") == 0){ + if (!roll_set) roll = ROLL_NOHISTORY; + else if (roll != ROLL_NOHISTORY) error->all(FLERR, "Illegal pair_coeff command, choice of rolling friction model must be the same for all types"); } - else if (strstr(arg[iarg+1], "sds") != NULL){ - if (roll != ROLL_SDS) error->all(FLERR, "Illegal pair_coeff command, choice of rolling friction model must be consistent"); + else if (strcmp(arg[iarg+1], "sds") == 0){ + if (!roll_set) roll = ROLL_SDS; + else if (roll != ROLL_SDS) error->all(FLERR, "Illegal pair_coeff command, choice of rolling friction model must be the same for all types"); roll_history = 1; } else{ @@ -1694,24 +1511,28 @@ void PairGranular::coeff(int narg, char **arg) iarg += 5; } } - else if (strstr(arg[iarg], "twist") != NULL){ + else if (strcmp(arg[iarg], "twisting") == 0){ if (iarg + 1 >= narg) error->all(FLERR, "Illegal pair_coeff command, not enough parameters"); - if (strstr(arg[iarg+1], "none") != NULL){ - if (twist != TWIST_NONE) error->all(FLERR, "Illegal pair_coeff command, choice of twisting friction model must be consistent"); + if (strcmp(arg[iarg+1], "none") == 0){ + if (!twist_set) twist = TWIST_NOHISTORY; + else if (twist != TWIST_NONE) error->all(FLERR, "Illegal pair_coeff command, choice of twisting friction model must be the same for all types"); iarg += 2; } - else if (strstr(arg[iarg+1], "marshall") != NULL){ - if (twist != TWIST_MARSHALL) error->all(FLERR, "Illegal pair_coeff command, choice of twisting friction model must be consistent"); + else if (strcmp(arg[iarg+1], "marshall") == 0){ + if (!twist_set) twist = TWIST_MARSHALL; + else if (twist != TWIST_MARSHALL) error->all(FLERR, "Illegal pair_coeff command, choice of twisting friction model must be the same for all types"); twist_history = 1; iarg += 2; } else{ if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for twist model"); - if (strstr(arg[iarg+1], "nohistory") != NULL){ - if (twist != TWIST_NOHISTORY) error->all(FLERR, "Illegal pair_coeff command, choice of twisting friction model must be consistent"); + if (!twist_set) twist = TWIST_NOHISTORY; + else if (strcmp(arg[iarg+1], "nohistory") == 0){ + if (twist != TWIST_NOHISTORY) error->all(FLERR, "Illegal pair_coeff command, choice of twisting friction model must be the same for all types"); } - else if (strstr(arg[iarg+1], "sds") != NULL){ - if (twist != TWIST_SDS) error->all(FLERR, "Illegal pair_coeff command, choice of twisting friction model must be consistent"); + else if (strcmp(arg[iarg+1], "sds") == 0){ + if (!twist_set) twist = TWIST_SDS; + else if (twist != TWIST_SDS) error->all(FLERR, "Illegal pair_coeff command, choice of twisting friction model must be the same for all types"); twist_history = 1; } else{ @@ -1727,6 +1548,15 @@ void PairGranular::coeff(int narg, char **arg) else error->all(FLERR, "Illegal pair coeff command"); } + //It is an error not to specify normal or tangential model + if (!normal_set) error->all(FLERR, "Illegal pair coeff command, must specify normal contact model"); + if (!tangential_set) error->all(FLERR, "Illegal pair coeff command, must specify tangential contact model"); + + //If unspecified, set damping to VISCOELASTIC, twist/roll to NONE (cannot be changed by subsequent pair_coeff commands) + if (!damping_set) damping = VISCOELASTIC; + if (!roll_set) roll = ROLL_NONE; + if (!twist_set) twist = TWIST_NONE; + int count = 0; double damp; if (damping == TSUJI){ @@ -1740,37 +1570,28 @@ void PairGranular::coeff(int narg, char **arg) for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { - if (normal_set){ - normal_coeffs[i][j][0] = normal_coeffs_local[0]; - normal_coeffs[i][j][1] = damp; - if (normal != HERTZ && normal != HOOKE) normal_coeffs[i][j][2] = normal_coeffs_local[2]; - if ((normal == JKR) || (normal == DMT)) - normal_coeffs[i][j][3] = normal_coeffs_local[3]; - } - if (tangential_set){ + normal_coeffs[i][j][0] = normal_coeffs_local[0]; + normal_coeffs[i][j][1] = damp; + if (normal != HERTZ && normal != HOOKE) normal_coeffs[i][j][2] = normal_coeffs_local[2]; + if ((normal == JKR) || (normal == DMT)) + normal_coeffs[i][j][3] = normal_coeffs_local[3]; + + for (int k = 0; k < 3; k++) + tangential_coeffs[i][j][k] = tangential_coeffs_local[k]; + + if (roll != ROLL_NONE) for (int k = 0; k < 3; k++) - tangential_coeffs[i][j][k] = tangential_coeffs_local[k]; - } - if (roll_set){ - if (roll != ROLL_NONE) - for (int k = 0; k < 3; k++) - roll_coeffs[i][j][k] = roll_coeffs_local[k]; - } - if (twist_set){ - if (twist != TWIST_NONE && twist != TWIST_MARSHALL) - for (int k = 0; k < 3; k++) - twist_coeffs[i][j][k] = twist_coeffs_local[k]; - } + roll_coeffs[i][j][k] = roll_coeffs_local[k]; + + if (twist != TWIST_NONE && twist != TWIST_MARSHALL) + for (int k = 0; k < 3; k++) + twist_coeffs[i][j][k] = twist_coeffs_local[k]; + setflag[i][j] = 1; count++; } } - delete[] normal_coeffs_local; - delete[] tangential_coeffs_local; - delete[] roll_coeffs_local; - delete[] twist_coeffs_local; - if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); } @@ -1959,20 +1780,25 @@ double PairGranular::init_one(int i, int j) // if there is no current information about radius/cutoff of type i and j). // we assign cutoff = max(cut[i][j]) for i,j such that cut[i][j] > 0.0. - if (((maxrad_dynamic[i] > 0.0) && (maxrad_dynamic[j] > 0.0)) || - ((maxrad_dynamic[i] > 0.0) && (maxrad_frozen[j] > 0.0)) || - ((maxrad_frozen[i] > 0.0) && (maxrad_dynamic[j] > 0.0))) { // radius info about both i and j exist - cutoff = maxrad_dynamic[i]+maxrad_dynamic[j]; - cutoff = MAX(cutoff,maxrad_frozen[i]+maxrad_dynamic[j]); - cutoff = MAX(cutoff,maxrad_dynamic[i]+maxrad_frozen[j]); - } - else { // radius info about either i or j does not exist (i.e. not present and not about to get poured; set to largest value to not interfere with neighbor list) - double cutmax = 0.0; - for (int k = 1; k <= atom->ntypes; k++) { - cutmax = MAX(cutmax,2.0*maxrad_dynamic[k]); - cutmax = MAX(cutmax,2.0*maxrad_frozen[k]); + if (cutoff_global < 0){ + if (((maxrad_dynamic[i] > 0.0) && (maxrad_dynamic[j] > 0.0)) || + ((maxrad_dynamic[i] > 0.0) && (maxrad_frozen[j] > 0.0)) || + ((maxrad_frozen[i] > 0.0) && (maxrad_dynamic[j] > 0.0))) { // radius info about both i and j exist + cutoff = maxrad_dynamic[i]+maxrad_dynamic[j]; + cutoff = MAX(cutoff,maxrad_frozen[i]+maxrad_dynamic[j]); + cutoff = MAX(cutoff,maxrad_dynamic[i]+maxrad_frozen[j]); } - cutoff = cutmax; + else { // radius info about either i or j does not exist (i.e. not present and not about to get poured; set to largest value to not interfere with neighbor list) + double cutmax = 0.0; + for (int k = 1; k <= atom->ntypes; k++) { + cutmax = MAX(cutmax,2.0*maxrad_dynamic[k]); + cutmax = MAX(cutmax,2.0*maxrad_frozen[k]); + } + cutoff = cutmax; + } + } + else{ + cutoff = cutoff_global; } return cutoff; } diff --git a/src/GRANULAR/pair_granular.h b/src/GRANULAR/pair_granular.h index 897316c907..f3a9d4dcbe 100644 --- a/src/GRANULAR/pair_granular.h +++ b/src/GRANULAR/pair_granular.h @@ -86,19 +86,18 @@ private: //Indices of history entries int tangential_history_index, roll_history_index, twist_history_index; - //Coefficients declared in pair style command, used as default unless - // overwritten in pair coeff command - double *normal_coeffs_global; - double *tangential_coeffs_global; - double *roll_coeffs_global; - double *twist_coeffs_global; + //Flags for whether model choices have been set + int normal_set, tangential_set, damping_set, roll_set, twist_set; - //Per-type coefficients declared in pair coeff command + //Per-type coefficients, set in pair coeff command double ***normal_coeffs; double ***tangential_coeffs; double ***roll_coeffs; double ***twist_coeffs; + //Optional user-specified global cutoff + double global_cutoff; + double mix_stiffnessE(double Eii, double Ejj, double Gii, double Gjj); double mix_stiffnessG(double Eii, double Ejj, double Gii, double Gjj); double mix_geom(double valii, double valjj); diff --git a/src/GRANULAR/pair_granular_multi.cpp b/src/GRANULAR/pair_granular_multi.cpp index 11381444a2..5fee363872 100644 --- a/src/GRANULAR/pair_granular_multi.cpp +++ b/src/GRANULAR/pair_granular_multi.cpp @@ -654,217 +654,15 @@ void PairGranularMulti::allocate() void PairGranularMulti::settings(int narg, char **arg) { - if (narg < 5) error->all(FLERR,"Illegal pair_style command"); + if (narg == 1){ + cutoff_global = force->numeric(FLERR,arg[0]) + } + else{ + cutoff_global = -1; //Will be set based on particle sizes, model choice + } - int iarg = 0; - - //Some defaults - normal_global = HERTZ; - damping_global = VISCOELASTIC; - tangential_global = TANGENTIAL_MINDLIN; - roll_global = ROLL_NONE; - twist_global = TWIST_NONE; - - tangential_history = 1; + tangential_history = 0; roll_history = twist_history = 0; - - int normal_set, tangential_set; - normal_set = tangential_set = 0; - - while (iarg < narg){ - if (strcmp(arg[iarg], "hooke") == 0){ - if (iarg + 2 >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for Hooke option"); - normal_global = HOOKE; - normal_set = 1; - memory->create(normal_coeffs_global, 2, "pair:normal_coeffs_global"); - normal_coeffs_global[0] = force->numeric(FLERR,arg[iarg+1]); //kn - normal_coeffs_global[1] = force->numeric(FLERR,arg[iarg+2]); //damping - iarg += 3; - } - else if (strcmp(arg[iarg], "hertz") == 0){ - int num_coeffs = 2; - if (iarg + num_coeffs >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for Hertz option"); - normal_global = HERTZ; - normal_set = 1; - memory->create(normal_coeffs_global, num_coeffs, "pair:normal_coeffs_global"); - normal_coeffs_global[0] = force->numeric(FLERR,arg[iarg+1]); //kn - normal_coeffs_global[1] = force->numeric(FLERR,arg[iarg+2]); //damping - iarg += num_coeffs+1; - } - else if (strcmp(arg[iarg], "hertz/material") == 0){ - int num_coeffs = 3; - if (iarg + num_coeffs >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for Hertz option"); - normal_global = HERTZ_MATERIAL; - normal_set = 1; - memory->create(normal_coeffs_global, num_coeffs, "pair:normal_coeffs_global"); - normal_coeffs_global[0] = force->numeric(FLERR,arg[iarg+1])*FOURTHIRDS; //E (Young's modulus) - normal_coeffs_global[1] = force->numeric(FLERR,arg[iarg+2]); //damping - normal_coeffs_global[2] = force->numeric(FLERR,arg[iarg+3]); //G (shear modulus) - iarg += num_coeffs+1; - } - else if (strcmp(arg[iarg], "dmt") == 0){ - if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for Hertz option"); - normal_global = DMT; - normal_set = 1; - memory->create(normal_coeffs_global, 4, "pair:normal_coeffs_global"); - normal_coeffs_global[0] = force->numeric(FLERR,arg[iarg+1])*FOURTHIRDS; //4/3 E - normal_coeffs_global[1] = force->numeric(FLERR,arg[iarg+2]); //damping - normal_coeffs_global[2] = force->numeric(FLERR,arg[iarg+3]); //G - normal_coeffs_global[3] = force->numeric(FLERR,arg[iarg+3]); //cohesion - iarg += 5; - } - else if (strcmp(arg[iarg], "jkr") == 0){ - if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for JKR option"); - beyond_contact = 1; - normal_global = JKR; - normal_set = 1; - memory->create(normal_coeffs_global, 4, "pair:normal_coeffs_global"); - normal_coeffs_global[0] = force->numeric(FLERR,arg[iarg+1]); //E - normal_coeffs_global[1] = force->numeric(FLERR,arg[iarg+2]); //damping - normal_coeffs_global[2] = force->numeric(FLERR,arg[iarg+3]); //G - normal_coeffs_global[3] = force->numeric(FLERR,arg[iarg+4]); //cohesion - iarg += 5; - } - else if (strcmp(arg[iarg], "damp_velocity") == 0){ - damping_global = VELOCITY; - iarg += 1; - } - else if (strcmp(arg[iarg], "damp_viscoelastic") == 0){ - damping_global = VISCOELASTIC; - iarg += 1; - } - else if (strcmp(arg[iarg], "damp_tsuji") == 0){ - damping_global = TSUJI; - iarg += 1; - } - else if (strstr(arg[iarg], "tangential") != NULL){ - if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for tangential model"); - if (strstr(arg[iarg+1], "nohistory") != NULL){ - tangential_global = TANGENTIAL_NOHISTORY; - tangential_set = 1; - } - else if (strstr(arg[iarg+1], "mindlin") != NULL){ - tangential_global = TANGENTIAL_MINDLIN; - tangential_history = 1; - tangential_set = 1; - } - else{ - error->all(FLERR, "Illegal pair_style command, unrecognized sliding friction model"); - } - memory->create(tangential_coeffs_global, 3, "pair:tangential_coeffs_global"); - tangential_coeffs_global[0] = force->numeric(FLERR,arg[iarg+2]); //kt - tangential_coeffs_global[1] = force->numeric(FLERR,arg[iarg+3]); //gammat - tangential_coeffs_global[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. - iarg += 5; - } - else if (strstr(arg[iarg], "roll") != NULL){ - if (strstr(arg[iarg+1], "none") != NULL){ - roll_global = ROLL_NONE; - iarg += 2; - } - else{ - if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for rolling model"); - if (strstr(arg[iarg+1], "nohistory") != NULL){ - roll_global = ROLL_NOHISTORY; - } - else if (strstr(arg[iarg+1], "sds") != NULL){ - roll_global = ROLL_SDS; - roll_history = 1; - } - else{ - error->all(FLERR, "Illegal pair_style command, unrecognized rolling friction model"); - } - memory->create(roll_coeffs_global, 3, "pair:roll_coeffs_global"); - roll_coeffs_global[0] = force->numeric(FLERR,arg[iarg+2]); //kR - roll_coeffs_global[1] = force->numeric(FLERR,arg[iarg+3]); //gammaR - roll_coeffs_global[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. - iarg += 5; - } - } - else if (strstr(arg[iarg], "twist") != NULL){ - if (strstr(arg[iarg+1], "none") != NULL){ - twist_global = TWIST_NONE; - iarg += 2; - } - else if (strstr(arg[iarg+1], "marshall") != NULL){ - twist_global = TWIST_MARSHALL; - twist_history = 1; - iarg += 2; - } - else{ - if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_style command, not enough parameters provided for twist model"); - memory->create(twist_coeffs_global, 3, "pair:twist_coeffs_global"); //To be filled later - if (strstr(arg[iarg+1], "nohistory") != NULL){ - twist_global = TWIST_NOHISTORY; - } - else if (strstr(arg[iarg+1], "sds") != NULL){ - twist_global = TWIST_SDS; - twist_history = 1; - } - else{ - error->all(FLERR, "Illegal pair_style command, unrecognized twisting friction model"); - } - memory->create(twist_coeffs_global, 3, "pair:twist_coeffs_global"); - twist_coeffs_global[0] = force->numeric(FLERR,arg[iarg+2]); //ktwist - twist_coeffs_global[1] = force->numeric(FLERR,arg[iarg+3]); //gammatwist - twist_coeffs_global[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. - iarg += 5; - } - } - else error->all(FLERR, "Illegal pair_style granular command"); - } - - //Set all i-i entries, which may be replaced by pair coeff commands - //It may also make sense to consider removing all of the above, and only - // having the option for pair_coeff to set the parameters, similar to most LAMMPS pair styles - // The reason for the current setup is to remain true to existing pair gran/hooke etc. syntax, - // where coeffs are set in the pair_style command, and a pair_coeff * * command is issued. - - //Other option is to have two pair styles, e.g. pair granular and pair granular/multi, - // where granular/multi allows per-type coefficients, pair granular does not (this would also - // allow minor speed-up by templating pair granular) - allocate(); - double damp; - for (int i = 1; i <= atom->ntypes; i++){ - normal[i][i] = normal_global; - damping[i][i] = damping_global; - tangential[i][i] = tangential_global; - roll[i][i] = roll_global; - twist[i][i] = twist_global; - - if (normal_set){ - if (damping_global == TSUJI){ - double cor = normal_coeffs_global[1]; - damp = 1.2728-4.2783*cor+11.087*pow(cor,2)-22.348*pow(cor,3)+ - 27.467*pow(cor,4)-18.022*pow(cor,5)+ - 4.8218*pow(cor,6); - } - else damp = normal_coeffs_global[1]; - normal_coeffs[i][i][0] = normal_coeffs_global[0]; - normal_coeffs[i][i][1] = damp; - if (normal[i][i] != HOOKE && normal[i][i] != HERTZ){ - normal_coeffs[i][i][2] = normal_coeffs_global[2]; - } - if ((normal_global == JKR) || (normal_global == DMT)) - normal_coeffs[i][i][3] = normal_coeffs_global[3]; - } - if(tangential_set){ - tangential[i][i] = tangential_global; - for (int k = 0; k < 3; k++) - tangential_coeffs[i][i][k] = tangential_coeffs_global[k]; - } - roll[i][i] = roll_global; - if (roll_global != ROLL_NONE) - for (int k = 0; k < 3; k++) - roll_coeffs[i][i][k] = roll_coeffs_global[k]; - - twist[i][i] = twist_global; - if (twist_global != TWIST_NONE && twist_global != TWIST_MARSHALL) - for (int k = 0; k < 3; k++) - twist_coeffs[i][i][k] = twist_coeffs_global[k]; - - if (normal_set && tangential_set) setflag[i][i] = 1; - } } /* ---------------------------------------------------------------------- @@ -874,10 +672,6 @@ void PairGranularMulti::settings(int narg, char **arg) void PairGranularMulti::coeff(int narg, char **arg) { int normal_local, damping_local, tangential_local, roll_local, twist_local; - double *normal_coeffs_local; - double *tangential_coeffs_local; - double *roll_coeffs_local; - double *twist_coeffs_local; normal_coeffs_local = new double[4]; tangential_coeffs_local = new double[4]; @@ -893,8 +687,10 @@ void PairGranularMulti::coeff(int narg, char **arg) force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); - normal_local = tangential_local = roll_local = twist_local = -1; - damping_local = -1; + //Defaults + normal_local = tangential_local = -1; + roll_local = twist_local = 0; + damping_local = VISCOELASTIC; int iarg = 2; while (iarg < narg){ @@ -941,24 +737,27 @@ void PairGranularMulti::coeff(int narg, char **arg) normal_coeffs_local[3] = force->numeric(FLERR,arg[iarg+4]); //cohesion iarg += 5; } - else if (strcmp(arg[iarg], "damp_velocity") == 0){ - damping_local = VELOCITY; - iarg += 1; + else if (strcmp(arg[iarg], "damp") == 0){ + if (iarg+1 >= narg) error->all(FLERR, "Illegal pair_coeff command, not enough parameters provided for damping model"); + if (strcmp(arg[iarg+1]), "velocity") == 0){ + damping_local = VELOCITY; + iarg += 1; + } + else if (strcmp(arg[iarg+1], "viscoelastic") == 0){ + damping_local = VISCOELASTIC; + iarg += 1; + } + else if (strcmp(arg[iarg], "tsuji") == 0){ + damping_local = TSUJI; + iarg += 1; + } } - else if (strcmp(arg[iarg], "damp_viscoelastic") == 0){ - damping_local = VISCOELASTIC; - iarg += 1; - } - else if (strcmp(arg[iarg], "damp_tsuji") == 0){ - damping_local = TSUJI; - iarg += 1; - } - else if (strstr(arg[iarg], "tangential") != NULL){ + else if (strcmp(arg[iarg], "tangential") == 0){ if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for tangential model"); - if (strstr(arg[iarg+1], "nohistory") != NULL){ + if (strcmp(arg[iarg+1], "nohistory") == 0){ tangential_local = TANGENTIAL_NOHISTORY; } - else if (strstr(arg[iarg+1], "mindlin") != NULL){ + else if (strcmp(arg[iarg+1], "mindlin") == 0){ tangential_local = TANGENTIAL_MINDLIN; tangential_history = 1; } @@ -970,18 +769,18 @@ void PairGranularMulti::coeff(int narg, char **arg) tangential_coeffs_local[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. iarg += 5; } - else if (strstr(arg[iarg], "rolling") != NULL){ + else if (strcmp(arg[iarg], "rolling") == 0){ if (iarg + 1 >= narg) error->all(FLERR, "Illegal pair_coeff command, not enough parameters"); - if (strstr(arg[iarg+1], "none") != NULL){ + if (strcmp(arg[iarg+1], "none") == 0){ roll_local = ROLL_NONE; iarg += 2; } else{ if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for rolling model"); - if (strstr(arg[iarg+1], "nohistory") != NULL){ + if (strcmp(arg[iarg+1], "nohistory") == 0){ roll_local = ROLL_NOHISTORY; } - else if (strstr(arg[iarg+1], "sds") != NULL){ + else if (strcmp(arg[iarg+1], "sds") == 0){ roll_local = ROLL_SDS; roll_history = 1; } @@ -994,23 +793,23 @@ void PairGranularMulti::coeff(int narg, char **arg) iarg += 5; } } - else if (strstr(arg[iarg], "twist") != NULL){ + else if (strcmp(arg[iarg], "twisting") == 0){ if (iarg + 1 >= narg) error->all(FLERR, "Illegal pair_coeff command, not enough parameters"); - if (strstr(arg[iarg+1], "none") != NULL){ + if (strcmp(arg[iarg+1], "none") == 0){ twist_local = TWIST_NONE; iarg += 2; } - else if (strstr(arg[iarg+1], "marshall") != NULL){ + else if (strcmp(arg[iarg+1], "marshall") == 0){ twist_local = TWIST_MARSHALL; twist_history = 1; iarg += 2; } else{ if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for twist model"); - if (strstr(arg[iarg+1], "nohistory") != NULL){ + if (strcmp(arg[iarg+1], "nohistory") == 0){ twist_local = TWIST_NOHISTORY; } - else if (strstr(arg[iarg+1], "sds") != NULL){ + else if (strcmp(arg[iarg+1], "sds") == 0){ twist_local = TWIST_SDS; twist_history = 1; } @@ -1026,66 +825,49 @@ void PairGranularMulti::coeff(int narg, char **arg) else error->all(FLERR, "Illegal pair coeff command"); } + //It is an error not to specify normal or tangential model + if ((normal_set < 0) || (tangential_set < 0)) error->all(FLERR, "Illegal pair coeff command, must specify normal contact model");)) + int count = 0; double damp; - if (damping_local >= 0){ - if (normal_local == -1) - error->all(FLERR, "Illegal pair_coeff command, must specify normal model when setting damping model"); - if (damping_local == TSUJI){ - double cor; - cor = normal_coeffs_local[1]; - damp = 1.2728-4.2783*cor+11.087*pow(cor,2)-22.348*pow(cor,3)+ - 27.467*pow(cor,4)-18.022*pow(cor,5)+ - 4.8218*pow(cor,6); - } - else damp = normal_coeffs_local[1]; + if (damping_local == TSUJI){ + double cor; + cor = normal_coeffs_local[1]; + damp = 1.2728-4.2783*cor+11.087*pow(cor,2)-22.348*pow(cor,3)+ + 27.467*pow(cor,4)-18.022*pow(cor,5)+ + 4.8218*pow(cor,6); } + else damp = normal_coeffs_local[1]; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { - if (normal_local >= 0){ - normal[i][j] = normal_local; - normal_coeffs[i][j][0] = normal_coeffs_local[0]; - if (damping_local == -1){ - damp = normal_coeffs_global[1]; - } - normal_coeffs[i][j][1] = damp; - if (normal_local != HERTZ && normal_local != HOOKE) normal_coeffs[i][j][2] = normal_coeffs_local[2]; - if ((normal_local == JKR) || (normal_local == DMT)) - normal_coeffs[i][j][3] = normal_coeffs_local[3]; - } - if (damping_local >= 0){ - damping[i][j] = damping_local; - } - if (tangential_local >= 0){ - tangential[i][j] = tangential_local; + normal[i][j] = normal_local; + normal_coeffs[i][j][0] = normal_coeffs_local[0]; + normal_coeffs[i][j][1] = damp; + if (normal_local != HERTZ && normal_local != HOOKE) normal_coeffs[i][j][2] = normal_coeffs_local[2]; + if ((normal_local == JKR) || (normal_local == DMT)) + normal_coeffs[i][j][3] = normal_coeffs_local[3]; + + damping[i][j] = damping_local; + + tangential[i][j] = tangential_local; for (int k = 0; k < 3; k++) tangential_coeffs[i][j][k] = tangential_coeffs_local[k]; - } - if (roll_local >= 0){ - roll[i][j] = roll_local; - if (roll_local != ROLL_NONE) - for (int k = 0; k < 3; k++) - roll_coeffs[i][j][k] = roll_coeffs_local[k]; - } - if (twist_local >= 0){ - twist[i][j] = twist_local; + + roll[i][j] = roll_local; + if (roll_local != ROLL_NONE) + for (int k = 0; k < 3; k++) + roll_coeffs[i][j][k] = roll_coeffs_local[k]; + + twist[i][j] = twist_local; if (twist_local != TWIST_NONE && twist_local != TWIST_MARSHALL) for (int k = 0; k < 3; k++) twist_coeffs[i][j][k] = twist_coeffs_local[k]; - } - - if (normal_local >= 0 && tangential_local >= 0) setflag[i][j] = 1; + setflag[i][j] = 1; count++; } } - - delete[] normal_coeffs_local; - delete[] tangential_coeffs_local; - delete[] roll_coeffs_local; - delete[] twist_coeffs_local; - if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); } @@ -1286,20 +1068,25 @@ double PairGranularMulti::init_one(int i, int j) // if there is no current information about radius/cutoff of type i and j). // we assign cutoff = max(cut[i][j]) for i,j such that cut[i][j] > 0.0. - if (((maxrad_dynamic[i] > 0.0) && (maxrad_dynamic[j] > 0.0)) || - ((maxrad_dynamic[i] > 0.0) && (maxrad_frozen[j] > 0.0)) || - ((maxrad_frozen[i] > 0.0) && (maxrad_dynamic[j] > 0.0))) { // radius info about both i and j exist - cutoff = maxrad_dynamic[i]+maxrad_dynamic[j]; - cutoff = MAX(cutoff,maxrad_frozen[i]+maxrad_dynamic[j]); - cutoff = MAX(cutoff,maxrad_dynamic[i]+maxrad_frozen[j]); - } - else { // radius info about either i or j does not exist (i.e. not present and not about to get poured; set to largest value to not interfere with neighbor list) - double cutmax = 0.0; - for (int k = 1; k <= atom->ntypes; k++) { - cutmax = MAX(cutmax,2.0*maxrad_dynamic[k]); - cutmax = MAX(cutmax,2.0*maxrad_frozen[k]); + if (cutoff_global < 0){ + if (((maxrad_dynamic[i] > 0.0) && (maxrad_dynamic[j] > 0.0)) || + ((maxrad_dynamic[i] > 0.0) && (maxrad_frozen[j] > 0.0)) || + ((maxrad_frozen[i] > 0.0) && (maxrad_dynamic[j] > 0.0))) { // radius info about both i and j exist + cutoff = maxrad_dynamic[i]+maxrad_dynamic[j]; + cutoff = MAX(cutoff,maxrad_frozen[i]+maxrad_dynamic[j]); + cutoff = MAX(cutoff,maxrad_dynamic[i]+maxrad_frozen[j]); } - cutoff = cutmax; + else { // radius info about either i or j does not exist (i.e. not present and not about to get poured; set to largest value to not interfere with neighbor list) + double cutmax = 0.0; + for (int k = 1; k <= atom->ntypes; k++) { + cutmax = MAX(cutmax,2.0*maxrad_dynamic[k]); + cutmax = MAX(cutmax,2.0*maxrad_frozen[k]); + } + cutoff = cutmax; + } + } + else{ + cutoff = cutoff_global; } return cutoff; } diff --git a/src/GRANULAR/pair_granular_multi.h b/src/GRANULAR/pair_granular_multi.h index e853e564df..95beb950f4 100644 --- a/src/GRANULAR/pair_granular_multi.h +++ b/src/GRANULAR/pair_granular_multi.h @@ -65,27 +65,26 @@ public: private: int size_history; - //Per-type models + //Models int **normal, **damping, **tangential, **roll, **twist; - int normal_global, damping_global; - int tangential_global, roll_global, twist_global; - + //History flags int tangential_history, roll_history, twist_history; + + //Indices of history entries int tangential_history_index; int roll_history_index; int twist_history_index; - double *normal_coeffs_global; - double *tangential_coeffs_global; - double *roll_coeffs_global; - double *twist_coeffs_global; - + //Per-type coefficients, set in pair coeff command double ***normal_coeffs; double ***tangential_coeffs; double ***roll_coeffs; double ***twist_coeffs; + //Optional user-specified global cutoff + double cutoff_global; + double mix_stiffnessE(double Eii, double Ejj, double Gii, double Gjj); double mix_stiffnessG(double Eii, double Ejj, double Gii, double Gjj); double mix_geom(double valii, double valjj); From 6e4e244e65ac89f4fc248442c85b451c2ce9080e Mon Sep 17 00:00:00 2001 From: dsbolin Date: Tue, 15 Jan 2019 13:31:16 -0700 Subject: [PATCH 15/44] More doc page additions --- doc/src/pair_granular.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/src/pair_granular.txt b/doc/src/pair_granular.txt index 19c16cc6ea..35b64bf29d 100644 --- a/doc/src/pair_granular.txt +++ b/doc/src/pair_granular.txt @@ -92,7 +92,11 @@ and their required arguments are: {no_history}: k_t, tangential_damping, friction coefficient {mindlin}: k_t, tangential_damping, friction coefficient -For {no_history}, the tangential force is computed according to +For {no_history}, the tangential force is computed according to: +:c,image{Eqs/tangential_nohistory.jpg} + +For {mindlin}, tangential force is: +:c,image{Eqs/tangential_mindlin.jpg} The total force on a particle is the sum of the normal and tangential forces from all interactions. The tangential force also induces a torque on both particles in a contacting pair. Additionally, rolling and twisting friction From 26eb17aa506f0c39995533e6b14255c6d4f83537 Mon Sep 17 00:00:00 2001 From: Dan Stefan Bolintineanu Date: Tue, 15 Jan 2019 16:42:06 -0700 Subject: [PATCH 16/44] Fixed tangential damping in pair granular; fixed order of template arguments, so that pair gran and gran/multi now produce identical results for same settings (as they should) --- src/GRANULAR/pair_granular.cpp | 41 ++++++++++++++-------------- src/GRANULAR/pair_granular.h | 2 +- src/GRANULAR/pair_granular_multi.cpp | 28 +++++++++---------- 3 files changed, 36 insertions(+), 35 deletions(-) diff --git a/src/GRANULAR/pair_granular.cpp b/src/GRANULAR/pair_granular.cpp index 9fe4bd8415..c2f202ac9c 100644 --- a/src/GRANULAR/pair_granular.cpp +++ b/src/GRANULAR/pair_granular.cpp @@ -825,12 +825,12 @@ void PairGranular::compute(int eflag, int vflag){ #ifdef TEMPLATED_PAIR_GRANULAR template < int Tp_normal, int Tp_damping, int Tp_tangential, - int Tp_roll, int Tp_twist > + int Tp_twist, int Tp_roll > void PairGranular::compute_templated(int eflag, int vflag) #else void PairGranular::compute_untemplated (int Tp_normal, int Tp_damping, int Tp_tangential, - int Tp_roll, int Tp_twist, int eflag, int vflag) + int Tp_twist, int Tp_roll, int eflag, int vflag) #endif { int i,j,ii,jj,inum,jnum,itype,jtype; @@ -1040,17 +1040,17 @@ void PairGranular::compute_untemplated //Consider restricting Hooke to only have 'velocity' as an option for damping? if (Tp_damping == VELOCITY){ - damp_normal = normal_coeffs[itype][jtype][1]; + damp_normal = 1; } else if (Tp_damping == VISCOELASTIC){ if (Tp_normal == HOOKE) a = sqrt(dR); - damp_normal = normal_coeffs[itype][jtype][1]*a*meff; + damp_normal = a*meff; } else if (Tp_damping == TSUJI){ - damp_normal = normal_coeffs[itype][jtype][1]*sqrt(meff*knfac); + damp_normal = sqrt(meff*knfac); } - Fdamp = -damp_normal*vnnr; + Fdamp = -normal_coeffs[itype][jtype][1]*damp_normal*vnnr; Fntot = Fne + Fdamp; @@ -1197,7 +1197,6 @@ void PairGranular::compute_untemplated history[rhist2] += vrl3*dt; } - k_roll = roll_coeffs[itype][jtype][0]; damp_roll = roll_coeffs[itype][jtype][1]; fr1 = -k_roll*history[rhist0] - damp_roll*vrl1; @@ -1361,7 +1360,7 @@ void PairGranular::allocate() void PairGranular::settings(int narg, char **arg) { if (narg == 1){ - cutoff_global = force->numeric(FLERR,arg[0]) + cutoff_global = force->numeric(FLERR,arg[0]); } else{ cutoff_global = -1; //Will be set based on particle sizes, model choice @@ -1377,10 +1376,10 @@ void PairGranular::settings(int narg, char **arg) void PairGranular::coeff(int narg, char **arg) { - normal_coeffs_local = new double[4]; - tangential_coeffs_local = new double[4]; - roll_coeffs_local = new double[4]; - twist_coeffs_local = new double[4]; + double normal_coeffs_local[4]; + double tangential_coeffs_local[4]; + double roll_coeffs_local[4]; + double twist_coeffs_local[4]; if (narg < 2) error->all(FLERR,"Incorrect args for pair coefficients"); @@ -1415,7 +1414,7 @@ void PairGranular::coeff(int narg, char **arg) else if (strcmp(arg[iarg], "hertz/material") == 0){ int num_coeffs = 3; if (iarg + num_coeffs >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hertz option"); - if (!normal_set) normal = HERTZ/MATERIAL; + if (!normal_set) normal = HERTZ_MATERIAL; else if (normal != HERTZ) if (normal != HOOKE) error->all(FLERR, "Illegal pair_coeff command, choice of normal contact model must be the same for all types"); normal_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1])*FOURTHIRDS; //E normal_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //damping @@ -1448,7 +1447,7 @@ void PairGranular::coeff(int narg, char **arg) } else if (strcmp(arg[iarg], "damp") == 0){ if (iarg+1 >= narg) error->all(FLERR, "Illegal pair_coeff command, not enough parameters provided for damping model"); - if (strcmp(arg[iarg+1]), "velocity") == 0){ + if (strcmp(arg[iarg+1], "velocity") == 0){ if (!damping_set) damping = VELOCITY; else if (damping != VELOCITY) error->all(FLERR, "Illegal pair_coeff command, choice of damping contact model must be the same for all types"); } @@ -1461,7 +1460,7 @@ void PairGranular::coeff(int narg, char **arg) if (damping != TSUJI) error->all(FLERR, "Illegal pair_coeff command, choice of damping contact model must be the same for all types"); } damping_set = 1; - iarg += 1; + iarg += 2; } else if (strcmp(arg[iarg], "tangential") == 0){ if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for tangential model"); @@ -1505,16 +1504,16 @@ void PairGranular::coeff(int narg, char **arg) error->all(FLERR, "Illegal pair_coeff command, rolling friction model not recognized"); } roll_set =1 ; - roll_coeffs_local[0] = force->numeric(FLERR,arg[iarg+2]); //kt - roll_coeffs_local[1] = force->numeric(FLERR,arg[iarg+3]); //gammat - roll_coeffs_local[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. + roll_coeffs_local[0] = force->numeric(FLERR,arg[iarg+2]); //kR + roll_coeffs_local[1] = force->numeric(FLERR,arg[iarg+3]); //gammaR + roll_coeffs_local[2] = force->numeric(FLERR,arg[iarg+4]); //rolling friction coeff. iarg += 5; } } else if (strcmp(arg[iarg], "twisting") == 0){ if (iarg + 1 >= narg) error->all(FLERR, "Illegal pair_coeff command, not enough parameters"); if (strcmp(arg[iarg+1], "none") == 0){ - if (!twist_set) twist = TWIST_NOHISTORY; + if (!twist_set) twist = TWIST_NONE; else if (twist != TWIST_NONE) error->all(FLERR, "Illegal pair_coeff command, choice of twisting friction model must be the same for all types"); iarg += 2; } @@ -1522,12 +1521,13 @@ void PairGranular::coeff(int narg, char **arg) if (!twist_set) twist = TWIST_MARSHALL; else if (twist != TWIST_MARSHALL) error->all(FLERR, "Illegal pair_coeff command, choice of twisting friction model must be the same for all types"); twist_history = 1; + twist_set = 1; iarg += 2; } else{ if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for twist model"); - if (!twist_set) twist = TWIST_NOHISTORY; else if (strcmp(arg[iarg+1], "nohistory") == 0){ + if (!twist_set) twist = TWIST_NOHISTORY; if (twist != TWIST_NOHISTORY) error->all(FLERR, "Illegal pair_coeff command, choice of twisting friction model must be the same for all types"); } else if (strcmp(arg[iarg+1], "sds") == 0){ @@ -1556,6 +1556,7 @@ void PairGranular::coeff(int narg, char **arg) if (!damping_set) damping = VISCOELASTIC; if (!roll_set) roll = ROLL_NONE; if (!twist_set) twist = TWIST_NONE; + damping_set = roll_set = twist_set = 1; int count = 0; double damp; diff --git a/src/GRANULAR/pair_granular.h b/src/GRANULAR/pair_granular.h index f3a9d4dcbe..f39f31e4cb 100644 --- a/src/GRANULAR/pair_granular.h +++ b/src/GRANULAR/pair_granular.h @@ -96,7 +96,7 @@ private: double ***twist_coeffs; //Optional user-specified global cutoff - double global_cutoff; + double cutoff_global; double mix_stiffnessE(double Eii, double Ejj, double Gii, double Gjj); double mix_stiffnessG(double Eii, double Ejj, double Gii, double Gjj); diff --git a/src/GRANULAR/pair_granular_multi.cpp b/src/GRANULAR/pair_granular_multi.cpp index 5fee363872..09b8ea9709 100644 --- a/src/GRANULAR/pair_granular_multi.cpp +++ b/src/GRANULAR/pair_granular_multi.cpp @@ -329,17 +329,17 @@ void PairGranularMulti::compute(int eflag, int vflag) //Consider restricting Hooke to only have 'velocity' as an option for damping? if (damping[itype][jtype] == VELOCITY){ - damp_normal = normal_coeffs[itype][jtype][1]; + damp_normal = 1; } else if (damping[itype][jtype] == VISCOELASTIC){ if (normal[itype][jtype] == HOOKE) a = sqrt(dR); - damp_normal = normal_coeffs[itype][jtype][1]*a*meff; + damp_normal = a*meff; } else if (damping[itype][jtype] == TSUJI){ - damp_normal = normal_coeffs[itype][jtype][1]*sqrt(meff*knfac); + damp_normal = sqrt(meff*knfac); } - Fdamp = -damp_normal*vnnr; + Fdamp = -normal_coeffs[itype][jtype][1]*damp_normal*vnnr; Fntot = Fne + Fdamp; @@ -655,7 +655,7 @@ void PairGranularMulti::allocate() void PairGranularMulti::settings(int narg, char **arg) { if (narg == 1){ - cutoff_global = force->numeric(FLERR,arg[0]) + cutoff_global = force->numeric(FLERR,arg[0]); } else{ cutoff_global = -1; //Will be set based on particle sizes, model choice @@ -673,10 +673,10 @@ void PairGranularMulti::coeff(int narg, char **arg) { int normal_local, damping_local, tangential_local, roll_local, twist_local; - normal_coeffs_local = new double[4]; - tangential_coeffs_local = new double[4]; - roll_coeffs_local = new double[4]; - twist_coeffs_local = new double[4]; + double normal_coeffs_local[4]; + double tangential_coeffs_local[4]; + double roll_coeffs_local[4]; + double twist_coeffs_local[4]; if (narg < 2) error->all(FLERR,"Incorrect args for pair coefficients"); @@ -739,7 +739,7 @@ void PairGranularMulti::coeff(int narg, char **arg) } else if (strcmp(arg[iarg], "damp") == 0){ if (iarg+1 >= narg) error->all(FLERR, "Illegal pair_coeff command, not enough parameters provided for damping model"); - if (strcmp(arg[iarg+1]), "velocity") == 0){ + if (strcmp(arg[iarg+1], "velocity") == 0){ damping_local = VELOCITY; iarg += 1; } @@ -787,9 +787,9 @@ void PairGranularMulti::coeff(int narg, char **arg) else{ error->all(FLERR, "Illegal pair_coeff command, rolling friction model not recognized"); } - roll_coeffs_local[0] = force->numeric(FLERR,arg[iarg+2]); //kt - roll_coeffs_local[1] = force->numeric(FLERR,arg[iarg+3]); //gammat - roll_coeffs_local[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. + roll_coeffs_local[0] = force->numeric(FLERR,arg[iarg+2]); //kR + roll_coeffs_local[1] = force->numeric(FLERR,arg[iarg+3]); //gammaR + roll_coeffs_local[2] = force->numeric(FLERR,arg[iarg+4]); //rolling friction coeff. iarg += 5; } } @@ -826,7 +826,7 @@ void PairGranularMulti::coeff(int narg, char **arg) } //It is an error not to specify normal or tangential model - if ((normal_set < 0) || (tangential_set < 0)) error->all(FLERR, "Illegal pair coeff command, must specify normal contact model");)) + if ((normal_local < 0) || (tangential_local < 0)) error->all(FLERR, "Illegal pair coeff command, must specify normal contact model"); int count = 0; double damp; From e195d6faee7346034d234b620bae670c52a11425 Mon Sep 17 00:00:00 2001 From: "Dan S. Bolintineanu" Date: Wed, 30 Jan 2019 08:37:04 -0700 Subject: [PATCH 17/44] Fixed issue with not setting i-j, j-i coefficients correctly --- src/GRANULAR/pair_granular.cpp | 28 ++++++++++---------- src/GRANULAR/pair_granular_multi.cpp | 38 ++++++++++++++-------------- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/GRANULAR/pair_granular.cpp b/src/GRANULAR/pair_granular.cpp index c2f202ac9c..82a470f83b 100644 --- a/src/GRANULAR/pair_granular.cpp +++ b/src/GRANULAR/pair_granular.cpp @@ -1571,22 +1571,22 @@ void PairGranular::coeff(int narg, char **arg) for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { - normal_coeffs[i][j][0] = normal_coeffs_local[0]; - normal_coeffs[i][j][1] = damp; + normal_coeffs[i][j][0] = normal_coeffs[j][i][0] = normal_coeffs_local[0]; + normal_coeffs[i][j][1] = normal_coeffs[j][i][1] = damp; if (normal != HERTZ && normal != HOOKE) normal_coeffs[i][j][2] = normal_coeffs_local[2]; if ((normal == JKR) || (normal == DMT)) - normal_coeffs[i][j][3] = normal_coeffs_local[3]; + normal_coeffs[i][j][3] = normal_coeffs[j][i][3] = normal_coeffs_local[3]; for (int k = 0; k < 3; k++) - tangential_coeffs[i][j][k] = tangential_coeffs_local[k]; + tangential_coeffs[i][j][k] = tangential_coeffs[j][i][k] = tangential_coeffs_local[k]; if (roll != ROLL_NONE) for (int k = 0; k < 3; k++) - roll_coeffs[i][j][k] = roll_coeffs_local[k]; + roll_coeffs[i][j][k] = roll_coeffs[j][i][k] = roll_coeffs_local[k]; if (twist != TWIST_NONE && twist != TWIST_MARSHALL) for (int k = 0; k < 3; k++) - twist_coeffs[i][j][k] = twist_coeffs_local[k]; + twist_coeffs[i][j][k] = twist_coeffs[j][i][k] = twist_coeffs_local[k]; setflag[i][j] = 1; count++; @@ -1746,31 +1746,31 @@ double PairGranular::init_one(int i, int j) if (setflag[i][j] == 0) { if (normal != HOOKE && normal != HERTZ){ - normal_coeffs[i][j][0] = mix_stiffnessE(normal_coeffs[i][i][0], normal_coeffs[j][j][0], + normal_coeffs[i][j][0] = normal_coeffs[j][i][0] = mix_stiffnessE(normal_coeffs[i][i][0], normal_coeffs[j][j][0], normal_coeffs[i][i][2], normal_coeffs[j][j][2]); - normal_coeffs[i][j][2] = mix_stiffnessG(normal_coeffs[i][i][0], normal_coeffs[j][j][0], + normal_coeffs[i][j][2] = normal_coeffs[j][i][2] = mix_stiffnessG(normal_coeffs[i][i][0], normal_coeffs[j][j][0], normal_coeffs[i][i][2], normal_coeffs[j][j][2]); } else{ - normal_coeffs[i][j][0] = mix_geom(normal_coeffs[i][i][0], normal_coeffs[j][j][0]); + normal_coeffs[i][j][0] = normal_coeffs[j][i][0] = mix_geom(normal_coeffs[i][i][0], normal_coeffs[j][j][0]); } - normal_coeffs[i][j][1] = mix_geom(normal_coeffs[i][i][1], normal_coeffs[j][j][1]); + normal_coeffs[i][j][1] = normal_coeffs[j][i][1] = mix_geom(normal_coeffs[i][i][1], normal_coeffs[j][j][1]); if ((normal == JKR) || (normal == DMT)) - normal_coeffs[i][j][3] = mix_geom(normal_coeffs[i][i][3], normal_coeffs[j][j][3]); + normal_coeffs[i][j][3] = normal_coeffs[j][i][3] = mix_geom(normal_coeffs[i][i][3], normal_coeffs[j][j][3]); for (int k = 0; k < 3; k++) - tangential_coeffs[i][j][k] = mix_geom(tangential_coeffs[i][i][k], tangential_coeffs[j][j][k]); + tangential_coeffs[i][j][k] = tangential_coeffs[j][i][k] = mix_geom(tangential_coeffs[i][i][k], tangential_coeffs[j][j][k]); if (roll != ROLL_NONE){ for (int k = 0; k < 3; k++) - roll_coeffs[i][j][k] = mix_geom(roll_coeffs[i][i][k], roll_coeffs[j][j][k]); + roll_coeffs[i][j][k] = roll_coeffs[j][i][k] = mix_geom(roll_coeffs[i][i][k], roll_coeffs[j][j][k]); } if (twist != TWIST_NONE && twist != TWIST_MARSHALL){ for (int k = 0; k < 3; k++) - twist_coeffs[i][j][k] = mix_geom(twist_coeffs[i][i][k], twist_coeffs[j][j][k]); + twist_coeffs[i][j][k] = twist_coeffs[j][i][k] = mix_geom(twist_coeffs[i][i][k], twist_coeffs[j][j][k]); } } diff --git a/src/GRANULAR/pair_granular_multi.cpp b/src/GRANULAR/pair_granular_multi.cpp index 09b8ea9709..07a6cab3dd 100644 --- a/src/GRANULAR/pair_granular_multi.cpp +++ b/src/GRANULAR/pair_granular_multi.cpp @@ -841,28 +841,28 @@ void PairGranularMulti::coeff(int narg, char **arg) for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { - normal[i][j] = normal_local; - normal_coeffs[i][j][0] = normal_coeffs_local[0]; - normal_coeffs[i][j][1] = damp; + normal[i][j] = normal[j][i] = normal_local; + normal_coeffs[i][j][0] = normal_coeffs[j][i][0] = normal_coeffs_local[0]; + normal_coeffs[i][j][1] = normal_coeffs[j][i][1] = damp; if (normal_local != HERTZ && normal_local != HOOKE) normal_coeffs[i][j][2] = normal_coeffs_local[2]; if ((normal_local == JKR) || (normal_local == DMT)) - normal_coeffs[i][j][3] = normal_coeffs_local[3]; + normal_coeffs[i][j][3] = normal_coeffs[j][i][3] = normal_coeffs_local[3]; - damping[i][j] = damping_local; + damping[i][j] = damping[j][i] = damping_local; - tangential[i][j] = tangential_local; + tangential[i][j] = tangential[j][i] = tangential_local; for (int k = 0; k < 3; k++) - tangential_coeffs[i][j][k] = tangential_coeffs_local[k]; + tangential_coeffs[i][j][k] = tangential_coeffs[j][i][k] = tangential_coeffs_local[k]; - roll[i][j] = roll_local; + roll[i][j] = roll[j][i] = roll_local; if (roll_local != ROLL_NONE) for (int k = 0; k < 3; k++) - roll_coeffs[i][j][k] = roll_coeffs_local[k]; + roll_coeffs[i][j][k] = roll_coeffs[j][i][k] = roll_coeffs_local[k]; - twist[i][j] = twist_local; + twist[i][j] = twist[j][i] = twist_local; if (twist_local != TWIST_NONE && twist_local != TWIST_MARSHALL) for (int k = 0; k < 3; k++) - twist_coeffs[i][j][k] = twist_coeffs_local[k]; + twist_coeffs[i][j][k] = twist_coeffs[j][i][k] = twist_coeffs_local[k]; setflag[i][j] = 1; count++; @@ -1033,31 +1033,31 @@ double PairGranularMulti::init_one(int i, int j) } if (normal[i][j] != HOOKE && normal[i][j] != HERTZ){ - normal_coeffs[i][j][0] = mix_stiffnessE(normal_coeffs[i][i][0], normal_coeffs[j][j][0], + normal_coeffs[i][j][0] = normal_coeffs[j][i][0] = mix_stiffnessE(normal_coeffs[i][i][0], normal_coeffs[j][j][0], normal_coeffs[i][i][2], normal_coeffs[j][j][2]); - normal_coeffs[i][j][2] = mix_stiffnessG(normal_coeffs[i][i][0], normal_coeffs[j][j][0], + normal_coeffs[i][j][2] = normal_coeffs[j][i][2] = mix_stiffnessG(normal_coeffs[i][i][0], normal_coeffs[j][j][0], normal_coeffs[i][i][2], normal_coeffs[j][j][2]); } else{ - normal_coeffs[i][j][0] = mix_geom(normal_coeffs[i][i][0], normal_coeffs[j][j][0]); + normal_coeffs[i][j][0] = normal_coeffs[j][i][0] = mix_geom(normal_coeffs[i][i][0], normal_coeffs[j][j][0]); } - normal_coeffs[i][j][1] = mix_geom(normal_coeffs[i][i][1], normal_coeffs[j][j][1]); + normal_coeffs[i][j][1] = normal_coeffs[j][i][1] = mix_geom(normal_coeffs[i][i][1], normal_coeffs[j][j][1]); if ((normal[i][i] == JKR) || (normal[i][i] == DMT)) - normal_coeffs[i][j][3] = mix_geom(normal_coeffs[i][i][3], normal_coeffs[j][j][3]); + normal_coeffs[i][j][3] = normal_coeffs[j][i][3] = mix_geom(normal_coeffs[i][i][3], normal_coeffs[j][j][3]); for (int k = 0; k < 3; k++) - tangential_coeffs[i][j][k] = mix_geom(tangential_coeffs[i][i][k], tangential_coeffs[j][j][k]); + tangential_coeffs[i][j][k] = normal_coeffs[j][i][k] = mix_geom(tangential_coeffs[i][i][k], tangential_coeffs[j][j][k]); if (roll[i][i] != ROLL_NONE){ for (int k = 0; k < 3; k++) - roll_coeffs[i][j][k] = mix_geom(roll_coeffs[i][i][k], roll_coeffs[j][j][k]); + roll_coeffs[i][j][k] = roll_coeffs[j][i][k] = mix_geom(roll_coeffs[i][i][k], roll_coeffs[j][j][k]); } if (twist[i][i] != TWIST_NONE && twist[i][i] != TWIST_MARSHALL){ for (int k = 0; k < 3; k++) - twist_coeffs[i][j][k] = mix_geom(twist_coeffs[i][i][k], twist_coeffs[j][j][k]); + twist_coeffs[i][j][k] = twist_coeffs[j][i][k] = mix_geom(twist_coeffs[i][i][k], twist_coeffs[j][j][k]); } } From b7413226e0a42db8fa5030a3aecb944760a05bcf Mon Sep 17 00:00:00 2001 From: "Dan S. Bolintineanu" Date: Mon, 11 Feb 2019 21:37:06 -0700 Subject: [PATCH 18/44] Several changes to new consolidated granular code: - Normal contact models take Young's modulus and Poisson's ratio (instead of Young's and shear modulus) - Mixing of Young's moduli corrected - Changes to cutoffs corrected for JKR pulloff distance - Renamed 'mindlin' to 'linear_history' - Progress on doc page --- doc/src/pair_granular.txt | 423 ++---- doc/src/pairs.txt | 1 + src/GRANULAR/pair_granular.cpp | 1168 ++++------------ src/GRANULAR/pair_granular.h | 53 +- src/pair_granular.cpp | 2337 ++++++++++++++++++++++++++++++++ src/pair_granular.h | 120 ++ 6 files changed, 2868 insertions(+), 1234 deletions(-) create mode 100644 src/pair_granular.cpp create mode 100644 src/pair_granular.h diff --git a/doc/src/pair_granular.txt b/doc/src/pair_granular.txt index 35b64bf29d..8bf4f20d5d 100644 --- a/doc/src/pair_granular.txt +++ b/doc/src/pair_granular.txt @@ -1,3 +1,10 @@ + + + "LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c :link(lws,http://lammps.sandia.gov) @@ -14,323 +21,185 @@ pair_style granular/multi command :h3 pair_style style cutoff :pre style = {granular} or {granular/multi} :ulb,l -cutoff = global cutoff (optional). See discussion below. +cutoff = global cutoff (optional). See discussion below. :l +:ule [Examples:] pair_style granular -pair coeff 1 1 hertz 1000.0 50.0 tangential mindlin 800.0 50.0 0.5 rolling sds 500.0 200.0 0.5 twisting marshall -pair coeff 2 2 hertz 200.0 20.0 tangential mindlin 300.0 50.0 0.1 rolling sds 200.0 100.0 0.1 twisting marshall +pair_coeff * * hertz 1000.0 50.0 tangential mindlin 800.0 50.0 0.4 :pre + +pair_style granular +pair_coeff 1 1 hertz 1000.0 50.0 tangential mindlin 800.0 50.0 0.5 rolling sds 500.0 200.0 0.5 twisting marshall +pair_coeff 2 2 hertz 200.0 20.0 tangential mindlin 300.0 50.0 0.1 rolling sds 200.0 100.0 0.1 twisting marshall :pre pair_style granular/multi -pair coeff 1 1 hertz 1000.0 50.0 tangential mindlin 800.0 50.0 0.5 rolling sds 500.0 200.0 0.5 twisting marshall -pair coeff 2 2 dmt 1000.0 50.0 800.0 10.0 tangential mindlin 800.0 50.0 0.1 roll sds 500.0 200.0 0.1 twisting marshall -pair coeff 1 2 dmt 1000.0 50.0 800.0 10.0 tangential mindlin 800.0 50.0 0.1 roll sds 500.0 200.0 0.1 twisting marshall +pair_coeff 1 1 hertz 1000.0 50.0 tangential mindlin 800.0 50.0 0.5 rolling sds 500.0 200.0 0.5 twisting marshall +pair_coeff 2 2 dmt 1000.0 50.0 800.0 10.0 tangential mindlin 800.0 50.0 0.1 roll sds 500.0 200.0 0.1 twisting marshall +pair_coeff 1 2 dmt 1000.0 50.0 800.0 10.0 tangential mindlin 800.0 50.0 0.1 roll sds 500.0 200.0 0.1 twisting marshall :pre [Description:] The {granular} styles support a variety of options for the normal, tangential, rolling and twisting -forces resulting from contact between two granular particles. The computed force depends on the combination -of choices for these models. +forces resulting from contact between two granular particles. This expands on the options offered +by the "pair gran/*"_pair_gran.html options. The total computed forces and torques depend on the combination +of choices for these various modes of motion. All model options and parameters are entered in the "pair_coeff"_pair_coeff.html command, as described below. Unlike e.g. "pair gran/hooke"_pair_gran.html, coefficient values are not global, but can be set to different values for various combinations of particle types, as determined by the "pair_coeff"_pair_coeff.html command. -In the case of {granular}, coefficients -can vary between particle types, but model choices cannot. For instance, in the first -example above, the stiffness, damping, and tangential friction are different for type 1 - type 1 and type 2 - type 2 interactions, but -both 1-1 and 2-2 interactions must have the same model form, hence all keywords are identical between the two types. Cross-coefficients -for 1-2 interactions for the case of the {hertz} model above are set via simple geometric mixing rules. The {granular/multi} +For {pair_style granular}, coefficients can vary between particle types, but model choices +cannot. For instance, in the first +example above, the stiffness, damping, and tangential friction are different for +type 1 - type 1 and type 2 - type 2 interactions, but +both 1-1 and 2-2 interactions must have the same model form, hence all keywords are +identical between the two types. Cross-coefficients +for 1-2 interactions for the case of the {hertz} model above are set via simple +geometric mixing rules. The {granular/multi} style removes this restriction at a small cost in computational efficiency, so that different particle types can potentially interact via different model forms. As shown in the second example, 1-1 interactions are based on a Hertzian contact model and 2-2 interactions are based on a {dmt} model (see below). In the case that 1-1 and 2-2 interactions have different model forms, mixing of coefficients cannot be determined, so 1-2 interactions must be explicitly defined via the pair coeff command, otherwise an error results. -The first required keyword for the pair coeff command is the normal contact model. Currently supported options and -the required arguments are: +:line -{hooke} : k_n, damping -{hertz} : k_n, damping +The first required keyword for the {pair_coeff} command is the normal contact model. Currently supported options +for normal contact models and their required arguments are: + +{hooke} : \(k_n\), damping +{hertz} : \(k_n\), damping {hertz/material} : E, damping, G {dmt} : E, damping, G, cohesion -{jkr} : E, damping, G, cohesion +{jkr} : E, damping, G, cohesion :ol -Here, k_n is spring stiffness, damping is a damping constant or a coefficient of restitution, depending on +Here, \(k_n\) is spring stiffness, damping is a damping constant or a coefficient of restitution, depending on the choice of damping model (see below), E and G are Young's modulus and shear modulus, in units of pressure, and cohesion is a surface energy density, in units of energy/length^2. -For the {hooke} model, the normal component of force is given by: -:c,image(Eqs/hooke_normal.jpg) +For the {hooke} model, the normal (elastic) component of force between two particles {i} and {j} is given by: +\begin\{equation\} +\mathbf\{F\}_\{ne, Hooke\} = k_N \delta_\{ij\} \mathbf\{n\} +\end\{equation\} -For {hertz}, the normal force is given by: -:c,image{Eqs/hertz_normal.jpg} +Where \(\delta = R_i + R_j - \|\mathbf\{r\}_\{ij\}\|\) is the particle overlap, +\(R_i, R_j\) are the particle radii, +\(\mathbf\{r\}_\{ij\} = \mathbf\{r\}_j - \mathbf\{r\}_i\) is the vector separating the +two particle centers +and \(\mathbf\{n\} = \frac\{\mathbf\{r\}_\{ij\}\}\{\|\mathbf\{r\}_\{ij\}\|\}\). -For both [hooke] and [hertz], stiffness for unspecified cross-terms is given by simple geometric mixing -(e.g. if stiffness is specified for type 1 and type 2 particles as k_n_1 and k_n_2, respectively, -type 1 - type 2 contacts use a stiffness given by k_n_{12} = sqrt(k_n_1*k_n_2)) +For the {hertz} model, the normal component of force is given by: +\begin\{equation\} +\mathbf\{F\}_\{ne, Hertz\} = k_N R_\{eff\}^\{1/2\}\delta_\{ij\}^\{3/2\} \mathbf\{n\} +\end\{equation\} -For {hertz/material}, the form is the same as above, but coefficients are computed differently, and mixing follows -a different rule based on shear modulus: -:c,image{Eqs/hertz_material_normal.jpg} +Here, \(R_\{eff\} = \frac\{R_i R_j\}\{R_i + R_j\}\) is the effective radius, denoted for simplicity as {R} from here on. -For {dmt}, the normal force is given by: -:c,image{Eqs/dmt_normal.jpg} +For the {hertz/material} model, the force is given by: +\begin\{equation\} +\mathbf\{F\}_\{ne, Hertz/material\} = \frac\{4\}\{3\} E_\{eff\} R_\{eff\}^\{1/2\}\delta_\{ij\}^\{3/2\} \mathbf\{n\} +\end\{equation\} -Where gamma is cohesion. +Here, \(E_\{eff\} = E = \left(\frac\{1-\nu_i^2\}\{E_i\} + \frac\{1-\nu_j^2\}\{E_j\}\right)^\{-1\}\) +is the effectve Young's modulus, +with \(\nu_i, \nu_j \) the Poisson ratios of the particles, which are related to the +input shear and Young's moduli by \(\nu_i = E_i/2G_i - 1\). Thus, if the elastic and shear moduli of the +two particles are the same, the {hertz/material} +model is equivalent to the {hertz} model with \(k_N = 4/3 E_\{eff\}\) -For {jkr}, the normal force is given by: -:c,image{Eqs/jkr_normal.jpg} +The {dmt} model corresponds to the Derjaguin-Muller-Toporov model, +where the force is simply Hertz with an additional attractive cohesion term: +\begin\{equation\} +\mathbf\{F\}_\{ne, dmt\} = \left(\frac\{4\}\{3\} E R^\{1/2\}\delta_\{ij\}^\{3/2\} - 4\pi\gamma R\right)\mathbf\{n\} +\end\{equation\} -The same mixing rule for stiffness as for {hertz/material} is used by both the {dmt} and {jkr} models. +The {jkr} model is the Johnson-Kendall-Roberts model, where the force is computed as: +\begin\{equation\} +\label\{eq:force_jkr\} +\mathbf\{F\}_\{ne, jkr\} = \left(\frac\{4Ea^3\}\{3R\} - 2\pi a^2\sqrt\{\frac\{4\gamma E\}\{\pi a\}\}\right)\mathbf\{n\} +\end\{equation\} + +Here, {a} is the radius of the contact zone, related to the overlap \(\delta\) according to: +\begin\{equation\} +\delta = a^2/R - 2\sqrt\{\pi \gamma a/E\} +\end\{equation\} -The tangential contact model must also be specified, which follows -the required {tangential} keyword. Currently supported options -and their required arguments are: +LAMMPS internally inverts the equation above to solve for {a} in terms of \(\delta\), then solves for +the force in the previous equation. Additionally, note that the JKR model allows for a tensile force beyond +contact (i.e. for \(\delta < 0\)), up to a maximum tensile force of \(-3\pi\gamma R\) (also known as +the 'pull-off' force). +Note that this is a hysteretic effect, where particles that are not contacting initially +will not experience force until they come into contact \(\delta \geq 0\); as they move apart +and (\(\delta < 0\)), they experience a tensile force up to \(-3\pi\gamma R\), +at which point they will lose contact. -{no_history}: k_t, tangential_damping, friction coefficient -{mindlin}: k_t, tangential_damping, friction coefficient +In addition to the above options, the normal force is augmented by a damping term. The optional +{damping} keyword to the {pair_coeff} command followed by the model choice determines the form of the damping. +The damping coefficient that was specified for the normal model +settings is used in computing the damping term, as described below. Note this damping parameter +may be interpreted differently depending on the model choice. +The options for the damping model currently supported are: + +{velocity} +{viscoelastic} +{tsuji} :ol + +If the {damping} keyword is not specified, the {viscoelastic} model is used by default. + +For {damping velocity}, the normal damping is simply proportional to the velocity: +\begin\{equation\} +F_\{N,damp\} = -\gamma_N\mathbf\{v\}_\{N,rel\} +\end\{equation\} + +Here, \(\gamma_N\) is the damping coefficient, in units of {mass}/{time}, +\(\mathbf\{v\}_\{N,rel\} = (\mathbf\{v\}_i - \mathbf\{v\}_j) \cdot \mathbf\{n\}\) +is the component of relative velocity along the direction of the vector \(\mathbf\{n\}\) that connects the centers of +particles {i} and {j}. + +The {damping viscoelastic} model is based on the viscoelastic treatment of "(Brilliantov et al)"_#Brill1996, +where the normal damping is given by: +\begin\{equation\} +F_\{N,damp\} = -\gamma_N a m_\{eff\} \mathbf\{v\}_\{N,rel\} +\end\{equation\} + +Here, \(m_\{eff\} = m_i m_j/(m_i + m_j)\) is the effective mass, {a} is the contact radius, given by \(a =\sqrt\{R\delta\}\) +for all models except {jkr}, for which it is given implicitly according to \(delta = a^2/R - 2\sqrt\{\pi \gamma a/E\}\). +In this case, \(\gamma_N\) is the damping coefficient, in units of 1/({time}*{distance}). + +The {tsuji} model is based on the work of "(Tsuji et al)"_#Tsuji1992. Here, the + + :line + +Following the normal contact model settings, the {pair_coeff} command requires specification +of the tangential contact model. The required keyword {tangential} is expected, followed by the model choice and associated +parameters. Currently supported tangential model choices and their expected parameters are as follows: -For {no_history}, the tangential force is computed according to: -:c,image{Eqs/tangential_nohistory.jpg} +{nohistory} : \(\gamma_t\), \(\mu_s\) +{history} : \(k_t\), \(\gamma_t\), \(\mu_s\) :ol -For {mindlin}, tangential force is: -:c,image{Eqs/tangential_mindlin.jpg} +Here, \(\gamma_t\) is the tangential damping coefficient, \(\mu_s\) is the tangential (or sliding) friction +coefficient, and \(k_t\) is the tangential stiffness. -The total force on a particle is the sum of the normal and tangential forces from all interactions. The tangential -force also induces a torque on both particles in a contacting pair. Additionally, rolling and twisting friction -models can also be applied, which may induce additional torques (but no force). The following options are -supported for the rolling friction model +For {nohistory}, a simple velocity-dependent Coulomb friction criterion is used, which reproduces the behavior +of the {pair gran/hooke} style. The tangential force (\mathbf\{F\}_t\) is given by: +\begin\{equation\} +\mathbf\{F\}_t = -min(\mu_s \|\mathbf\{F\}_n\|, \gamma_t m_\{eff\}\|\mathbf\{v\}_\{t, rel\}\|) \mathbf\{t\} +\end\{equation\} + +Where \(\|\mathbf\{F\}_n\) is the magnitude of the normal force, +\(\mathbf\{v\}_\{t, rel\} = \mathbf\{v\}_\{t\} - (R_i\Omega_i + R_j\Omega_j) \times \mathbf\{n\}\) is the relative tangential +velocity at the point of contact, \(\mathbf\{v\}_\{t\} = \mathbf\{v\}_n - \) + + + :link(Brill1996) +[(Brilliantov et al, 1996)] Brilliantov, N. V., Spahn, F., Hertzsch, J. M., & Poschel, T. (1996). +Model for collisions in granular gases. Physical review E, 53(5), 5382. -The first required keyword -in the pair coeff command is the choice -of normal force contact model, for which current opitons are {hooke}, {hertz} + :link(Tsuji1992) + [(Tsuji et al, 1992)] Tsuji, Y., Tanaka, T., & Ishida, T. (1992). Lagrangian numerical simulation of plug flow of + cohesionless particles in a horizontal pipe. Powder technology, 71(3), 239-250. -The {gran} styles use the following formulas for the frictional force -between two granular particles, as described in -"(Brilliantov)"_#Brilliantov, "(Silbert)"_#Silbert, and -"(Zhang)"_#Zhang3, when the distance r between two particles of radii -Ri and Rj is less than their contact distance d = Ri + Rj. There is -no force between the particles when r > d. - -The two Hookean styles use this formula: - -:c,image(Eqs/pair_gran_hooke.jpg) - -The Hertzian style uses this formula: - -:c,image(Eqs/pair_gran_hertz.jpg) - -In both equations the first parenthesized term is the normal force -between the two particles and the second parenthesized term is the -tangential force. The normal force has 2 terms, a contact force and a -damping force. The tangential force also has 2 terms: a shear force -and a damping force. The shear force is a "history" effect that -accounts for the tangential displacement between the particles for the -duration of the time they are in contact. This term is included in -pair styles {hooke/history} and {hertz/history}, but is not included -in pair style {hooke}. The tangential damping force term is included -in all three pair styles if {dampflag} is set to 1; it is not included -if {dampflag} is set to 0. - -The other quantities in the equations are as follows: - -delta = d - r = overlap distance of 2 particles -Kn = elastic constant for normal contact -Kt = elastic constant for tangential contact -gamma_n = viscoelastic damping constant for normal contact -gamma_t = viscoelastic damping constant for tangential contact -m_eff = Mi Mj / (Mi + Mj) = effective mass of 2 particles of mass Mi and Mj -Delta St = tangential displacement vector between 2 particles \ - which is truncated to satisfy a frictional yield criterion -n_ij = unit vector along the line connecting the centers of the 2 particles -Vn = normal component of the relative velocity of the 2 particles -Vt = tangential component of the relative velocity of the 2 particles :ul - -The Kn, Kt, gamma_n, and gamma_t coefficients are specified as -parameters to the pair_style command. If a NULL is used for Kt, then -a default value is used where Kt = 2/7 Kn. If a NULL is used for -gamma_t, then a default value is used where gamma_t = 1/2 gamma_n. - -The interpretation and units for these 4 coefficients are different in -the Hookean versus Hertzian equations. - -The Hookean model is one where the normal push-back force for two -overlapping particles is a linear function of the overlap distance. -Thus the specified Kn is in units of (force/distance). Note that this -push-back force is independent of absolute particle size (in the -monodisperse case) and of the relative sizes of the two particles (in -the polydisperse case). This model also applies to the other terms in -the force equation so that the specified gamma_n is in units of -(1/time), Kt is in units of (force/distance), and gamma_t is in units -of (1/time). - -The Hertzian model is one where the normal push-back force for two -overlapping particles is proportional to the area of overlap of the -two particles, and is thus a non-linear function of overlap distance. -Thus Kn has units of force per area and is thus specified in units of -(pressure). The effects of absolute particle size (monodispersity) -and relative size (polydispersity) are captured in the radii-dependent -pre-factors. When these pre-factors are carried through to the other -terms in the force equation it means that the specified gamma_n is in -units of (1/(time*distance)), Kt is in units of (pressure), and -gamma_t is in units of (1/(time*distance)). - -Note that in the Hookean case, Kn can be thought of as a linear spring -constant with units of force/distance. In the Hertzian case, Kn is -like a non-linear spring constant with units of force/area or -pressure, and as shown in the "(Zhang)"_#Zhang3 paper, Kn = 4G / -(3(1-nu)) where nu = the Poisson ratio, G = shear modulus = E / -(2(1+nu)), and E = Young's modulus. Similarly, Kt = 4G / (2-nu). -(NOTE: in an earlier version of the manual, we incorrectly stated that -Kt = 8G / (2-nu).) - -Thus in the Hertzian case Kn and Kt can be set to values that -corresponds to properties of the material being modeled. This is also -true in the Hookean case, except that a spring constant must be chosen -that is appropriate for the absolute size of particles in the model. -Since relative particle sizes are not accounted for, the Hookean -styles may not be a suitable model for polydisperse systems. - -NOTE: In versions of LAMMPS before 9Jan09, the equation for Hertzian -interactions did not include the sqrt(RiRj/Ri+Rj) term and thus was -not as accurate for polydisperse systems. For monodisperse systems, -sqrt(RiRj/Ri+Rj) is a constant factor that effectively scales all 4 -coefficients: Kn, Kt, gamma_n, gamma_t. Thus you can set the values -of these 4 coefficients appropriately in the current code to reproduce -the results of a previous Hertzian monodisperse calculation. For -example, for the common case of a monodisperse system with particles -of diameter 1, all 4 of these coefficients should now be set 2x larger -than they were previously. - -Xmu is also specified in the pair_style command and is the upper limit -of the tangential force through the Coulomb criterion Ft = xmu*Fn, -where Ft and Fn are the total tangential and normal force components -in the formulas above. Thus in the Hookean case, the tangential force -between 2 particles grows according to a tangential spring and -dash-pot model until Ft/Fn = xmu and is then held at Ft = Fn*xmu until -the particles lose contact. In the Hertzian case, a similar analogy -holds, though the spring is no longer linear. - -NOTE: Normally, xmu should be specified as a fractional value between -0.0 and 1.0, however LAMMPS allows large values (up to 1.0e4) to allow -for modeling of systems which can sustain very large tangential -forces. - -The effective mass {m_eff} is given by the formula above for two -isolated particles. If either particle is part of a rigid body, its -mass is replaced by the mass of the rigid body in the formula above. -This is determined by searching for a "fix rigid"_fix_rigid.html -command (or its variants). - -For granular styles there are no additional coefficients to set for -each pair of atom types via the "pair_coeff"_pair_coeff.html command. -All settings are global and are made via the pair_style command. -However you must still use the "pair_coeff"_pair_coeff.html for all -pairs of granular atom types. For example the command - -pair_coeff * * :pre - -should be used if all atoms in the simulation interact via a granular -potential (i.e. one of the pair styles above is used). If a granular -potential is used as a sub-style of "pair_style -hybrid"_pair_hybrid.html, then specific atom types can be used in the -pair_coeff command to determine which atoms interact via a granular -potential. - -:line - -Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are -functionally the same as the corresponding style without the suffix. -They have been optimized to run faster, depending on your available -hardware, as discussed on the "Speed packages"_Speed_packages.html doc -page. The accelerated styles take the same arguments and should -produce the same results, except for round-off and precision issues. - -These accelerated styles are part of the GPU, USER-INTEL, KOKKOS, -USER-OMP and OPT packages, respectively. They are only enabled if -LAMMPS was built with those packages. See the "Build -package"_Build_package.html doc page for more info. - -You can specify the accelerated styles explicitly in your input script -by including their suffix, or you can use the "-suffix command-line -switch"_Run_options.html when you invoke LAMMPS, or you can use the -"suffix"_suffix.html command in your input script. - -See the "Speed packages"_Speed_packages.html doc page for more -instructions on how to use the accelerated styles effectively. - -:line - -[Mixing, shift, table, tail correction, restart, rRESPA info]: - -The "pair_modify"_pair_modify.html mix, shift, table, and tail options -are not relevant for granular pair styles. - -These pair styles write their information to "binary restart -files"_restart.html, so a pair_style command does not need to be -specified in an input script that reads a restart file. - -These pair styles can only be used via the {pair} keyword of the -"run_style respa"_run_style.html command. They do not support the -{inner}, {middle}, {outer} keywords. - -The single() function of these pair styles returns 0.0 for the energy -of a pairwise interaction, since energy is not conserved in these -dissipative potentials. It also returns only the normal component of -the pairwise interaction force. However, the single() function also -calculates 10 extra pairwise quantities. The first 3 are the -components of the tangential force between particles I and J, acting -on particle I. The 4th is the magnitude of this tangential force. -The next 3 (5-7) are the components of the relative velocity in the -normal direction (along the line joining the 2 sphere centers). The -last 3 (8-10) the components of the relative velocity in the -tangential direction. - -These extra quantities can be accessed by the "compute -pair/local"_compute_pair_local.html command, as {p1}, {p2}, ..., -{p10}. - -:line - -[Restrictions:] - -All the granular pair styles are part of the GRANULAR package. It is -only enabled if LAMMPS was built with that package. See the "Build -package"_Build_package.html doc page for more info. - -These pair styles require that atoms store torque and angular velocity -(omega) as defined by the "atom_style"_atom_style.html. They also -require a per-particle radius is stored. The {sphere} atom style does -all of this. - -This pair style requires you to use the "comm_modify vel -yes"_comm_modify.html command so that velocities are stored by ghost -atoms. - -These pair styles will not restart exactly when using the -"read_restart"_read_restart.html command, though they should provide -statistically similar results. This is because the forces they -compute depend on atom velocities. See the -"read_restart"_read_restart.html command for more details. - -[Related commands:] - -"pair_coeff"_pair_coeff.html - -[Default:] none - -:line - -:link(Brilliantov) -[(Brilliantov)] Brilliantov, Spahn, Hertzsch, Poschel, Phys Rev E, 53, -p 5382-5392 (1996). - -:link(Silbert) -[(Silbert)] Silbert, Ertas, Grest, Halsey, Levine, Plimpton, Phys Rev -E, 64, p 051302 (2001). - -:link(Zhang3) -[(Zhang)] Zhang and Makse, Phys Rev E, 72, p 011301 (2005). + + \ No newline at end of file diff --git a/doc/src/pairs.txt b/doc/src/pairs.txt index ca79051053..3cd20c728d 100644 --- a/doc/src/pairs.txt +++ b/doc/src/pairs.txt @@ -41,6 +41,7 @@ Pair Styles :h1 pair_gauss pair_gayberne pair_gran + pair_granular pair_gromacs pair_gw pair_hbond_dreiding diff --git a/src/GRANULAR/pair_granular.cpp b/src/GRANULAR/pair_granular.cpp index 82a470f83b..3713b9251c 100644 --- a/src/GRANULAR/pair_granular.cpp +++ b/src/GRANULAR/pair_granular.cpp @@ -11,8 +11,9 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- -Contributing authors: Leo Silbert (SNL), Gary Grest (SNL), - Jeremy Lechman (SNL), Dan Bolintineanu (SNL), Ishan Srivastava (SNL) +Contributing authors: +Dan Bolintineanu (SNL), Ishan Srivastava (SNL), Jeremy Lechman(SNL) +Leo Silbert (SNL), Gary Grest (SNL) ----------------------------------------------------------------------- */ #include @@ -50,7 +51,7 @@ using namespace MathConst; enum {HOOKE, HERTZ, HERTZ_MATERIAL, DMT, JKR}; enum {VELOCITY, VISCOELASTIC, TSUJI}; -enum {TANGENTIAL_NOHISTORY, TANGENTIAL_MINDLIN}; +enum {TANGENTIAL_NOHISTORY, TANGENTIAL_HISTORY, TANGENTIAL_MINDLIN}; enum {TWIST_NONE, TWIST_NOHISTORY, TWIST_SDS, TWIST_MARSHALL}; enum {ROLL_NONE, ROLL_NOHISTORY, ROLL_SDS}; @@ -98,13 +99,24 @@ PairGranular::~PairGranular() if (allocated) { memory->destroy(setflag); memory->destroy(cutsq); - memory->destroy(cut); + memory->destroy(cutoff_type); memory->destroy(normal_coeffs); memory->destroy(tangential_coeffs); memory->destroy(roll_coeffs); memory->destroy(twist_coeffs); + memory->destroy(Emod); + memory->destroy(poiss); + + memory->destroy(normal_model); + memory->destroy(damping_model); + memory->destroy(tangential_model); + memory->destroy(roll_model); + memory->destroy(twist_model); + + + delete [] onerad_dynamic; delete [] onerad_frozen; delete [] maxrad_dynamic; @@ -113,725 +125,7 @@ PairGranular::~PairGranular() memory->destroy(mass_rigid); } -void PairGranular::compute(int eflag, int vflag){ -#ifdef TEMPLATED_PAIR_GRANULAR - if (normal == HOOKE){ - if (damping == VELOCITY){ - if (tangential == TANGENTIAL_NOHISTORY){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<0,0,0,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<0,0,0,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<0,0,0,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<0,0,0,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<0,0,0,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<0,0,0,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<0,0,0,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<0,0,0,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<0,0,0,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<0,0,0,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<0,0,0,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<0,0,0,3,2>(eflag, vflag); - } - } - else if (tangential == TANGENTIAL_MINDLIN){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<0,0,1,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<0,0,1,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<0,0,1,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<0,0,1,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<0,0,1,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<0,0,1,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<0,0,1,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<0,0,1,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<0,0,1,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<0,0,1,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<0,0,1,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<0,0,1,3,2>(eflag, vflag); - } - } - } - else if (damping == VISCOELASTIC){ - if (tangential == TANGENTIAL_NOHISTORY){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<0,1,0,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<0,1,0,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<0,1,0,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<0,1,0,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<0,1,0,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<0,1,0,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<0,1,0,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<0,1,0,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<0,1,0,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<0,1,0,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<0,1,0,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<0,1,0,3,2>(eflag, vflag); - } - } - else if (tangential == TANGENTIAL_MINDLIN){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<0,1,1,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<0,1,1,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<0,1,1,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<0,1,1,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<0,1,1,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<0,1,1,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<0,1,1,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<0,1,1,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<0,1,1,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<0,1,1,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<0,1,1,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<0,1,1,3,2>(eflag, vflag); - } - } - } - else if (damping == TSUJI){ - if (tangential == TANGENTIAL_NOHISTORY){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<0,2,0,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<0,2,0,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<0,2,0,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<0,2,0,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<0,2,0,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<0,2,0,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<0,2,0,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<0,2,0,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<0,2,0,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<0,2,0,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<0,2,0,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<0,2,0,3,2>(eflag, vflag); - } - } - else if (tangential == TANGENTIAL_MINDLIN){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<0,2,1,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<0,2,1,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<0,2,1,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<0,2,1,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<0,2,1,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<0,2,1,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<0,2,1,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<0,2,1,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<0,2,1,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<0,2,1,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<0,2,1,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<0,2,1,3,2>(eflag, vflag); - } - } - } - } - else if (normal == HERTZ){ - if (damping == VELOCITY){ - if (tangential == TANGENTIAL_NOHISTORY){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<1,0,0,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<1,0,0,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<1,0,0,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<1,0,0,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<1,0,0,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<1,0,0,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<1,0,0,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<1,0,0,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<1,0,0,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<1,0,0,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<1,0,0,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<1,0,0,3,2>(eflag, vflag); - } - } - else if (tangential == TANGENTIAL_MINDLIN){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<1,0,1,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<1,0,1,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<1,0,1,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<1,0,1,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<1,0,1,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<1,0,1,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<1,0,1,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<1,0,1,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<1,0,1,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<1,0,1,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<1,0,1,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<1,0,1,3,2>(eflag, vflag); - } - } - } - else if (damping == VISCOELASTIC){ - if (tangential == TANGENTIAL_NOHISTORY){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<1,1,0,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<1,1,0,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<1,1,0,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<1,1,0,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<1,1,0,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<1,1,0,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<1,1,0,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<1,1,0,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<1,1,0,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<1,1,0,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<1,1,0,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<1,1,0,3,2>(eflag, vflag); - } - } - else if (tangential == TANGENTIAL_MINDLIN){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<1,1,1,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<1,1,1,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<1,1,1,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<1,1,1,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<1,1,1,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<1,1,1,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<1,1,1,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<1,1,1,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<1,1,1,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<1,1,1,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<1,1,1,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<1,1,1,3,2>(eflag, vflag); - } - } - } - else if (damping == TSUJI){ - if (tangential == TANGENTIAL_NOHISTORY){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<1,2,0,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<1,2,0,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<1,2,0,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<1,2,0,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<1,2,0,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<1,2,0,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<1,2,0,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<1,2,0,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<1,2,0,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<1,2,0,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<1,2,0,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<1,2,0,3,2>(eflag, vflag); - } - } - else if (tangential == TANGENTIAL_MINDLIN){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<1,2,1,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<1,2,1,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<1,2,1,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<1,2,1,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<1,2,1,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<1,2,1,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<1,2,1,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<1,2,1,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<1,2,1,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<1,2,1,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<1,2,1,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<1,2,1,3,2>(eflag, vflag); - } - } - } - } - else if (normal == HERTZ_MATERIAL){ - if (damping == VELOCITY){ - if (tangential == TANGENTIAL_NOHISTORY){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<2,0,0,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<2,0,0,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<2,0,0,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<2,0,0,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<2,0,0,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<2,0,0,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<2,0,0,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<2,0,0,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<2,0,0,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<2,0,0,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<2,0,0,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<2,0,0,3,2>(eflag, vflag); - } - } - else if (tangential == TANGENTIAL_MINDLIN){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<2,0,1,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<2,0,1,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<2,0,1,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<2,0,1,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<2,0,1,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<2,0,1,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<2,0,1,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<2,0,1,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<2,0,1,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<2,0,1,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<2,0,1,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<2,0,1,3,2>(eflag, vflag); - } - } - } - else if (damping == VISCOELASTIC){ - if (tangential == TANGENTIAL_NOHISTORY){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<2,1,0,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<2,1,0,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<2,1,0,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<2,1,0,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<2,1,0,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<2,1,0,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<2,1,0,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<2,1,0,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<2,1,0,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<2,1,0,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<2,1,0,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<2,1,0,3,2>(eflag, vflag); - } - } - else if (tangential == TANGENTIAL_MINDLIN){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<2,1,1,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<2,1,1,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<2,1,1,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<2,1,1,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<2,1,1,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<2,1,1,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<2,1,1,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<2,1,1,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<2,1,1,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<2,1,1,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<2,1,1,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<2,1,1,3,2>(eflag, vflag); - } - } - } - else if (damping == TSUJI){ - if (tangential == TANGENTIAL_NOHISTORY){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<2,2,0,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<2,2,0,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<2,2,0,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<2,2,0,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<2,2,0,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<2,2,0,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<2,2,0,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<2,2,0,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<2,2,0,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<2,2,0,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<2,2,0,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<2,2,0,3,2>(eflag, vflag); - } - } - else if (tangential == TANGENTIAL_MINDLIN){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<2,2,1,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<2,2,1,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<2,2,1,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<2,2,1,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<2,2,1,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<2,2,1,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<2,2,1,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<2,2,1,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<2,2,1,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<2,2,1,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<2,2,1,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<2,2,1,3,2>(eflag, vflag); - } - } - } - } - else if (normal == DMT){ - if (damping == VELOCITY){ - if (tangential == TANGENTIAL_NOHISTORY){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<3,0,0,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<3,0,0,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<3,0,0,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<3,0,0,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<3,0,0,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<3,0,0,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<3,0,0,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<3,0,0,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<3,0,0,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<3,0,0,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<3,0,0,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<3,0,0,3,2>(eflag, vflag); - } - } - else if (tangential == TANGENTIAL_MINDLIN){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<3,0,1,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<3,0,1,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<3,0,1,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<3,0,1,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<3,0,1,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<3,0,1,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<3,0,1,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<3,0,1,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<3,0,1,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<3,0,1,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<3,0,1,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<3,0,1,3,2>(eflag, vflag); - } - } - } - else if (damping == VISCOELASTIC){ - if (tangential == TANGENTIAL_NOHISTORY){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<3,1,0,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<3,1,0,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<3,1,0,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<3,1,0,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<3,1,0,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<3,1,0,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<3,1,0,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<3,1,0,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<3,1,0,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<3,1,0,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<3,1,0,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<3,1,0,3,2>(eflag, vflag); - } - } - else if (tangential == TANGENTIAL_MINDLIN){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<3,1,1,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<3,1,1,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<3,1,1,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<3,1,1,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<3,1,1,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<3,1,1,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<3,1,1,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<3,1,1,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<3,1,1,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<3,1,1,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<3,1,1,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<3,1,1,3,2>(eflag, vflag); - } - } - } - else if (damping == TSUJI){ - if (tangential == TANGENTIAL_NOHISTORY){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<3,2,0,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<3,2,0,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<3,2,0,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<3,2,0,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<3,2,0,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<3,2,0,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<3,2,0,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<3,2,0,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<3,2,0,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<3,2,0,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<3,2,0,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<3,2,0,3,2>(eflag, vflag); - } - } - else if (tangential == TANGENTIAL_MINDLIN){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<3,2,1,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<3,2,1,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<3,2,1,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<3,2,1,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<3,2,1,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<3,2,1,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<3,2,1,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<3,2,1,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<3,2,1,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<3,2,1,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<3,2,1,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<3,2,1,3,2>(eflag, vflag); - } - } - } - } - else if (normal == JKR){ - if (damping == VELOCITY){ - if (tangential == TANGENTIAL_NOHISTORY){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<4,0,0,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<4,0,0,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<4,0,0,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<4,0,0,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<4,0,0,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<4,0,0,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<4,0,0,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<4,0,0,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<4,0,0,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<4,0,0,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<4,0,0,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<4,0,0,3,2>(eflag, vflag); - } - } - else if (tangential == TANGENTIAL_MINDLIN){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<4,0,1,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<4,0,1,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<4,0,1,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<4,0,1,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<4,0,1,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<4,0,1,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<4,0,1,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<4,0,1,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<4,0,1,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<4,0,1,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<4,0,1,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<4,0,1,3,2>(eflag, vflag); - } - } - } - else if (damping == VISCOELASTIC){ - if (tangential == TANGENTIAL_NOHISTORY){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<4,1,0,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<4,1,0,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<4,1,0,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<4,1,0,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<4,1,0,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<4,1,0,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<4,1,0,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<4,1,0,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<4,1,0,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<4,1,0,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<4,1,0,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<4,1,0,3,2>(eflag, vflag); - } - } - else if (tangential == TANGENTIAL_MINDLIN){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<4,1,1,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<4,1,1,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<4,1,1,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<4,1,1,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<4,1,1,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<4,1,1,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<4,1,1,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<4,1,1,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<4,1,1,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<4,1,1,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<4,1,1,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<4,1,1,3,2>(eflag, vflag); - } - } - } - else if (damping == TSUJI){ - if (tangential == TANGENTIAL_NOHISTORY){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<4,2,0,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<4,2,0,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<4,2,0,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<4,2,0,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<4,2,0,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<4,2,0,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<4,2,0,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<4,2,0,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<4,2,0,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<4,2,0,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<4,2,0,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<4,2,0,3,2>(eflag, vflag); - } - } - else if (tangential == TANGENTIAL_MINDLIN){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<4,2,1,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<4,2,1,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<4,2,1,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<4,2,1,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<4,2,1,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<4,2,1,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<4,2,1,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<4,2,1,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<4,2,1,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<4,2,1,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<4,2,1,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<4,2,1,3,2>(eflag, vflag); - } - } - } - } - -#else - compute_untemplated(Tp_normal, Tp_damping, Tp_tangential, - Tp_roll, Tp_twist, - eflag, vflag); -#endif -} - -#ifdef TEMPLATED_PAIR_GRANULAR -template < int Tp_normal, int Tp_damping, int Tp_tangential, - int Tp_twist, int Tp_roll > -void PairGranular::compute_templated(int eflag, int vflag) -#else -void PairGranular::compute_untemplated - (int Tp_normal, int Tp_damping, int Tp_tangential, - int Tp_twist, int Tp_roll, int eflag, int vflag) -#endif +void PairGranular::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,fx,fy,fz,nx,ny,nz; @@ -847,14 +141,14 @@ void PairGranular::compute_untemplated double Fne, Ft, Fdamp, Fntot, Fcrit, Fscrit, Frcrit; double fs, fs1, fs2, fs3; + double mi,mj,meff,damp,ccel,tor1,tor2,tor3; + double relrot1,relrot2,relrot3,vrl1,vrl2,vrl3,vrlmag,vrlmaginv; + //For JKR double R2, coh, F_pulloff, delta_pulloff, dist_pulloff, a, a2, E; double t0, t1, t2, t3, t4, t5, t6; double sqrt1, sqrt2, sqrt3, sqrt4; - double mi,mj,meff,damp,ccel,tor1,tor2,tor3; - double relrot1,relrot2,relrot3,vrl1,vrl2,vrl3,vrlmag,vrlmaginv; - //Rolling double k_roll, damp_roll; double roll1, roll2, roll3, torroll1, torroll2, torroll3; @@ -947,7 +241,7 @@ void PairGranular::compute_untemplated Reff = radi*radj/(radi+radj); touchflag = false; - if (Tp_normal == JKR){ + if (normal_model[itype][jtype] == JKR){ if (touch[jj]){ R2 = Reff*Reff; coh = normal_coeffs[itype][jtype][3]; @@ -1008,7 +302,7 @@ void PairGranular::compute_untemplated delta = radsum - r; dR = delta*Reff; - if (Tp_normal == JKR){ + if (normal_model[itype][jtype] == JKR){ touch[jj] = 1; R2=Reff*Reff; coh = normal_coeffs[itype][jtype][3]; @@ -1031,22 +325,21 @@ void PairGranular::compute_untemplated else{ knfac = E; //Hooke Fne = knfac*delta; - if (Tp_normal != HOOKE) - a = sqrt(dR); + a = sqrt(dR); + if (normal_model[itype][jtype] != HOOKE) Fne *= a; - if (Tp_normal == DMT) + if (normal_model[itype][jtype] == DMT) Fne -= 4*MY_PI*normal_coeffs[itype][jtype][3]*Reff; } //Consider restricting Hooke to only have 'velocity' as an option for damping? - if (Tp_damping == VELOCITY){ + if (damping_model[itype][jtype] == VELOCITY){ damp_normal = 1; } - else if (Tp_damping == VISCOELASTIC){ - if (Tp_normal == HOOKE) a = sqrt(dR); + else if (damping_model[itype][jtype] == VISCOELASTIC){ damp_normal = a*meff; } - else if (Tp_damping == TSUJI){ + else if (damping_model[itype][jtype] == TSUJI){ damp_normal = sqrt(meff*knfac); } @@ -1081,8 +374,7 @@ void PairGranular::compute_untemplated history = &allhistory[size_history*jj]; } - - if (Tp_normal == JKR){ + if (normal_model[itype][jtype] == JKR){ F_pulloff = 3*M_PI*coh*Reff; Fcrit = fabs(Fne + 2*F_pulloff); } @@ -1096,7 +388,7 @@ void PairGranular::compute_untemplated k_tangential = tangential_coeffs[itype][jtype][0]; damp_tangential = tangential_coeffs[itype][jtype][1]*damp_normal; - if (Tp_tangential > 0){ + if (tangential_history){ shrmag = sqrt(history[0]*history[0] + history[1]*history[1] + history[2]*history[2]); @@ -1153,7 +445,7 @@ void PairGranular::compute_untemplated // Rolling resistance //**************************************** - if (Tp_roll != ROLL_NONE){ + if (roll_model[itype][jtype] != ROLL_NONE){ relrot1 = omega[i][0] - omega[j][0]; relrot2 = omega[i][1] - omega[j][1]; relrot3 = omega[i][2] - omega[j][2]; @@ -1168,7 +460,7 @@ void PairGranular::compute_untemplated if (vrlmag != 0.0) vrlmaginv = 1.0/vrlmag; else vrlmaginv = 0.0; - if (Tp_roll > 1){ + if (roll_history){ int rhist0 = roll_history_index; int rhist1 = rhist0 + 1; int rhist2 = rhist1 + 1; @@ -1197,6 +489,7 @@ void PairGranular::compute_untemplated history[rhist2] += vrl3*dt; } + k_roll = roll_coeffs[itype][jtype][0]; damp_roll = roll_coeffs[itype][jtype][1]; fr1 = -k_roll*history[rhist0] - damp_roll*vrl1; @@ -1231,9 +524,9 @@ void PairGranular::compute_untemplated //**************************************** // Twisting torque, including history effects //**************************************** - if (Tp_twist != TWIST_NONE){ + if (twist_model[itype][jtype] != TWIST_NONE){ magtwist = relrot1*nx + relrot2*ny + relrot3*nz; //Omega_T (eq 29 of Marshall) - if (Tp_twist == TWIST_MARSHALL){ + if (twist_model[itype][jtype] == TWIST_MARSHALL){ k_twist = 0.5*k_tangential*a*a;; //eq 32 damp_twist = 0.5*damp_tangential*a*a; mu_twist = TWOTHIRDS*a; @@ -1243,7 +536,7 @@ void PairGranular::compute_untemplated damp_twist = twist_coeffs[itype][jtype][1]; mu_twist = twist_coeffs[itype][jtype][2]; } - if (Tp_twist > 1){ + if (twist_model[itype][jtype] > 1){ if (historyupdate){ history[twist_history_index] += magtwist*dt; } @@ -1278,7 +571,7 @@ void PairGranular::compute_untemplated torque[i][1] -= radi*tor2; torque[i][2] -= radi*tor3; - if (Tp_twist != TWIST_NONE){ + if (twist_model[itype][jtype] != TWIST_NONE){ tortwist1 = magtortwist * nx; tortwist2 = magtortwist * ny; tortwist3 = magtortwist * nz; @@ -1288,7 +581,7 @@ void PairGranular::compute_untemplated torque[i][2] += tortwist3; } - if (Tp_roll != ROLL_NONE){ + if (roll_model[itype][jtype] != ROLL_NONE){ torroll1 = Reff*(ny*fr3 - nz*fr2); //n cross fr torroll2 = Reff*(nz*fr1 - nx*fr3); torroll3 = Reff*(nx*fr2 - ny*fr1); @@ -1307,12 +600,12 @@ void PairGranular::compute_untemplated torque[j][1] -= radj*tor2; torque[j][2] -= radj*tor3; - if (Tp_twist != TWIST_NONE){ + if (twist_model[itype][jtype] != TWIST_NONE){ torque[j][0] -= tortwist1; torque[j][1] -= tortwist2; torque[j][2] -= tortwist3; } - if (Tp_roll != ROLL_NONE){ + if (roll_model[itype][jtype] != ROLL_NONE){ torque[j][0] -= torroll1; torque[j][1] -= torroll2; torque[j][2] -= torroll3; @@ -1341,12 +634,21 @@ void PairGranular::allocate() setflag[i][j] = 0; memory->create(cutsq,n+1,n+1,"pair:cutsq"); - memory->create(cut,n+1,n+1,"pair:cut"); + memory->create(cutoff_type,n+1,n+1,"pair:cutoff_type"); memory->create(normal_coeffs,n+1,n+1,4,"pair:normal_coeffs"); memory->create(tangential_coeffs,n+1,n+1,3,"pair:tangential_coeffs"); memory->create(roll_coeffs,n+1,n+1,3,"pair:roll_coeffs"); memory->create(twist_coeffs,n+1,n+1,3,"pair:twist_coeffs"); + memory->create(Emod,n+1,n+1,"pair:Emod"); + memory->create(poiss,n+1,n+1,"pair:poiss"); + + memory->create(normal_model,n+1,n+1,"pair:normal_model"); + memory->create(damping_model,n+1,n+1,"pair:damping_model"); + memory->create(tangential_model,n+1,n+1,"pair:tangential_model"); + memory->create(roll_model,n+1,n+1,"pair:roll_model"); + memory->create(twist_model,n+1,n+1,"pair:twist_model"); + onerad_dynamic = new double[n+1]; onerad_frozen = new double[n+1]; maxrad_dynamic = new double[n+1]; @@ -1365,9 +667,9 @@ void PairGranular::settings(int narg, char **arg) else{ cutoff_global = -1; //Will be set based on particle sizes, model choice } - tangential_history = 0; + + normal_history = tangential_history = 0; roll_history = twist_history = 0; - normal_set = tangential_set = damping_set = roll_set = twist_set = 0; } /* ---------------------------------------------------------------------- @@ -1376,10 +678,15 @@ void PairGranular::settings(int narg, char **arg) void PairGranular::coeff(int narg, char **arg) { - double normal_coeffs_local[4]; - double tangential_coeffs_local[4]; - double roll_coeffs_local[4]; - double twist_coeffs_local[4]; + int normal_model_one, damping_model_one; + int tangential_model_one, roll_model_one, twist_model_one; + + double normal_coeffs_one[4]; + double tangential_coeffs_one[4]; + double roll_coeffs_one[4]; + double twist_coeffs_one[4]; + + double cutoff_one = -1; if (narg < 2) error->all(FLERR,"Incorrect args for pair coefficients"); @@ -1390,209 +697,200 @@ void PairGranular::coeff(int narg, char **arg) force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); + //Defaults + normal_model_one = tangential_model_one = -1; + roll_model_one = twist_model_one = 0; + damping_model_one = VISCOELASTIC; + int iarg = 2; while (iarg < narg){ if (strcmp(arg[iarg], "hooke") == 0){ if (iarg + 2 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hooke option"); - if (!normal_set) normal = HOOKE; - else if (normal != HOOKE) error->all(FLERR, "Illegal pair_coeff command, choice of normal contact model must be the same for all types"); - normal_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1]); //kn - normal_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //damping - normal_set = 1; + normal_model_one = HOOKE; + normal_coeffs_one[0] = force->numeric(FLERR,arg[iarg+1]); //kn + normal_coeffs_one[1] = force->numeric(FLERR,arg[iarg+2]); //damping iarg += 3; } else if (strcmp(arg[iarg], "hertz") == 0){ int num_coeffs = 2; if (iarg + num_coeffs >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hertz option"); - if (!normal_set) normal = HERTZ; - else if (normal_set && normal != HERTZ) if (normal != HOOKE) error->all(FLERR, "Illegal pair_coeff command, choice of normal contact model must be the same for all types"); - normal_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1]); //kn - normal_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //damping - normal_set = 1; + normal_model_one = HERTZ; + normal_coeffs_one[0] = force->numeric(FLERR,arg[iarg+1]); //kn + normal_coeffs_one[1] = force->numeric(FLERR,arg[iarg+2]); //damping iarg += num_coeffs+1; } else if (strcmp(arg[iarg], "hertz/material") == 0){ int num_coeffs = 3; if (iarg + num_coeffs >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hertz option"); - if (!normal_set) normal = HERTZ_MATERIAL; - else if (normal != HERTZ) if (normal != HOOKE) error->all(FLERR, "Illegal pair_coeff command, choice of normal contact model must be the same for all types"); - normal_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1])*FOURTHIRDS; //E - normal_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //damping - normal_coeffs_local[2] = force->numeric(FLERR,arg[iarg+3]); //G - normal_set = 1; + normal_model_one = HERTZ; + normal_coeffs_one[0] = force->numeric(FLERR,arg[iarg+1])*FOURTHIRDS; //E + normal_coeffs_one[1] = force->numeric(FLERR,arg[iarg+2]); //damping + normal_coeffs_one[2] = force->numeric(FLERR,arg[iarg+3]); //Poisson's ratio iarg += num_coeffs+1; } else if (strcmp(arg[iarg], "dmt") == 0){ if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hertz option"); - if (!normal_set) normal = DMT; - else if (normal != DMT) error->all(FLERR, "Illegal pair_coeff command, choice of normal contact model must be the same for all types"); - normal_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1])*FOURTHIRDS; //E - normal_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //damping - normal_coeffs_local[2] = force->numeric(FLERR,arg[iarg+3]); //G - normal_coeffs_local[3] = force->numeric(FLERR,arg[iarg+3]); //cohesion - normal_set = 1; + normal_model_one = DMT; + normal_coeffs_one[0] = force->numeric(FLERR,arg[iarg+1])*FOURTHIRDS; //E + normal_coeffs_one[1] = force->numeric(FLERR,arg[iarg+2]); //damping + normal_coeffs_one[2] = force->numeric(FLERR,arg[iarg+3]); //Poisson's ratio + normal_coeffs_one[3] = force->numeric(FLERR,arg[iarg+3]); //cohesion iarg += 5; } else if (strcmp(arg[iarg], "jkr") == 0){ if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for JKR option"); beyond_contact = 1; - if (!normal_set) normal = JKR; - else if (normal != JKR) error->all(FLERR, "Illegal pair_coeff command, choice of normal contact model must be the same for all types"); - normal_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1]); //E - normal_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //damping - normal_coeffs_local[2] = force->numeric(FLERR,arg[iarg+3]); //G - normal_coeffs_local[3] = force->numeric(FLERR,arg[iarg+4]); //cohesion - normal_set = 1; + normal_model_one = JKR; + normal_coeffs_one[0] = force->numeric(FLERR,arg[iarg+1]); //E + normal_coeffs_one[1] = force->numeric(FLERR,arg[iarg+2]); //damping + normal_coeffs_one[2] = force->numeric(FLERR,arg[iarg+3]); //Poisson's ratio + normal_coeffs_one[3] = force->numeric(FLERR,arg[iarg+4]); //cohesion iarg += 5; } else if (strcmp(arg[iarg], "damp") == 0){ if (iarg+1 >= narg) error->all(FLERR, "Illegal pair_coeff command, not enough parameters provided for damping model"); if (strcmp(arg[iarg+1], "velocity") == 0){ - if (!damping_set) damping = VELOCITY; - else if (damping != VELOCITY) error->all(FLERR, "Illegal pair_coeff command, choice of damping contact model must be the same for all types"); + damping_model_one = VELOCITY; + iarg += 1; } else if (strcmp(arg[iarg+1], "viscoelastic") == 0){ - if (!damping_set) damping = VISCOELASTIC; - else if (damping != VISCOELASTIC) error->all(FLERR, "Illegal pair_coeff command, choice of damping contact model must be the same for all types"); + damping_model_one = VISCOELASTIC; + iarg += 1; } - else if (strcmp(arg[iarg+1], "tsuji") == 0){ - if (!damping_set) damping = TSUJI; - if (damping != TSUJI) error->all(FLERR, "Illegal pair_coeff command, choice of damping contact model must be the same for all types"); + else if (strcmp(arg[iarg], "tsuji") == 0){ + damping_model_one = TSUJI; + iarg += 1; } - damping_set = 1; - iarg += 2; } else if (strcmp(arg[iarg], "tangential") == 0){ if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for tangential model"); - if (strcmp(arg[iarg+1], "nohistory") == 0){ - if (!tangential_set) tangential = TANGENTIAL_NOHISTORY; - else if (tangential != TANGENTIAL_NOHISTORY) error->all(FLERR, "Illegal pair_coeff command, choice of tangential contact model must be the same for all types"); + if (strcmp(arg[iarg+1], "linear_nohistory") == 0){ + tangential_model_one = TANGENTIAL_NOHISTORY; } - else if (strcmp(arg[iarg+1], "mindlin") == 0){ - if (!tangential_set) tangential = TANGENTIAL_MINDLIN; - else if (tangential != TANGENTIAL_MINDLIN) error->all(FLERR, "Illegal pair_coeff command, choice of tangential contact model must be the same for all types");; + else if (strcmp(arg[iarg+1], "linear_history") == 0){ + tangential_model_one = TANGENTIAL_HISTORY; tangential_history = 1; } else{ error->all(FLERR, "Illegal pair_coeff command, tangential model not recognized"); } - tangential_set = 1; - tangential_coeffs_local[0] = force->numeric(FLERR,arg[iarg+2]); //kt - tangential_coeffs_local[1] = force->numeric(FLERR,arg[iarg+3]); //gammat - tangential_coeffs_local[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. + tangential_coeffs_one[0] = force->numeric(FLERR,arg[iarg+2]); //kt + tangential_coeffs_one[1] = force->numeric(FLERR,arg[iarg+3]); //gammat + tangential_coeffs_one[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. iarg += 5; } else if (strcmp(arg[iarg], "rolling") == 0){ if (iarg + 1 >= narg) error->all(FLERR, "Illegal pair_coeff command, not enough parameters"); if (strcmp(arg[iarg+1], "none") == 0){ - if (!roll_set) roll = ROLL_NONE; - else if (roll != ROLL_NONE) error->all(FLERR, "Illegal pair_coeff command, choice of rolling friction model must be the same for all types"); + roll_model_one = ROLL_NONE; iarg += 2; } else{ if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for rolling model"); if (strcmp(arg[iarg+1], "nohistory") == 0){ - if (!roll_set) roll = ROLL_NOHISTORY; - else if (roll != ROLL_NOHISTORY) error->all(FLERR, "Illegal pair_coeff command, choice of rolling friction model must be the same for all types"); + roll_model_one = ROLL_NOHISTORY; } else if (strcmp(arg[iarg+1], "sds") == 0){ - if (!roll_set) roll = ROLL_SDS; - else if (roll != ROLL_SDS) error->all(FLERR, "Illegal pair_coeff command, choice of rolling friction model must be the same for all types"); + roll_model_one = ROLL_SDS; roll_history = 1; } else{ error->all(FLERR, "Illegal pair_coeff command, rolling friction model not recognized"); } - roll_set =1 ; - roll_coeffs_local[0] = force->numeric(FLERR,arg[iarg+2]); //kR - roll_coeffs_local[1] = force->numeric(FLERR,arg[iarg+3]); //gammaR - roll_coeffs_local[2] = force->numeric(FLERR,arg[iarg+4]); //rolling friction coeff. + roll_coeffs_one[0] = force->numeric(FLERR,arg[iarg+2]); //kR + roll_coeffs_one[1] = force->numeric(FLERR,arg[iarg+3]); //gammaR + roll_coeffs_one[2] = force->numeric(FLERR,arg[iarg+4]); //rolling friction coeff. iarg += 5; } } else if (strcmp(arg[iarg], "twisting") == 0){ if (iarg + 1 >= narg) error->all(FLERR, "Illegal pair_coeff command, not enough parameters"); if (strcmp(arg[iarg+1], "none") == 0){ - if (!twist_set) twist = TWIST_NONE; - else if (twist != TWIST_NONE) error->all(FLERR, "Illegal pair_coeff command, choice of twisting friction model must be the same for all types"); + twist_model_one = TWIST_NONE; iarg += 2; } else if (strcmp(arg[iarg+1], "marshall") == 0){ - if (!twist_set) twist = TWIST_MARSHALL; - else if (twist != TWIST_MARSHALL) error->all(FLERR, "Illegal pair_coeff command, choice of twisting friction model must be the same for all types"); + twist_model_one = TWIST_MARSHALL; twist_history = 1; - twist_set = 1; iarg += 2; } else{ if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for twist model"); - else if (strcmp(arg[iarg+1], "nohistory") == 0){ - if (!twist_set) twist = TWIST_NOHISTORY; - if (twist != TWIST_NOHISTORY) error->all(FLERR, "Illegal pair_coeff command, choice of twisting friction model must be the same for all types"); + if (strcmp(arg[iarg+1], "nohistory") == 0){ + twist_model_one = TWIST_NOHISTORY; } else if (strcmp(arg[iarg+1], "sds") == 0){ - if (!twist_set) twist = TWIST_SDS; - else if (twist != TWIST_SDS) error->all(FLERR, "Illegal pair_coeff command, choice of twisting friction model must be the same for all types"); + twist_model_one = TWIST_SDS; twist_history = 1; } else{ error->all(FLERR, "Illegal pair_coeff command, twisting friction model not recognized"); } - twist_set = 1; - twist_coeffs_local[0] = force->numeric(FLERR,arg[iarg+2]); //kt - twist_coeffs_local[1] = force->numeric(FLERR,arg[iarg+3]); //gammat - twist_coeffs_local[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. + twist_coeffs_one[0] = force->numeric(FLERR,arg[iarg+2]); //kt + twist_coeffs_one[1] = force->numeric(FLERR,arg[iarg+3]); //gammat + twist_coeffs_one[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. iarg += 5; } } + else if (strcmp(arg[iarg], "cutoff") == 0){ + if (iarg + 1 >= narg) error->all(FLERR, "Illegal pair_coeff command, not enough parameters"); + cutoff_one = force->numeric(FLERR,arg[iarg+1]); + } else error->all(FLERR, "Illegal pair coeff command"); } //It is an error not to specify normal or tangential model - if (!normal_set) error->all(FLERR, "Illegal pair coeff command, must specify normal contact model"); - if (!tangential_set) error->all(FLERR, "Illegal pair coeff command, must specify tangential contact model"); - - //If unspecified, set damping to VISCOELASTIC, twist/roll to NONE (cannot be changed by subsequent pair_coeff commands) - if (!damping_set) damping = VISCOELASTIC; - if (!roll_set) roll = ROLL_NONE; - if (!twist_set) twist = TWIST_NONE; - damping_set = roll_set = twist_set = 1; + if ((normal_model_one < 0) || (tangential_model_one < 0)) error->all(FLERR, "Illegal pair coeff command, must specify normal contact model"); int count = 0; double damp; - if (damping == TSUJI){ + if (damping_model_one == TSUJI){ double cor; - cor = normal_coeffs_local[1]; + cor = normal_coeffs_one[1]; damp = 1.2728-4.2783*cor+11.087*pow(cor,2)-22.348*pow(cor,3)+ 27.467*pow(cor,4)-18.022*pow(cor,5)+ 4.8218*pow(cor,6); } - else damp = normal_coeffs_local[1]; + else damp = normal_coeffs_one[1]; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { - normal_coeffs[i][j][0] = normal_coeffs[j][i][0] = normal_coeffs_local[0]; + normal_model[i][j] = normal_model[j][i] = normal_model_one; normal_coeffs[i][j][1] = normal_coeffs[j][i][1] = damp; - if (normal != HERTZ && normal != HOOKE) normal_coeffs[i][j][2] = normal_coeffs_local[2]; - if ((normal == JKR) || (normal == DMT)) - normal_coeffs[i][j][3] = normal_coeffs[j][i][3] = normal_coeffs_local[3]; + if (normal_model_one != HERTZ && normal_model_one != HOOKE){ + Emod[i][j] = Emod[j][i] = normal_coeffs_one[0]; + poiss[i][j] = poiss[j][i] = normal_coeffs_one[2]; + normal_coeffs[i][j][0] = normal_coeffs[j][i][0] = mix_stiffnessE(Emod[i][j], Emod[i][j], poiss[i][j], poiss[i][j]); + } + else{ + normal_coeffs[i][j][0] = normal_coeffs[j][i][0] = normal_coeffs_one[0]; + } + if ((normal_model_one == JKR) || (normal_model_one == DMT)) + normal_coeffs[i][j][3] = normal_coeffs[j][i][3] = normal_coeffs_one[3]; + damping_model[i][j] = damping_model[j][i] = damping_model_one; + + tangential_model[i][j] = tangential_model[j][i] = tangential_model_one; for (int k = 0; k < 3; k++) - tangential_coeffs[i][j][k] = tangential_coeffs[j][i][k] = tangential_coeffs_local[k]; + tangential_coeffs[i][j][k] = tangential_coeffs[j][i][k] = tangential_coeffs_one[k]; - if (roll != ROLL_NONE) + roll_model[i][j] = roll_model[j][i] = roll_model_one; + if (roll_model_one != ROLL_NONE) for (int k = 0; k < 3; k++) - roll_coeffs[i][j][k] = roll_coeffs[j][i][k] = roll_coeffs_local[k]; + roll_coeffs[i][j][k] = roll_coeffs[j][i][k] = roll_coeffs_one[k]; - if (twist != TWIST_NONE && twist != TWIST_MARSHALL) + twist_model[i][j] = twist_model[j][i] = twist_model_one; + if (twist_model_one != TWIST_NONE && twist_model_one != TWIST_MARSHALL) for (int k = 0; k < 3; k++) - twist_coeffs[i][j][k] = twist_coeffs[j][i][k] = twist_coeffs_local[k]; + twist_coeffs[i][j][k] = twist_coeffs[j][i][k] = twist_coeffs_one[k]; + + + cutoff_type[i][j] = cutoff_type[j][i] = cutoff_one; setflag[i][j] = 1; count++; } } - if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); } @@ -1615,7 +913,9 @@ void PairGranular::init_style() use_history = tangential_history || roll_history || twist_history; //For JKR, will need fix/neigh/history to keep track of touch arrays - if (normal == JKR) use_history = 1; + for (int i = 1; i <= atom->ntypes; i++) + for (int j = 1; j <= atom->ntypes; j++) + if (normal_model[i][j] == JKR) use_history = 1; size_history = 3*tangential_history + 3*roll_history + twist_history; @@ -1693,13 +993,11 @@ void PairGranular::init_style() if (ipour >= 0) { itype = i; double radmax = *((double *) modify->fix[ipour]->extract("radius",itype)); - if (normal == JKR) radmax = radmax - 0.5*pulloff_distance(radmax, itype); onerad_dynamic[i] = radmax; } if (idep >= 0) { itype = i; double radmax = *((double *) modify->fix[idep]->extract("radius",itype)); - if (normal == JKR) radmax = radmax - 0.5*pulloff_distance(radmax, itype); onerad_dynamic[i] = radmax; } } @@ -1711,9 +1009,6 @@ void PairGranular::init_style() for (i = 0; i < nlocal; i++){ double radius_cut = radius[i]; - if (normal == JKR){ - radius_cut = radius[i] - 0.5*pulloff_distance(radius[i], type[i]); - } if (mask[i] & freeze_group_bit){ onerad_frozen[type[i]] = MAX(onerad_frozen[type[i]],radius_cut); } @@ -1743,32 +1038,38 @@ void PairGranular::init_style() double PairGranular::init_one(int i, int j) { double cutoff; - if (setflag[i][j] == 0) { - if (normal != HOOKE && normal != HERTZ){ - normal_coeffs[i][j][0] = normal_coeffs[j][i][0] = mix_stiffnessE(normal_coeffs[i][i][0], normal_coeffs[j][j][0], - normal_coeffs[i][i][2], normal_coeffs[j][j][2]); - normal_coeffs[i][j][2] = normal_coeffs[j][i][2] = mix_stiffnessG(normal_coeffs[i][i][0], normal_coeffs[j][j][0], - normal_coeffs[i][i][2], normal_coeffs[j][j][2]); + if (setflag[i][j] == 0){ + if ((normal_model[i][i] != normal_model[j][j]) || + (damping_model[i][i] != damping_model[j][j]) || + (tangential_model[i][i] != tangential_model[j][j]) || + (roll_model[i][i] != roll_model[j][j]) || + (twist_model[i][i] != twist_model[j][j])){ + + char str[512]; + sprintf(str,"Granular pair style functional forms are different, cannot mix coefficients for types %d and %d. \nThis combination must be set explicitly via pair_coeff command.",i,j); + error->one(FLERR,str); } - else{ + + if (normal_model[i][j] == HERTZ || normal_model[i][j] == HOOKE) normal_coeffs[i][j][0] = normal_coeffs[j][i][0] = mix_geom(normal_coeffs[i][i][0], normal_coeffs[j][j][0]); - } + else + normal_coeffs[i][j][0] = normal_coeffs[j][i][0] = mix_stiffnessE(Emod[i][i], Emod[j][j], poiss[i][i], poiss[j][j]); normal_coeffs[i][j][1] = normal_coeffs[j][i][1] = mix_geom(normal_coeffs[i][i][1], normal_coeffs[j][j][1]); - if ((normal == JKR) || (normal == DMT)) + if ((normal_model[i][j] == JKR) || (normal_model[i][j] == DMT)) normal_coeffs[i][j][3] = normal_coeffs[j][i][3] = mix_geom(normal_coeffs[i][i][3], normal_coeffs[j][j][3]); for (int k = 0; k < 3; k++) tangential_coeffs[i][j][k] = tangential_coeffs[j][i][k] = mix_geom(tangential_coeffs[i][i][k], tangential_coeffs[j][j][k]); - if (roll != ROLL_NONE){ + if (roll_model[i][j] != ROLL_NONE){ for (int k = 0; k < 3; k++) roll_coeffs[i][j][k] = roll_coeffs[j][i][k] = mix_geom(roll_coeffs[i][i][k], roll_coeffs[j][j][k]); } - if (twist != TWIST_NONE && twist != TWIST_MARSHALL){ + if (twist_model[i][j] != TWIST_NONE && twist_model[i][j] != TWIST_MARSHALL){ for (int k = 0; k < 3; k++) twist_coeffs[i][j][k] = twist_coeffs[j][i][k] = mix_geom(twist_coeffs[i][i][k], twist_coeffs[j][j][k]); } @@ -1780,22 +1081,40 @@ double PairGranular::init_one(int i, int j) // To avoid this issue, for cases involving cut[i][j] = 0.0 (possible only // if there is no current information about radius/cutoff of type i and j). // we assign cutoff = max(cut[i][j]) for i,j such that cut[i][j] > 0.0. - + double pulloff; if (cutoff_global < 0){ - if (((maxrad_dynamic[i] > 0.0) && (maxrad_dynamic[j] > 0.0)) || - ((maxrad_dynamic[i] > 0.0) && (maxrad_frozen[j] > 0.0)) || - ((maxrad_frozen[i] > 0.0) && (maxrad_dynamic[j] > 0.0))) { // radius info about both i and j exist - cutoff = maxrad_dynamic[i]+maxrad_dynamic[j]; - cutoff = MAX(cutoff,maxrad_frozen[i]+maxrad_dynamic[j]); - cutoff = MAX(cutoff,maxrad_dynamic[i]+maxrad_frozen[j]); - } - else { // radius info about either i or j does not exist (i.e. not present and not about to get poured; set to largest value to not interfere with neighbor list) - double cutmax = 0.0; - for (int k = 1; k <= atom->ntypes; k++) { - cutmax = MAX(cutmax,2.0*maxrad_dynamic[k]); - cutmax = MAX(cutmax,2.0*maxrad_frozen[k]); + if (cutoff_type[i][j] < 0){ + if (((maxrad_dynamic[i] > 0.0) && (maxrad_dynamic[j] > 0.0)) || + ((maxrad_dynamic[i] > 0.0) && (maxrad_frozen[j] > 0.0)) || + ((maxrad_frozen[i] > 0.0) && (maxrad_dynamic[j] > 0.0))) { // radius info about both i and j exist + cutoff = maxrad_dynamic[i]+maxrad_dynamic[j]; + if (normal_model[i][j] == JKR){ + pulloff = pulloff_distance(maxrad_dynamic[i], maxrad_dynamic[j], i, j); + cutoff += pulloff; + } + else{ + pulloff = 0; + } + + if (normal_model[i][j] == JKR) + pulloff = pulloff_distance(maxrad_frozen[i], maxrad_dynamic[j], i, j); + cutoff = MAX(cutoff, maxrad_frozen[i]+maxrad_dynamic[j]+pulloff); + + if (normal_model[i][j] == JKR) + pulloff = pulloff_distance(maxrad_dynamic[i], maxrad_frozen[j], i, j); + cutoff = MAX(cutoff,maxrad_dynamic[i]+maxrad_frozen[j]+pulloff); } - cutoff = cutmax; + else { // radius info about either i or j does not exist (i.e. not present and not about to get poured; set to largest value to not interfere with neighbor list) + double cutmax = 0.0; + for (int k = 1; k <= atom->ntypes; k++) { + cutmax = MAX(cutmax,2.0*maxrad_dynamic[k]); + cutmax = MAX(cutmax,2.0*maxrad_frozen[k]); + } + cutoff = cutmax; + } + } + else{ + cutoff = cutoff_type[i][j]; } } else{ @@ -1804,7 +1123,6 @@ double PairGranular::init_one(int i, int j) return cutoff; } - /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ @@ -1812,15 +1130,15 @@ double PairGranular::init_one(int i, int j) void PairGranular::write_restart(FILE *fp) { int i,j; - fwrite(&normal,sizeof(int),1,fp); - fwrite(&damping,sizeof(int),1,fp); - fwrite(&tangential,sizeof(int),1,fp); - fwrite(&roll,sizeof(int),1,fp); - fwrite(&twist,sizeof(int),1,fp); for (i = 1; i <= atom->ntypes; i++) { for (j = i; j <= atom->ntypes; j++) { fwrite(&setflag[i][j],sizeof(int),1,fp); if (setflag[i][j]) { + fwrite(&normal_model[i][j],sizeof(int),1,fp); + fwrite(&damping_model[i][j],sizeof(int),1,fp); + fwrite(&tangential_model[i][j],sizeof(int),1,fp); + fwrite(&roll_model[i][j],sizeof(int),1,fp); + fwrite(&twist_model[i][j],sizeof(int),1,fp); fwrite(&normal_coeffs[i][j],sizeof(double),4,fp); fwrite(&tangential_coeffs[i][j],sizeof(double),3,fp); fwrite(&roll_coeffs[i][j],sizeof(double),3,fp); @@ -1840,30 +1158,28 @@ void PairGranular::read_restart(FILE *fp) allocate(); int i,j; int me = comm->me; - if (me == 0){ - fread(&normal,sizeof(int),1,fp); - fread(&damping,sizeof(int),1,fp); - fread(&tangential,sizeof(int),1,fp); - fread(&roll,sizeof(int),1,fp); - fread(&twist,sizeof(int),1,fp); - } - MPI_Bcast(&normal,1,MPI_INT,0,world); - MPI_Bcast(&damping,1,MPI_INT,0,world); - MPI_Bcast(&tangential,1,MPI_INT,0,world); - MPI_Bcast(&roll,1,MPI_INT,0,world); - MPI_Bcast(&twist,1,MPI_INT,0,world); for (i = 1; i <= atom->ntypes; i++) { for (j = i; j <= atom->ntypes; j++) { if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp); MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world); if (setflag[i][j]) { if (me == 0) { + fread(&normal_model[i][j],sizeof(int),1,fp); + fread(&damping_model[i][j],sizeof(int),1,fp); + fread(&tangential_model[i][j],sizeof(int),1,fp); + fread(&roll_model[i][j],sizeof(int),1,fp); + fread(&twist_model[i][j],sizeof(int),1,fp); fread(&normal_coeffs[i][j],sizeof(double),4,fp); fread(&tangential_coeffs[i][j],sizeof(double),3,fp); fread(&roll_coeffs[i][j],sizeof(double),3,fp); fread(&twist_coeffs[i][j],sizeof(double),3,fp); fread(&cut[i][j],sizeof(double),1,fp); } + MPI_Bcast(&normal_model[i][j],1,MPI_INT,0,world); + MPI_Bcast(&damping_model[i][j],1,MPI_INT,0,world); + MPI_Bcast(&tangential_model[i][j],1,MPI_INT,0,world); + MPI_Bcast(&roll_model[i][j],1,MPI_INT,0,world); + MPI_Bcast(&twist_model[i][j],1,MPI_INT,0,world); MPI_Bcast(&normal_coeffs[i][j],4,MPI_DOUBLE,0,world); MPI_Bcast(&tangential_coeffs[i][j],3,MPI_DOUBLE,0,world); MPI_Bcast(&roll_coeffs[i][j],3,MPI_DOUBLE,0,world); @@ -1930,7 +1246,7 @@ double PairGranular::single(int i, int j, int itype, int jtype, Reff = radi*radj/(radi+radj); bool touchflag; - if (normal == JKR){ + if (normal_model[itype][jtype] == JKR){ R2 = Reff*Reff; coh = normal_coeffs[itype][jtype][3]; a = cbrt(9.0*M_PI*coh*R2/(4*E)); @@ -2022,7 +1338,7 @@ double PairGranular::single(int i, int j, int itype, int jtype, delta = radsum - r; dR = delta*Reff; - if (normal == JKR){ + if (normal_model[itype][jtype] == JKR){ dR2 = dR*dR; t0 = coh*coh*R2*R2*E; t1 = PI27SQ*t0; @@ -2042,22 +1358,21 @@ double PairGranular::single(int i, int j, int itype, int jtype, else{ knfac = E; Fne = knfac*delta; - if (normal != HOOKE) - a = sqrt(dR); + a = sqrt(dR); + if (normal_model[itype][jtype] != HOOKE) Fne *= a; - if (normal == DMT) + if (normal_model[itype][jtype] == DMT) Fne -= 4*MY_PI*normal_coeffs[itype][jtype][3]*Reff; } //Consider restricting Hooke to only have 'velocity' as an option for damping? - if (damping == VELOCITY){ + if (damping_model[itype][jtype] == VELOCITY){ damp_normal = normal_coeffs[itype][jtype][1]; } - else if (damping == VISCOELASTIC){ - if (normal == HOOKE) a = sqrt(dR); + else if (damping_model[itype][jtype] == VISCOELASTIC){ damp_normal = normal_coeffs[itype][jtype][1]*a*meff; } - else if (damping == TSUJI){ + else if (damping_model[itype][jtype] == TSUJI){ damp_normal = normal_coeffs[itype][jtype][1]*sqrt(meff*knfac); } @@ -2099,17 +1414,19 @@ double PairGranular::single(int i, int j, int itype, int jtype, vrel = vtr1*vtr1 + vtr2*vtr2 + vtr3*vtr3; vrel = sqrt(vrel); - Fcrit = fabs(Fne); - if (normal == JKR){ + if (normal_model[itype][jtype] == JKR){ F_pulloff = 3*M_PI*coh*Reff; Fcrit = fabs(Fne + 2*F_pulloff); } + else{ + Fcrit = fabs(Fne); + } //------------------------------ //Tangential forces //------------------------------ k_tangential = tangential_coeffs[itype][jtype][0]; - if (normal != HOOKE){ + if (normal_model[itype][jtype] != HOOKE){ k_tangential *= a; } damp_tangential = tangential_coeffs[itype][jtype][1]*damp_normal; @@ -2150,7 +1467,7 @@ double PairGranular::single(int i, int j, int itype, int jtype, // Rolling resistance //**************************************** - if (roll != ROLL_NONE){ + if (roll_model[itype][jtype] != ROLL_NONE){ relrot1 = omega[i][0] - omega[j][0]; relrot2 = omega[i][1] - omega[j][1]; relrot3 = omega[i][2] - omega[j][2]; @@ -2211,9 +1528,9 @@ double PairGranular::single(int i, int j, int itype, int jtype, //**************************************** // Twisting torque, including history effects //**************************************** - if (twist != TWIST_NONE){ + if (twist_model[itype][jtype] != TWIST_NONE){ magtwist = relrot1*nx + relrot2*ny + relrot3*nz; //Omega_T (eq 29 of Marshall) - if (twist == TWIST_MARSHALL){ + if (twist_model[itype][jtype] == TWIST_MARSHALL){ k_twist = 0.5*k_tangential*a*a;; //eq 32 damp_twist = 0.5*damp_tangential*a*a; mu_twist = TWOTHIRDS*a; @@ -2293,22 +1610,18 @@ double PairGranular::memory_usage() mixing of Young's modulus (E) ------------------------------------------------------------------------- */ -double PairGranular::mix_stiffnessE(double Eii, double Ejj, double Gii, double Gjj) +double PairGranular::mix_stiffnessE(double Eii, double Ejj, double poisii, double poisjj) { - double poisii = Eii/(2.0*Gii) - 1.0; - double poisjj = Ejj/(2.0*Gjj) - 1.0; - return 1/((1-poisii*poisjj)/Eii+(1-poisjj*poisjj)/Ejj); + return 1/((1-poisii*poisii)/Eii+(1-poisjj*poisjj)/Ejj); } /* ---------------------------------------------------------------------- mixing of shear modulus (G) - ------------------------------------------------------------------------- */ +------------------------------------------------------------------------ */ -double PairGranular::mix_stiffnessG(double Eii, double Ejj, double Gii, double Gjj) +double PairGranular::mix_stiffnessG(double Gii, double Gjj, double poisii, double poisjj) { - double poisii = Eii/(2.0*Gii) - 1.0; - double poisjj = Ejj/(2.0*Gjj) - 1.0; - return 1/((2.0 -poisjj)/Gii+(2.0-poisjj)/Gjj); + return 1/((2.0 -poisii)/Gii+(2.0-poisjj)/Gjj); } /* ---------------------------------------------------------------------- @@ -2325,13 +1638,14 @@ double PairGranular::mix_geom(double valii, double valjj) Compute pull-off distance (beyond contact) for a given radius and atom type ------------------------------------------------------------------------- */ -double PairGranular::pulloff_distance(double radius, int itype) +double PairGranular::pulloff_distance(double radi, double radj, int itype, int jtype) { - double E, coh, a, delta_pulloff; + double E, coh, a, delta_pulloff, Reff; + Reff = radi*radj/(radi+radj); + if (Reff <= 0) return 0; coh = normal_coeffs[itype][itype][3]; - E = mix_stiffnessE(normal_coeffs[itype][itype][0], normal_coeffs[itype][itype][0], - normal_coeffs[itype][itype][2], normal_coeffs[itype][itype][2]); - a = cbrt(9*M_PI*coh*radius*radius/(4*E)); - return a*a/radius - 2*sqrt(M_PI*coh*a/E); + E = normal_coeffs[itype][jtype][0]; + a = cbrt(9*M_PI*coh*Reff/(4*E)); + return a*a/Reff - 2*sqrt(M_PI*coh*a/E); } diff --git a/src/GRANULAR/pair_granular.h b/src/GRANULAR/pair_granular.h index f39f31e4cb..625ff17c72 100644 --- a/src/GRANULAR/pair_granular.h +++ b/src/GRANULAR/pair_granular.h @@ -21,40 +21,28 @@ PairStyle(granular,PairGranular) #define LMP_PAIR_GRANULAR_H #include "pair.h" +#include "pair_granular.h" namespace LAMMPS_NS { -class PairGranular : public Pair { +class PairGranular : public Pair{ public: PairGranular(class LAMMPS *); - virtual ~PairGranular(); - + ~PairGranular(); void compute(int, int); - // comment next line to turn off templating -#define TEMPLATED_PAIR_GRANULAR -#ifdef TEMPLATED_PAIR_GRANULAR - template < int Tp_normal, int Tp_damping, int Tp_tangential, - int Tp_roll, int Tp_twist> - void compute_templated(int, int); -#else - void compute_untemplated(int, int, int, int, int, - int, int); -#endif - - virtual void settings(int, char **); - virtual void coeff(int, char **); + void settings(int, char **); + void coeff(int, char **); void init_style(); double init_one(int, int); void write_restart(FILE *); void read_restart(FILE *); void reset_dt(); - virtual double single(int, int, int, int, double, double, double, double &); + double single(int, int, int, int, double, double, double, double &); int pack_forward_comm(int, int *, double *, int, int *); void unpack_forward_comm(int, int, double *); double memory_usage(); protected: - double cut_global; double dt; int freeze_group_bit; int use_history; @@ -72,22 +60,26 @@ public: double *mass_rigid; // rigid mass for owned+ghost atoms int nmax; // allocated size of mass_rigid - virtual void allocate(); + void allocate(); private: int size_history; - //Models - int normal, damping, tangential, roll, twist; + //Models choices + int **normal_model, **damping_model; + double **tangential_model, **roll_model, **twist_model; //History flags - int tangential_history, roll_history, twist_history; + int normal_history, tangential_history, roll_history, twist_history; //Indices of history entries - int tangential_history_index, roll_history_index, twist_history_index; + int normal_history_index; + int tangential_history_index; + int roll_history_index; + int twist_history_index; - //Flags for whether model choices have been set - int normal_set, tangential_set, damping_set, roll_set, twist_set; + //Per-type material coefficients + double **Emod, **poiss, **Gmod; //Per-type coefficients, set in pair coeff command double ***normal_coeffs; @@ -95,13 +87,14 @@ private: double ***roll_coeffs; double ***twist_coeffs; - //Optional user-specified global cutoff + //Optional user-specified global cutoff, per-type user-specified cutoffs + double **cutoff_type; double cutoff_global; - double mix_stiffnessE(double Eii, double Ejj, double Gii, double Gjj); - double mix_stiffnessG(double Eii, double Ejj, double Gii, double Gjj); - double mix_geom(double valii, double valjj); - double pulloff_distance(double radius, int itype); + double mix_stiffnessE(double, double, double, double); + double mix_stiffnessG(double, double, double, double); + double mix_geom(double, double); + double pulloff_distance(double, double, int, int); }; } diff --git a/src/pair_granular.cpp b/src/pair_granular.cpp new file mode 100644 index 0000000000..82a470f83b --- /dev/null +++ b/src/pair_granular.cpp @@ -0,0 +1,2337 @@ +/* ---------------------------------------------------------------------- +http://lammps.sandia.gov, Sandia National Laboratories +Steve Plimpton, sjplimp@sandia.gov + +Copyright (2003) Sandia Corporation. Under the terms of Contract +DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains +certain rights in this software. This software is distributed under +the GNU General Public License. + +See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- +Contributing authors: Leo Silbert (SNL), Gary Grest (SNL), + Jeremy Lechman (SNL), Dan Bolintineanu (SNL), Ishan Srivastava (SNL) +----------------------------------------------------------------------- */ + +#include +#include +#include +#include +#include "pair_granular.h" +#include "atom.h" +#include "atom_vec.h" +#include "domain.h" +#include "force.h" +#include "update.h" +#include "modify.h" +#include "fix.h" +#include "fix_neigh_history.h" +#include "comm.h" +#include "neighbor.h" +#include "neigh_list.h" +#include "neigh_request.h" +#include "memory.h" +#include "error.h" +#include "math_const.h" + +using namespace LAMMPS_NS; +using namespace MathConst; + +#define PI27SQ 266.47931882941264802866 // 27*PI**2 +#define THREEROOT3 5.19615242270663202362 // 3*sqrt(3) +#define SIXROOT6 14.69693845669906728801 // 6*sqrt(6) +#define INVROOT6 0.40824829046386307274 // 1/sqrt(6) +#define FOURTHIRDS 1.333333333333333 // 4/3 +#define TWOPI 6.28318530717959 // 2*PI + +#define EPSILON 1e-10 + +enum {HOOKE, HERTZ, HERTZ_MATERIAL, DMT, JKR}; +enum {VELOCITY, VISCOELASTIC, TSUJI}; +enum {TANGENTIAL_NOHISTORY, TANGENTIAL_MINDLIN}; +enum {TWIST_NONE, TWIST_NOHISTORY, TWIST_SDS, TWIST_MARSHALL}; +enum {ROLL_NONE, ROLL_NOHISTORY, ROLL_SDS}; + +/* ---------------------------------------------------------------------- */ + +PairGranular::PairGranular(LAMMPS *lmp) : Pair(lmp) +{ + single_enable = 1; + no_virial_fdotr_compute = 1; + fix_history = NULL; + + single_extra = 9; + svector = new double[single_extra]; + + neighprev = 0; + + nmax = 0; + mass_rigid = NULL; + + onerad_dynamic = NULL; + onerad_frozen = NULL; + maxrad_dynamic = NULL; + maxrad_frozen = NULL; + + dt = update->dt; + + // set comm size needed by this Pair if used with fix rigid + + comm_forward = 1; + + use_history = 0; + beyond_contact = 0; + nondefault_history_transfer = 0; + tangential_history_index = 0; + roll_history_index = twist_history_index = 0; + +} + +/* ---------------------------------------------------------------------- */ +PairGranular::~PairGranular() +{ + delete [] svector; + if (fix_history) modify->delete_fix("NEIGH_HISTORY"); + + if (allocated) { + memory->destroy(setflag); + memory->destroy(cutsq); + memory->destroy(cut); + + memory->destroy(normal_coeffs); + memory->destroy(tangential_coeffs); + memory->destroy(roll_coeffs); + memory->destroy(twist_coeffs); + + delete [] onerad_dynamic; + delete [] onerad_frozen; + delete [] maxrad_dynamic; + delete [] maxrad_frozen; + } + memory->destroy(mass_rigid); +} + +void PairGranular::compute(int eflag, int vflag){ +#ifdef TEMPLATED_PAIR_GRANULAR + if (normal == HOOKE){ + if (damping == VELOCITY){ + if (tangential == TANGENTIAL_NOHISTORY){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<0,0,0,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<0,0,0,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<0,0,0,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<0,0,0,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<0,0,0,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<0,0,0,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<0,0,0,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<0,0,0,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<0,0,0,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<0,0,0,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<0,0,0,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<0,0,0,3,2>(eflag, vflag); + } + } + else if (tangential == TANGENTIAL_MINDLIN){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<0,0,1,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<0,0,1,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<0,0,1,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<0,0,1,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<0,0,1,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<0,0,1,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<0,0,1,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<0,0,1,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<0,0,1,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<0,0,1,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<0,0,1,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<0,0,1,3,2>(eflag, vflag); + } + } + } + else if (damping == VISCOELASTIC){ + if (tangential == TANGENTIAL_NOHISTORY){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<0,1,0,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<0,1,0,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<0,1,0,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<0,1,0,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<0,1,0,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<0,1,0,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<0,1,0,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<0,1,0,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<0,1,0,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<0,1,0,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<0,1,0,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<0,1,0,3,2>(eflag, vflag); + } + } + else if (tangential == TANGENTIAL_MINDLIN){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<0,1,1,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<0,1,1,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<0,1,1,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<0,1,1,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<0,1,1,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<0,1,1,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<0,1,1,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<0,1,1,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<0,1,1,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<0,1,1,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<0,1,1,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<0,1,1,3,2>(eflag, vflag); + } + } + } + else if (damping == TSUJI){ + if (tangential == TANGENTIAL_NOHISTORY){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<0,2,0,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<0,2,0,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<0,2,0,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<0,2,0,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<0,2,0,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<0,2,0,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<0,2,0,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<0,2,0,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<0,2,0,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<0,2,0,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<0,2,0,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<0,2,0,3,2>(eflag, vflag); + } + } + else if (tangential == TANGENTIAL_MINDLIN){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<0,2,1,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<0,2,1,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<0,2,1,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<0,2,1,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<0,2,1,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<0,2,1,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<0,2,1,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<0,2,1,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<0,2,1,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<0,2,1,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<0,2,1,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<0,2,1,3,2>(eflag, vflag); + } + } + } + } + else if (normal == HERTZ){ + if (damping == VELOCITY){ + if (tangential == TANGENTIAL_NOHISTORY){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<1,0,0,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<1,0,0,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<1,0,0,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<1,0,0,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<1,0,0,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<1,0,0,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<1,0,0,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<1,0,0,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<1,0,0,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<1,0,0,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<1,0,0,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<1,0,0,3,2>(eflag, vflag); + } + } + else if (tangential == TANGENTIAL_MINDLIN){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<1,0,1,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<1,0,1,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<1,0,1,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<1,0,1,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<1,0,1,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<1,0,1,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<1,0,1,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<1,0,1,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<1,0,1,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<1,0,1,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<1,0,1,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<1,0,1,3,2>(eflag, vflag); + } + } + } + else if (damping == VISCOELASTIC){ + if (tangential == TANGENTIAL_NOHISTORY){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<1,1,0,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<1,1,0,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<1,1,0,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<1,1,0,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<1,1,0,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<1,1,0,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<1,1,0,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<1,1,0,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<1,1,0,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<1,1,0,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<1,1,0,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<1,1,0,3,2>(eflag, vflag); + } + } + else if (tangential == TANGENTIAL_MINDLIN){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<1,1,1,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<1,1,1,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<1,1,1,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<1,1,1,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<1,1,1,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<1,1,1,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<1,1,1,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<1,1,1,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<1,1,1,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<1,1,1,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<1,1,1,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<1,1,1,3,2>(eflag, vflag); + } + } + } + else if (damping == TSUJI){ + if (tangential == TANGENTIAL_NOHISTORY){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<1,2,0,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<1,2,0,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<1,2,0,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<1,2,0,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<1,2,0,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<1,2,0,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<1,2,0,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<1,2,0,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<1,2,0,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<1,2,0,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<1,2,0,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<1,2,0,3,2>(eflag, vflag); + } + } + else if (tangential == TANGENTIAL_MINDLIN){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<1,2,1,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<1,2,1,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<1,2,1,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<1,2,1,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<1,2,1,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<1,2,1,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<1,2,1,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<1,2,1,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<1,2,1,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<1,2,1,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<1,2,1,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<1,2,1,3,2>(eflag, vflag); + } + } + } + } + else if (normal == HERTZ_MATERIAL){ + if (damping == VELOCITY){ + if (tangential == TANGENTIAL_NOHISTORY){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<2,0,0,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<2,0,0,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<2,0,0,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<2,0,0,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<2,0,0,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<2,0,0,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<2,0,0,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<2,0,0,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<2,0,0,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<2,0,0,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<2,0,0,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<2,0,0,3,2>(eflag, vflag); + } + } + else if (tangential == TANGENTIAL_MINDLIN){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<2,0,1,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<2,0,1,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<2,0,1,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<2,0,1,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<2,0,1,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<2,0,1,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<2,0,1,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<2,0,1,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<2,0,1,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<2,0,1,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<2,0,1,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<2,0,1,3,2>(eflag, vflag); + } + } + } + else if (damping == VISCOELASTIC){ + if (tangential == TANGENTIAL_NOHISTORY){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<2,1,0,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<2,1,0,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<2,1,0,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<2,1,0,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<2,1,0,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<2,1,0,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<2,1,0,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<2,1,0,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<2,1,0,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<2,1,0,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<2,1,0,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<2,1,0,3,2>(eflag, vflag); + } + } + else if (tangential == TANGENTIAL_MINDLIN){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<2,1,1,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<2,1,1,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<2,1,1,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<2,1,1,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<2,1,1,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<2,1,1,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<2,1,1,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<2,1,1,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<2,1,1,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<2,1,1,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<2,1,1,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<2,1,1,3,2>(eflag, vflag); + } + } + } + else if (damping == TSUJI){ + if (tangential == TANGENTIAL_NOHISTORY){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<2,2,0,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<2,2,0,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<2,2,0,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<2,2,0,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<2,2,0,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<2,2,0,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<2,2,0,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<2,2,0,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<2,2,0,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<2,2,0,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<2,2,0,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<2,2,0,3,2>(eflag, vflag); + } + } + else if (tangential == TANGENTIAL_MINDLIN){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<2,2,1,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<2,2,1,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<2,2,1,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<2,2,1,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<2,2,1,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<2,2,1,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<2,2,1,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<2,2,1,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<2,2,1,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<2,2,1,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<2,2,1,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<2,2,1,3,2>(eflag, vflag); + } + } + } + } + else if (normal == DMT){ + if (damping == VELOCITY){ + if (tangential == TANGENTIAL_NOHISTORY){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<3,0,0,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<3,0,0,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<3,0,0,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<3,0,0,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<3,0,0,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<3,0,0,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<3,0,0,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<3,0,0,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<3,0,0,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<3,0,0,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<3,0,0,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<3,0,0,3,2>(eflag, vflag); + } + } + else if (tangential == TANGENTIAL_MINDLIN){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<3,0,1,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<3,0,1,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<3,0,1,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<3,0,1,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<3,0,1,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<3,0,1,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<3,0,1,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<3,0,1,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<3,0,1,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<3,0,1,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<3,0,1,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<3,0,1,3,2>(eflag, vflag); + } + } + } + else if (damping == VISCOELASTIC){ + if (tangential == TANGENTIAL_NOHISTORY){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<3,1,0,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<3,1,0,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<3,1,0,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<3,1,0,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<3,1,0,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<3,1,0,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<3,1,0,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<3,1,0,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<3,1,0,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<3,1,0,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<3,1,0,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<3,1,0,3,2>(eflag, vflag); + } + } + else if (tangential == TANGENTIAL_MINDLIN){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<3,1,1,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<3,1,1,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<3,1,1,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<3,1,1,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<3,1,1,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<3,1,1,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<3,1,1,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<3,1,1,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<3,1,1,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<3,1,1,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<3,1,1,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<3,1,1,3,2>(eflag, vflag); + } + } + } + else if (damping == TSUJI){ + if (tangential == TANGENTIAL_NOHISTORY){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<3,2,0,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<3,2,0,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<3,2,0,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<3,2,0,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<3,2,0,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<3,2,0,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<3,2,0,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<3,2,0,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<3,2,0,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<3,2,0,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<3,2,0,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<3,2,0,3,2>(eflag, vflag); + } + } + else if (tangential == TANGENTIAL_MINDLIN){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<3,2,1,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<3,2,1,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<3,2,1,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<3,2,1,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<3,2,1,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<3,2,1,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<3,2,1,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<3,2,1,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<3,2,1,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<3,2,1,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<3,2,1,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<3,2,1,3,2>(eflag, vflag); + } + } + } + } + else if (normal == JKR){ + if (damping == VELOCITY){ + if (tangential == TANGENTIAL_NOHISTORY){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<4,0,0,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<4,0,0,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<4,0,0,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<4,0,0,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<4,0,0,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<4,0,0,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<4,0,0,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<4,0,0,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<4,0,0,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<4,0,0,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<4,0,0,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<4,0,0,3,2>(eflag, vflag); + } + } + else if (tangential == TANGENTIAL_MINDLIN){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<4,0,1,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<4,0,1,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<4,0,1,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<4,0,1,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<4,0,1,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<4,0,1,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<4,0,1,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<4,0,1,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<4,0,1,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<4,0,1,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<4,0,1,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<4,0,1,3,2>(eflag, vflag); + } + } + } + else if (damping == VISCOELASTIC){ + if (tangential == TANGENTIAL_NOHISTORY){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<4,1,0,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<4,1,0,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<4,1,0,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<4,1,0,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<4,1,0,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<4,1,0,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<4,1,0,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<4,1,0,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<4,1,0,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<4,1,0,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<4,1,0,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<4,1,0,3,2>(eflag, vflag); + } + } + else if (tangential == TANGENTIAL_MINDLIN){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<4,1,1,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<4,1,1,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<4,1,1,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<4,1,1,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<4,1,1,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<4,1,1,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<4,1,1,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<4,1,1,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<4,1,1,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<4,1,1,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<4,1,1,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<4,1,1,3,2>(eflag, vflag); + } + } + } + else if (damping == TSUJI){ + if (tangential == TANGENTIAL_NOHISTORY){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<4,2,0,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<4,2,0,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<4,2,0,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<4,2,0,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<4,2,0,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<4,2,0,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<4,2,0,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<4,2,0,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<4,2,0,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<4,2,0,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<4,2,0,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<4,2,0,3,2>(eflag, vflag); + } + } + else if (tangential == TANGENTIAL_MINDLIN){ + if (twist == TWIST_NONE){ + if (roll == ROLL_NONE) compute_templated<4,2,1,0,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<4,2,1,0,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<4,2,1,0,2>(eflag, vflag); + } + else if (twist == TWIST_NOHISTORY){ + if (roll == ROLL_NONE) compute_templated<4,2,1,1,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<4,2,1,1,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<4,2,1,1,2>(eflag, vflag); + } + else if (twist == TWIST_SDS){ + if (roll == ROLL_NONE) compute_templated<4,2,1,2,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<4,2,1,2,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<4,2,1,2,2>(eflag, vflag); + } + else if (twist == TWIST_MARSHALL){ + if (roll == ROLL_NONE) compute_templated<4,2,1,3,0>(eflag, vflag); + else if (roll == ROLL_NOHISTORY) compute_templated<4,2,1,3,1>(eflag, vflag); + else if (roll == ROLL_SDS) compute_templated<4,2,1,3,2>(eflag, vflag); + } + } + } + } + +#else + compute_untemplated(Tp_normal, Tp_damping, Tp_tangential, + Tp_roll, Tp_twist, + eflag, vflag); +#endif +} + +#ifdef TEMPLATED_PAIR_GRANULAR +template < int Tp_normal, int Tp_damping, int Tp_tangential, + int Tp_twist, int Tp_roll > +void PairGranular::compute_templated(int eflag, int vflag) +#else +void PairGranular::compute_untemplated + (int Tp_normal, int Tp_damping, int Tp_tangential, + int Tp_twist, int Tp_roll, int eflag, int vflag) +#endif +{ + int i,j,ii,jj,inum,jnum,itype,jtype; + double xtmp,ytmp,ztmp,delx,dely,delz,fx,fy,fz,nx,ny,nz; + double radi,radj,radsum,rsq,r,rinv,rsqinv; + double Reff, delta, dR, dR2; + + double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3; + double wr1,wr2,wr3; + double vtr1,vtr2,vtr3,vrel; + + double knfac, damp_normal; + double k_tangential, damp_tangential; + double Fne, Ft, Fdamp, Fntot, Fcrit, Fscrit, Frcrit; + double fs, fs1, fs2, fs3; + + //For JKR + double R2, coh, F_pulloff, delta_pulloff, dist_pulloff, a, a2, E; + double t0, t1, t2, t3, t4, t5, t6; + double sqrt1, sqrt2, sqrt3, sqrt4; + + double mi,mj,meff,damp,ccel,tor1,tor2,tor3; + double relrot1,relrot2,relrot3,vrl1,vrl2,vrl3,vrlmag,vrlmaginv; + + //Rolling + double k_roll, damp_roll; + double roll1, roll2, roll3, torroll1, torroll2, torroll3; + double rollmag, rolldotn, scalefac; + double fr, fr1, fr2, fr3; + + //Twisting + double k_twist, damp_twist, mu_twist; + double signtwist, magtwist, magtortwist, Mtcrit; + double tortwist1, tortwist2, tortwist3; + + double shrmag,rsht; + int *ilist,*jlist,*numneigh,**firstneigh; + int *touch,**firsttouch; + double *history,*allhistory,**firsthistory; + + bool touchflag; + + if (eflag || vflag) ev_setup(eflag,vflag); + else evflag = vflag_fdotr = 0; + + int historyupdate = 1; + if (update->setupflag) historyupdate = 0; + + // update rigid body info for owned & ghost atoms if using FixRigid masses + // body[i] = which body atom I is in, -1 if none + // mass_body = mass of each rigid body + + if (fix_rigid && neighbor->ago == 0){ + int tmp; + int *body = (int *) fix_rigid->extract("body",tmp); + double *mass_body = (double *) fix_rigid->extract("masstotal",tmp); + if (atom->nmax > nmax) { + memory->destroy(mass_rigid); + nmax = atom->nmax; + memory->create(mass_rigid,nmax,"pair:mass_rigid"); + } + int nlocal = atom->nlocal; + for (i = 0; i < nlocal; i++) + if (body[i] >= 0) mass_rigid[i] = mass_body[body[i]]; + else mass_rigid[i] = 0.0; + comm->forward_comm_pair(this); + } + + double **x = atom->x; + double **v = atom->v; + double **f = atom->f; + int *type = atom->type; + double **omega = atom->omega; + double **torque = atom->torque; + double *radius = atom->radius; + double *rmass = atom->rmass; + int *mask = atom->mask; + int nlocal = atom->nlocal; + int newton_pair = force->newton_pair; + + inum = list->inum; + ilist = list->ilist; + numneigh = list->numneigh; + firstneigh = list->firstneigh; + firsttouch = fix_history->firstflag; + firsthistory = fix_history->firstvalue; + + for (ii = 0; ii < inum; ii++) { + i = ilist[ii]; + itype = type[i]; + xtmp = x[i][0]; + ytmp = x[i][1]; + ztmp = x[i][2]; + itype = type[i]; + radi = radius[i]; + touch = firsttouch[i]; + allhistory = firsthistory[i]; + jlist = firstneigh[i]; + jnum = numneigh[i]; + + for (jj = 0; jj < jnum; jj++){ + j = jlist[jj]; + j &= NEIGHMASK; + + delx = xtmp - x[j][0]; + dely = ytmp - x[j][1]; + delz = ztmp - x[j][2]; + jtype = type[j]; + rsq = delx*delx + dely*dely + delz*delz; + radj = radius[j]; + radsum = radi + radj; + + E = normal_coeffs[itype][jtype][0]; + Reff = radi*radj/(radi+radj); + touchflag = false; + + if (Tp_normal == JKR){ + if (touch[jj]){ + R2 = Reff*Reff; + coh = normal_coeffs[itype][jtype][3]; + a = cbrt(9.0*M_PI*coh*R2/(4*E)); + delta_pulloff = a*a/Reff - 2*sqrt(M_PI*coh*a/E); + dist_pulloff = radsum-delta_pulloff; + touchflag = (rsq < dist_pulloff*dist_pulloff); + } + else{ + touchflag = (rsq < radsum*radsum); + } + } + else{ + touchflag = (rsq < radsum*radsum); + } + + if (!touchflag){ + // unset non-touching neighbors + touch[jj] = 0; + history = &allhistory[size_history*jj]; + for (int k = 0; k < size_history; k++) history[k] = 0.0; + } + else{ + r = sqrt(rsq); + rinv = 1.0/r; + + nx = delx*rinv; + ny = dely*rinv; + nz = delz*rinv; + + // relative translational velocity + + vr1 = v[i][0] - v[j][0]; + vr2 = v[i][1] - v[j][1]; + vr3 = v[i][2] - v[j][2]; + + // normal component + + vnnr = vr1*nx + vr2*ny + vr3*nz; //v_R . n + vn1 = nx*vnnr; + vn2 = ny*vnnr; + vn3 = nz*vnnr; + + // meff = effective mass of pair of particles + // if I or J part of rigid body, use body mass + // if I or J is frozen, meff is other particle + + mi = rmass[i]; + mj = rmass[j]; + if (fix_rigid) { + if (mass_rigid[i] > 0.0) mi = mass_rigid[i]; + if (mass_rigid[j] > 0.0) mj = mass_rigid[j]; + } + + meff = mi*mj / (mi+mj); + if (mask[i] & freeze_group_bit) meff = mj; + if (mask[j] & freeze_group_bit) meff = mi; + + delta = radsum - r; + dR = delta*Reff; + if (Tp_normal == JKR){ + touch[jj] = 1; + R2=Reff*Reff; + coh = normal_coeffs[itype][jtype][3]; + dR2 = dR*dR; + t0 = coh*coh*R2*R2*E; + t1 = PI27SQ*t0; + t2 = 8*dR*dR2*E*E*E; + t3 = 4*dR2*E; + sqrt1 = MAX(0, t0*(t1+2*t2)); //In case of sqrt(0) < 0 due to precision issues + t4 = cbrt(t1+t2+THREEROOT3*M_PI*sqrt(sqrt1)); + t5 = t3/t4 + t4/E; + sqrt2 = MAX(0, 2*dR + t5); + t6 = sqrt(sqrt2); + sqrt3 = MAX(0, 4*dR - t5 + SIXROOT6*coh*M_PI*R2/(E*t6)); + a = INVROOT6*(t6 + sqrt(sqrt3)); + a2 = a*a; + knfac = FOURTHIRDS*E*a; + Fne = knfac*a2/Reff - TWOPI*a2*sqrt(4*coh*E/(M_PI*a)); + } + else{ + knfac = E; //Hooke + Fne = knfac*delta; + if (Tp_normal != HOOKE) + a = sqrt(dR); + Fne *= a; + if (Tp_normal == DMT) + Fne -= 4*MY_PI*normal_coeffs[itype][jtype][3]*Reff; + } + + //Consider restricting Hooke to only have 'velocity' as an option for damping? + if (Tp_damping == VELOCITY){ + damp_normal = 1; + } + else if (Tp_damping == VISCOELASTIC){ + if (Tp_normal == HOOKE) a = sqrt(dR); + damp_normal = a*meff; + } + else if (Tp_damping == TSUJI){ + damp_normal = sqrt(meff*knfac); + } + + Fdamp = -normal_coeffs[itype][jtype][1]*damp_normal*vnnr; + + Fntot = Fne + Fdamp; + + //**************************************** + //Tangential force, including history effects + //**************************************** + + // tangential component + vt1 = vr1 - vn1; + vt2 = vr2 - vn2; + vt3 = vr3 - vn3; + + // relative rotational velocity + wr1 = (radi*omega[i][0] + radj*omega[j][0]); + wr2 = (radi*omega[i][1] + radj*omega[j][1]); + wr3 = (radi*omega[i][2] + radj*omega[j][2]); + + // relative tangential velocities + vtr1 = vt1 - (nz*wr2-ny*wr3); + vtr2 = vt2 - (nx*wr3-nz*wr1); + vtr3 = vt3 - (ny*wr1-nx*wr2); + vrel = vtr1*vtr1 + vtr2*vtr2 + vtr3*vtr3; + vrel = sqrt(vrel); + + // If any history is needed: + if (use_history){ + touch[jj] = 1; + history = &allhistory[size_history*jj]; + } + + + if (Tp_normal == JKR){ + F_pulloff = 3*M_PI*coh*Reff; + Fcrit = fabs(Fne + 2*F_pulloff); + } + else{ + Fcrit = fabs(Fne); + } + + //------------------------------ + //Tangential forces + //------------------------------ + k_tangential = tangential_coeffs[itype][jtype][0]; + damp_tangential = tangential_coeffs[itype][jtype][1]*damp_normal; + + if (Tp_tangential > 0){ + shrmag = sqrt(history[0]*history[0] + history[1]*history[1] + + history[2]*history[2]); + + // Rotate and update displacements. + // See e.g. eq. 17 of Luding, Gran. Matter 2008, v10,p235 + if (historyupdate) { + rsht = history[0]*nx + history[1]*ny + history[2]*nz; + if (fabs(rsht) < EPSILON) rsht = 0; + if (rsht > 0){ + scalefac = shrmag/(shrmag - rsht); //if rhst == shrmag, contacting pair has rotated 90 deg. in one step, in which case you deserve a crash! + history[0] -= rsht*nx; + history[1] -= rsht*ny; + history[2] -= rsht*nz; + //Also rescale to preserve magnitude + history[0] *= scalefac; + history[1] *= scalefac; + history[2] *= scalefac; + } + //Update history + history[0] += vtr1*dt; + history[1] += vtr2*dt; + history[2] += vtr3*dt; + } + + // tangential forces = history + tangential velocity damping + fs1 = -k_tangential*history[0] - damp_tangential*vtr1; + fs2 = -k_tangential*history[1] - damp_tangential*vtr2; + fs3 = -k_tangential*history[2] - damp_tangential*vtr3; + + // rescale frictional displacements and forces if needed + Fscrit = tangential_coeffs[itype][jtype][2] * Fcrit; + fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); + if (fs > Fscrit) { + if (shrmag != 0.0) { + history[0] = -1.0/k_tangential*(Fscrit*fs1/fs + damp_tangential*vtr1); + history[1] = -1.0/k_tangential*(Fscrit*fs2/fs + damp_tangential*vtr2); + history[2] = -1.0/k_tangential*(Fscrit*fs3/fs + damp_tangential*vtr3); + fs1 *= Fscrit/fs; + fs2 *= Fscrit/fs; + fs3 *= Fscrit/fs; + } else fs1 = fs2 = fs3 = 0.0; + } + } + else{ //Classic pair gran/hooke (no history) + fs = meff*damp_tangential*vrel; + if (vrel != 0.0) Ft = MIN(Fne,fs) / vrel; + else Ft = 0.0; + fs1 = -Ft*vtr1; + fs2 = -Ft*vtr2; + fs3 = -Ft*vtr3; + } + + //**************************************** + // Rolling resistance + //**************************************** + + if (Tp_roll != ROLL_NONE){ + relrot1 = omega[i][0] - omega[j][0]; + relrot2 = omega[i][1] - omega[j][1]; + relrot3 = omega[i][2] - omega[j][2]; + + // rolling velocity, see eq. 31 of Wang et al, Particuology v 23, p 49 (2015) + // This is different from the Marshall papers, which use the Bagi/Kuhn formulation + // for rolling velocity (see Wang et al for why the latter is wrong) + vrl1 = Reff*(relrot2*nz - relrot3*ny); //- 0.5*((radj-radi)/radsum)*vtr1; + vrl2 = Reff*(relrot3*nx - relrot1*nz); //- 0.5*((radj-radi)/radsum)*vtr2; + vrl3 = Reff*(relrot1*ny - relrot2*nx); //- 0.5*((radj-radi)/radsum)*vtr3; + vrlmag = sqrt(vrl1*vrl1+vrl2*vrl2+vrl3*vrl3); + if (vrlmag != 0.0) vrlmaginv = 1.0/vrlmag; + else vrlmaginv = 0.0; + + if (Tp_roll > 1){ + int rhist0 = roll_history_index; + int rhist1 = rhist0 + 1; + int rhist2 = rhist1 + 1; + + // Rolling displacement + rollmag = sqrt(history[rhist0]*history[rhist0] + + history[rhist1]*history[rhist1] + + history[rhist2]*history[rhist2]); + + rolldotn = history[rhist0]*nx + history[rhist1]*ny + history[rhist2]*nz; + + if (historyupdate){ + if (fabs(rolldotn) < EPSILON) rolldotn = 0; + if (rolldotn > 0){ //Rotate into tangential plane + scalefac = rollmag/(rollmag - rolldotn); + history[rhist0] -= rolldotn*nx; + history[rhist1] -= rolldotn*ny; + history[rhist2] -= rolldotn*nz; + //Also rescale to preserve magnitude + history[rhist0] *= scalefac; + history[rhist1] *= scalefac; + history[rhist2] *= scalefac; + } + history[rhist0] += vrl1*dt; + history[rhist1] += vrl2*dt; + history[rhist2] += vrl3*dt; + } + + k_roll = roll_coeffs[itype][jtype][0]; + damp_roll = roll_coeffs[itype][jtype][1]; + fr1 = -k_roll*history[rhist0] - damp_roll*vrl1; + fr2 = -k_roll*history[rhist1] - damp_roll*vrl2; + fr3 = -k_roll*history[rhist2] - damp_roll*vrl3; + + // rescale frictional displacements and forces if needed + Frcrit = roll_coeffs[itype][jtype][2] * Fcrit; + + fr = sqrt(fr1*fr1 + fr2*fr2 + fr3*fr3); + if (fr > Frcrit) { + if (rollmag != 0.0) { + history[rhist0] = -1.0/k_roll*(Frcrit*fr1/fr + damp_roll*vrl1); + history[rhist1] = -1.0/k_roll*(Frcrit*fr2/fr + damp_roll*vrl2); + history[rhist2] = -1.0/k_roll*(Frcrit*fr3/fr + damp_roll*vrl3); + fr1 *= Frcrit/fr; + fr2 *= Frcrit/fr; + fr3 *= Frcrit/fr; + } else fr1 = fr2 = fr3 = 0.0; + } + } + else{ // + fr = meff*roll_coeffs[itype][jtype][1]*vrlmag; + if (vrlmag != 0.0) fr = MIN(Fne, fr) / vrlmag; + else fr = 0.0; + fr1 = -fr*vrl1; + fr2 = -fr*vrl2; + fr3 = -fr*vrl3; + } + } + + //**************************************** + // Twisting torque, including history effects + //**************************************** + if (Tp_twist != TWIST_NONE){ + magtwist = relrot1*nx + relrot2*ny + relrot3*nz; //Omega_T (eq 29 of Marshall) + if (Tp_twist == TWIST_MARSHALL){ + k_twist = 0.5*k_tangential*a*a;; //eq 32 + damp_twist = 0.5*damp_tangential*a*a; + mu_twist = TWOTHIRDS*a; + } + else{ + k_twist = twist_coeffs[itype][jtype][0]; + damp_twist = twist_coeffs[itype][jtype][1]; + mu_twist = twist_coeffs[itype][jtype][2]; + } + if (Tp_twist > 1){ + if (historyupdate){ + history[twist_history_index] += magtwist*dt; + } + magtortwist = -k_twist*history[twist_history_index] - damp_twist*magtwist;//M_t torque (eq 30) + signtwist = (magtwist > 0) - (magtwist < 0); + Mtcrit = TWOTHIRDS*a*Fscrit;//critical torque (eq 44) + if (fabs(magtortwist) > Mtcrit) { + history[twist_history_index] = 1.0/k_twist*(Mtcrit*signtwist - damp_twist*magtwist); + magtortwist = -Mtcrit * signtwist; //eq 34 + } + } + else{ + if (magtwist > 0) magtortwist = -damp_twist*magtwist; + else magtortwist = 0; + } + } + // Apply forces & torques + + fx = nx*Fntot + fs1; + fy = ny*Fntot + fs2; + fz = nz*Fntot + fs3; + + f[i][0] += fx; + f[i][1] += fy; + f[i][2] += fz; + + tor1 = ny*fs3 - nz*fs2; + tor2 = nz*fs1 - nx*fs3; + tor3 = nx*fs2 - ny*fs1; + + torque[i][0] -= radi*tor1; + torque[i][1] -= radi*tor2; + torque[i][2] -= radi*tor3; + + if (Tp_twist != TWIST_NONE){ + tortwist1 = magtortwist * nx; + tortwist2 = magtortwist * ny; + tortwist3 = magtortwist * nz; + + torque[i][0] += tortwist1; + torque[i][1] += tortwist2; + torque[i][2] += tortwist3; + } + + if (Tp_roll != ROLL_NONE){ + torroll1 = Reff*(ny*fr3 - nz*fr2); //n cross fr + torroll2 = Reff*(nz*fr1 - nx*fr3); + torroll3 = Reff*(nx*fr2 - ny*fr1); + + torque[i][0] += torroll1; + torque[i][1] += torroll2; + torque[i][2] += torroll3; + } + + if (force->newton_pair || j < nlocal) { + f[j][0] -= fx; + f[j][1] -= fy; + f[j][2] -= fz; + + torque[j][0] -= radj*tor1; + torque[j][1] -= radj*tor2; + torque[j][2] -= radj*tor3; + + if (Tp_twist != TWIST_NONE){ + torque[j][0] -= tortwist1; + torque[j][1] -= tortwist2; + torque[j][2] -= tortwist3; + } + if (Tp_roll != ROLL_NONE){ + torque[j][0] -= torroll1; + torque[j][1] -= torroll2; + torque[j][2] -= torroll3; + } + } + if (evflag) ev_tally_xyz(i,j,nlocal,0, + 0.0,0.0,fx,fy,fz,delx,dely,delz); + } + } + } +} + + +/* ---------------------------------------------------------------------- +allocate all arrays +------------------------------------------------------------------------- */ + +void PairGranular::allocate() +{ + allocated = 1; + int n = atom->ntypes; + + memory->create(setflag,n+1,n+1,"pair:setflag"); + for (int i = 1; i <= n; i++) + for (int j = i; j <= n; j++) + setflag[i][j] = 0; + + memory->create(cutsq,n+1,n+1,"pair:cutsq"); + memory->create(cut,n+1,n+1,"pair:cut"); + memory->create(normal_coeffs,n+1,n+1,4,"pair:normal_coeffs"); + memory->create(tangential_coeffs,n+1,n+1,3,"pair:tangential_coeffs"); + memory->create(roll_coeffs,n+1,n+1,3,"pair:roll_coeffs"); + memory->create(twist_coeffs,n+1,n+1,3,"pair:twist_coeffs"); + + onerad_dynamic = new double[n+1]; + onerad_frozen = new double[n+1]; + maxrad_dynamic = new double[n+1]; + maxrad_frozen = new double[n+1]; +} + +/* ---------------------------------------------------------------------- + global settings +------------------------------------------------------------------------- */ + +void PairGranular::settings(int narg, char **arg) +{ + if (narg == 1){ + cutoff_global = force->numeric(FLERR,arg[0]); + } + else{ + cutoff_global = -1; //Will be set based on particle sizes, model choice + } + tangential_history = 0; + roll_history = twist_history = 0; + normal_set = tangential_set = damping_set = roll_set = twist_set = 0; +} + +/* ---------------------------------------------------------------------- + set coeffs for one or more type pairs +------------------------------------------------------------------------- */ + +void PairGranular::coeff(int narg, char **arg) +{ + double normal_coeffs_local[4]; + double tangential_coeffs_local[4]; + double roll_coeffs_local[4]; + double twist_coeffs_local[4]; + + if (narg < 2) + error->all(FLERR,"Incorrect args for pair coefficients"); + + if (!allocated) allocate(); + + int ilo,ihi,jlo,jhi; + force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); + force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); + + int iarg = 2; + while (iarg < narg){ + if (strcmp(arg[iarg], "hooke") == 0){ + if (iarg + 2 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hooke option"); + if (!normal_set) normal = HOOKE; + else if (normal != HOOKE) error->all(FLERR, "Illegal pair_coeff command, choice of normal contact model must be the same for all types"); + normal_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1]); //kn + normal_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //damping + normal_set = 1; + iarg += 3; + } + else if (strcmp(arg[iarg], "hertz") == 0){ + int num_coeffs = 2; + if (iarg + num_coeffs >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hertz option"); + if (!normal_set) normal = HERTZ; + else if (normal_set && normal != HERTZ) if (normal != HOOKE) error->all(FLERR, "Illegal pair_coeff command, choice of normal contact model must be the same for all types"); + normal_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1]); //kn + normal_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //damping + normal_set = 1; + iarg += num_coeffs+1; + } + else if (strcmp(arg[iarg], "hertz/material") == 0){ + int num_coeffs = 3; + if (iarg + num_coeffs >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hertz option"); + if (!normal_set) normal = HERTZ_MATERIAL; + else if (normal != HERTZ) if (normal != HOOKE) error->all(FLERR, "Illegal pair_coeff command, choice of normal contact model must be the same for all types"); + normal_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1])*FOURTHIRDS; //E + normal_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //damping + normal_coeffs_local[2] = force->numeric(FLERR,arg[iarg+3]); //G + normal_set = 1; + iarg += num_coeffs+1; + } + else if (strcmp(arg[iarg], "dmt") == 0){ + if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hertz option"); + if (!normal_set) normal = DMT; + else if (normal != DMT) error->all(FLERR, "Illegal pair_coeff command, choice of normal contact model must be the same for all types"); + normal_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1])*FOURTHIRDS; //E + normal_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //damping + normal_coeffs_local[2] = force->numeric(FLERR,arg[iarg+3]); //G + normal_coeffs_local[3] = force->numeric(FLERR,arg[iarg+3]); //cohesion + normal_set = 1; + iarg += 5; + } + else if (strcmp(arg[iarg], "jkr") == 0){ + if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for JKR option"); + beyond_contact = 1; + if (!normal_set) normal = JKR; + else if (normal != JKR) error->all(FLERR, "Illegal pair_coeff command, choice of normal contact model must be the same for all types"); + normal_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1]); //E + normal_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //damping + normal_coeffs_local[2] = force->numeric(FLERR,arg[iarg+3]); //G + normal_coeffs_local[3] = force->numeric(FLERR,arg[iarg+4]); //cohesion + normal_set = 1; + iarg += 5; + } + else if (strcmp(arg[iarg], "damp") == 0){ + if (iarg+1 >= narg) error->all(FLERR, "Illegal pair_coeff command, not enough parameters provided for damping model"); + if (strcmp(arg[iarg+1], "velocity") == 0){ + if (!damping_set) damping = VELOCITY; + else if (damping != VELOCITY) error->all(FLERR, "Illegal pair_coeff command, choice of damping contact model must be the same for all types"); + } + else if (strcmp(arg[iarg+1], "viscoelastic") == 0){ + if (!damping_set) damping = VISCOELASTIC; + else if (damping != VISCOELASTIC) error->all(FLERR, "Illegal pair_coeff command, choice of damping contact model must be the same for all types"); + } + else if (strcmp(arg[iarg+1], "tsuji") == 0){ + if (!damping_set) damping = TSUJI; + if (damping != TSUJI) error->all(FLERR, "Illegal pair_coeff command, choice of damping contact model must be the same for all types"); + } + damping_set = 1; + iarg += 2; + } + else if (strcmp(arg[iarg], "tangential") == 0){ + if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for tangential model"); + if (strcmp(arg[iarg+1], "nohistory") == 0){ + if (!tangential_set) tangential = TANGENTIAL_NOHISTORY; + else if (tangential != TANGENTIAL_NOHISTORY) error->all(FLERR, "Illegal pair_coeff command, choice of tangential contact model must be the same for all types"); + } + else if (strcmp(arg[iarg+1], "mindlin") == 0){ + if (!tangential_set) tangential = TANGENTIAL_MINDLIN; + else if (tangential != TANGENTIAL_MINDLIN) error->all(FLERR, "Illegal pair_coeff command, choice of tangential contact model must be the same for all types");; + tangential_history = 1; + } + else{ + error->all(FLERR, "Illegal pair_coeff command, tangential model not recognized"); + } + tangential_set = 1; + tangential_coeffs_local[0] = force->numeric(FLERR,arg[iarg+2]); //kt + tangential_coeffs_local[1] = force->numeric(FLERR,arg[iarg+3]); //gammat + tangential_coeffs_local[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. + iarg += 5; + } + else if (strcmp(arg[iarg], "rolling") == 0){ + if (iarg + 1 >= narg) error->all(FLERR, "Illegal pair_coeff command, not enough parameters"); + if (strcmp(arg[iarg+1], "none") == 0){ + if (!roll_set) roll = ROLL_NONE; + else if (roll != ROLL_NONE) error->all(FLERR, "Illegal pair_coeff command, choice of rolling friction model must be the same for all types"); + iarg += 2; + } + else{ + if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for rolling model"); + if (strcmp(arg[iarg+1], "nohistory") == 0){ + if (!roll_set) roll = ROLL_NOHISTORY; + else if (roll != ROLL_NOHISTORY) error->all(FLERR, "Illegal pair_coeff command, choice of rolling friction model must be the same for all types"); + } + else if (strcmp(arg[iarg+1], "sds") == 0){ + if (!roll_set) roll = ROLL_SDS; + else if (roll != ROLL_SDS) error->all(FLERR, "Illegal pair_coeff command, choice of rolling friction model must be the same for all types"); + roll_history = 1; + } + else{ + error->all(FLERR, "Illegal pair_coeff command, rolling friction model not recognized"); + } + roll_set =1 ; + roll_coeffs_local[0] = force->numeric(FLERR,arg[iarg+2]); //kR + roll_coeffs_local[1] = force->numeric(FLERR,arg[iarg+3]); //gammaR + roll_coeffs_local[2] = force->numeric(FLERR,arg[iarg+4]); //rolling friction coeff. + iarg += 5; + } + } + else if (strcmp(arg[iarg], "twisting") == 0){ + if (iarg + 1 >= narg) error->all(FLERR, "Illegal pair_coeff command, not enough parameters"); + if (strcmp(arg[iarg+1], "none") == 0){ + if (!twist_set) twist = TWIST_NONE; + else if (twist != TWIST_NONE) error->all(FLERR, "Illegal pair_coeff command, choice of twisting friction model must be the same for all types"); + iarg += 2; + } + else if (strcmp(arg[iarg+1], "marshall") == 0){ + if (!twist_set) twist = TWIST_MARSHALL; + else if (twist != TWIST_MARSHALL) error->all(FLERR, "Illegal pair_coeff command, choice of twisting friction model must be the same for all types"); + twist_history = 1; + twist_set = 1; + iarg += 2; + } + else{ + if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for twist model"); + else if (strcmp(arg[iarg+1], "nohistory") == 0){ + if (!twist_set) twist = TWIST_NOHISTORY; + if (twist != TWIST_NOHISTORY) error->all(FLERR, "Illegal pair_coeff command, choice of twisting friction model must be the same for all types"); + } + else if (strcmp(arg[iarg+1], "sds") == 0){ + if (!twist_set) twist = TWIST_SDS; + else if (twist != TWIST_SDS) error->all(FLERR, "Illegal pair_coeff command, choice of twisting friction model must be the same for all types"); + twist_history = 1; + } + else{ + error->all(FLERR, "Illegal pair_coeff command, twisting friction model not recognized"); + } + twist_set = 1; + twist_coeffs_local[0] = force->numeric(FLERR,arg[iarg+2]); //kt + twist_coeffs_local[1] = force->numeric(FLERR,arg[iarg+3]); //gammat + twist_coeffs_local[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. + iarg += 5; + } + } + else error->all(FLERR, "Illegal pair coeff command"); + } + + //It is an error not to specify normal or tangential model + if (!normal_set) error->all(FLERR, "Illegal pair coeff command, must specify normal contact model"); + if (!tangential_set) error->all(FLERR, "Illegal pair coeff command, must specify tangential contact model"); + + //If unspecified, set damping to VISCOELASTIC, twist/roll to NONE (cannot be changed by subsequent pair_coeff commands) + if (!damping_set) damping = VISCOELASTIC; + if (!roll_set) roll = ROLL_NONE; + if (!twist_set) twist = TWIST_NONE; + damping_set = roll_set = twist_set = 1; + + int count = 0; + double damp; + if (damping == TSUJI){ + double cor; + cor = normal_coeffs_local[1]; + damp = 1.2728-4.2783*cor+11.087*pow(cor,2)-22.348*pow(cor,3)+ + 27.467*pow(cor,4)-18.022*pow(cor,5)+ + 4.8218*pow(cor,6); + } + else damp = normal_coeffs_local[1]; + + for (int i = ilo; i <= ihi; i++) { + for (int j = MAX(jlo,i); j <= jhi; j++) { + normal_coeffs[i][j][0] = normal_coeffs[j][i][0] = normal_coeffs_local[0]; + normal_coeffs[i][j][1] = normal_coeffs[j][i][1] = damp; + if (normal != HERTZ && normal != HOOKE) normal_coeffs[i][j][2] = normal_coeffs_local[2]; + if ((normal == JKR) || (normal == DMT)) + normal_coeffs[i][j][3] = normal_coeffs[j][i][3] = normal_coeffs_local[3]; + + for (int k = 0; k < 3; k++) + tangential_coeffs[i][j][k] = tangential_coeffs[j][i][k] = tangential_coeffs_local[k]; + + if (roll != ROLL_NONE) + for (int k = 0; k < 3; k++) + roll_coeffs[i][j][k] = roll_coeffs[j][i][k] = roll_coeffs_local[k]; + + if (twist != TWIST_NONE && twist != TWIST_MARSHALL) + for (int k = 0; k < 3; k++) + twist_coeffs[i][j][k] = twist_coeffs[j][i][k] = twist_coeffs_local[k]; + + setflag[i][j] = 1; + count++; + } + } + + if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); +} + +/* ---------------------------------------------------------------------- + init specific to this pair style +------------------------------------------------------------------------- */ + +void PairGranular::init_style() +{ + int i; + + // error and warning checks + + if (!atom->radius_flag || !atom->rmass_flag) + error->all(FLERR,"Pair granular requires atom attributes radius, rmass"); + if (comm->ghost_velocity == 0) + error->all(FLERR,"Pair granular requires ghost atoms store velocity"); + + // Determine whether we need a granular neigh list, how large it needs to be + use_history = tangential_history || roll_history || twist_history; + + //For JKR, will need fix/neigh/history to keep track of touch arrays + if (normal == JKR) use_history = 1; + + size_history = 3*tangential_history + 3*roll_history + twist_history; + + //Determine location of tangential/roll/twist histories in array + if (roll_history){ + if (tangential_history) roll_history_index = 3; + else roll_history_index = 0; + } + if (twist_history){ + if (tangential_history){ + if (roll_history) twist_history_index = 6; + else twist_history_index = 3; + } + else{ + if (roll_history) twist_history_index = 3; + else twist_history_index = 0; + } + } + + int irequest = neighbor->request(this,instance_me); + neighbor->requests[irequest]->size = 1; + if (use_history) neighbor->requests[irequest]->history = 1; + + dt = update->dt; + + // if history is stored: + // if first init, create Fix needed for storing history + + if (use_history && fix_history == NULL) { + char dnumstr[16]; + sprintf(dnumstr,"%d",size_history); + char **fixarg = new char*[4]; + fixarg[0] = (char *) "NEIGH_HISTORY"; + fixarg[1] = (char *) "all"; + fixarg[2] = (char *) "NEIGH_HISTORY"; + fixarg[3] = dnumstr; + modify->add_fix(4,fixarg,1); + delete [] fixarg; + fix_history = (FixNeighHistory *) modify->fix[modify->nfix-1]; + fix_history->pair = this; + } + + // check for FixFreeze and set freeze_group_bit + + for (i = 0; i < modify->nfix; i++) + if (strcmp(modify->fix[i]->style,"freeze") == 0) break; + if (i < modify->nfix) freeze_group_bit = modify->fix[i]->groupbit; + else freeze_group_bit = 0; + + // check for FixRigid so can extract rigid body masses + + fix_rigid = NULL; + for (i = 0; i < modify->nfix; i++) + if (modify->fix[i]->rigid_flag) break; + if (i < modify->nfix) fix_rigid = modify->fix[i]; + + // check for FixPour and FixDeposit so can extract particle radii + + int ipour; + for (ipour = 0; ipour < modify->nfix; ipour++) + if (strcmp(modify->fix[ipour]->style,"pour") == 0) break; + if (ipour == modify->nfix) ipour = -1; + + int idep; + for (idep = 0; idep < modify->nfix; idep++) + if (strcmp(modify->fix[idep]->style,"deposit") == 0) break; + if (idep == modify->nfix) idep = -1; + + // set maxrad_dynamic and maxrad_frozen for each type + // include future FixPour and FixDeposit particles as dynamic + + int itype; + for (i = 1; i <= atom->ntypes; i++) { + onerad_dynamic[i] = onerad_frozen[i] = 0.0; + if (ipour >= 0) { + itype = i; + double radmax = *((double *) modify->fix[ipour]->extract("radius",itype)); + if (normal == JKR) radmax = radmax - 0.5*pulloff_distance(radmax, itype); + onerad_dynamic[i] = radmax; + } + if (idep >= 0) { + itype = i; + double radmax = *((double *) modify->fix[idep]->extract("radius",itype)); + if (normal == JKR) radmax = radmax - 0.5*pulloff_distance(radmax, itype); + onerad_dynamic[i] = radmax; + } + } + + double *radius = atom->radius; + int *mask = atom->mask; + int *type = atom->type; + int nlocal = atom->nlocal; + + for (i = 0; i < nlocal; i++){ + double radius_cut = radius[i]; + if (normal == JKR){ + radius_cut = radius[i] - 0.5*pulloff_distance(radius[i], type[i]); + } + if (mask[i] & freeze_group_bit){ + onerad_frozen[type[i]] = MAX(onerad_frozen[type[i]],radius_cut); + } + else{ + onerad_dynamic[type[i]] = MAX(onerad_dynamic[type[i]],radius_cut); + } + } + + MPI_Allreduce(&onerad_dynamic[1],&maxrad_dynamic[1],atom->ntypes, + MPI_DOUBLE,MPI_MAX,world); + MPI_Allreduce(&onerad_frozen[1],&maxrad_frozen[1],atom->ntypes, + MPI_DOUBLE,MPI_MAX,world); + + // set fix which stores history info + + if (size_history > 0){ + int ifix = modify->find_fix("NEIGH_HISTORY"); + if (ifix < 0) error->all(FLERR,"Could not find pair fix neigh history ID"); + fix_history = (FixNeighHistory *) modify->fix[ifix]; + } +} + +/* ---------------------------------------------------------------------- + init for one type pair i,j and corresponding j,i +------------------------------------------------------------------------- */ + +double PairGranular::init_one(int i, int j) +{ + double cutoff; + if (setflag[i][j] == 0) { + + if (normal != HOOKE && normal != HERTZ){ + normal_coeffs[i][j][0] = normal_coeffs[j][i][0] = mix_stiffnessE(normal_coeffs[i][i][0], normal_coeffs[j][j][0], + normal_coeffs[i][i][2], normal_coeffs[j][j][2]); + normal_coeffs[i][j][2] = normal_coeffs[j][i][2] = mix_stiffnessG(normal_coeffs[i][i][0], normal_coeffs[j][j][0], + normal_coeffs[i][i][2], normal_coeffs[j][j][2]); + } + else{ + normal_coeffs[i][j][0] = normal_coeffs[j][i][0] = mix_geom(normal_coeffs[i][i][0], normal_coeffs[j][j][0]); + } + + normal_coeffs[i][j][1] = normal_coeffs[j][i][1] = mix_geom(normal_coeffs[i][i][1], normal_coeffs[j][j][1]); + if ((normal == JKR) || (normal == DMT)) + normal_coeffs[i][j][3] = normal_coeffs[j][i][3] = mix_geom(normal_coeffs[i][i][3], normal_coeffs[j][j][3]); + + for (int k = 0; k < 3; k++) + tangential_coeffs[i][j][k] = tangential_coeffs[j][i][k] = mix_geom(tangential_coeffs[i][i][k], tangential_coeffs[j][j][k]); + + + if (roll != ROLL_NONE){ + for (int k = 0; k < 3; k++) + roll_coeffs[i][j][k] = roll_coeffs[j][i][k] = mix_geom(roll_coeffs[i][i][k], roll_coeffs[j][j][k]); + } + + if (twist != TWIST_NONE && twist != TWIST_MARSHALL){ + for (int k = 0; k < 3; k++) + twist_coeffs[i][j][k] = twist_coeffs[j][i][k] = mix_geom(twist_coeffs[i][i][k], twist_coeffs[j][j][k]); + } + } + + // It is possible that cut[i][j] at this point is still 0.0. This can happen when + // there is a future fix_pour after the current run. A cut[i][j] = 0.0 creates + // problems because neighbor.cpp uses min(cut[i][j]) to decide on the bin size + // To avoid this issue, for cases involving cut[i][j] = 0.0 (possible only + // if there is no current information about radius/cutoff of type i and j). + // we assign cutoff = max(cut[i][j]) for i,j such that cut[i][j] > 0.0. + + if (cutoff_global < 0){ + if (((maxrad_dynamic[i] > 0.0) && (maxrad_dynamic[j] > 0.0)) || + ((maxrad_dynamic[i] > 0.0) && (maxrad_frozen[j] > 0.0)) || + ((maxrad_frozen[i] > 0.0) && (maxrad_dynamic[j] > 0.0))) { // radius info about both i and j exist + cutoff = maxrad_dynamic[i]+maxrad_dynamic[j]; + cutoff = MAX(cutoff,maxrad_frozen[i]+maxrad_dynamic[j]); + cutoff = MAX(cutoff,maxrad_dynamic[i]+maxrad_frozen[j]); + } + else { // radius info about either i or j does not exist (i.e. not present and not about to get poured; set to largest value to not interfere with neighbor list) + double cutmax = 0.0; + for (int k = 1; k <= atom->ntypes; k++) { + cutmax = MAX(cutmax,2.0*maxrad_dynamic[k]); + cutmax = MAX(cutmax,2.0*maxrad_frozen[k]); + } + cutoff = cutmax; + } + } + else{ + cutoff = cutoff_global; + } + return cutoff; +} + + +/* ---------------------------------------------------------------------- + proc 0 writes to restart file + ------------------------------------------------------------------------- */ + +void PairGranular::write_restart(FILE *fp) +{ + int i,j; + fwrite(&normal,sizeof(int),1,fp); + fwrite(&damping,sizeof(int),1,fp); + fwrite(&tangential,sizeof(int),1,fp); + fwrite(&roll,sizeof(int),1,fp); + fwrite(&twist,sizeof(int),1,fp); + for (i = 1; i <= atom->ntypes; i++) { + for (j = i; j <= atom->ntypes; j++) { + fwrite(&setflag[i][j],sizeof(int),1,fp); + if (setflag[i][j]) { + fwrite(&normal_coeffs[i][j],sizeof(double),4,fp); + fwrite(&tangential_coeffs[i][j],sizeof(double),3,fp); + fwrite(&roll_coeffs[i][j],sizeof(double),3,fp); + fwrite(&twist_coeffs[i][j],sizeof(double),3,fp); + fwrite(&cut[i][j],sizeof(double),1,fp); + } + } + } +} + +/* ---------------------------------------------------------------------- + proc 0 reads from restart file, bcasts + ------------------------------------------------------------------------- */ + +void PairGranular::read_restart(FILE *fp) +{ + allocate(); + int i,j; + int me = comm->me; + if (me == 0){ + fread(&normal,sizeof(int),1,fp); + fread(&damping,sizeof(int),1,fp); + fread(&tangential,sizeof(int),1,fp); + fread(&roll,sizeof(int),1,fp); + fread(&twist,sizeof(int),1,fp); + } + MPI_Bcast(&normal,1,MPI_INT,0,world); + MPI_Bcast(&damping,1,MPI_INT,0,world); + MPI_Bcast(&tangential,1,MPI_INT,0,world); + MPI_Bcast(&roll,1,MPI_INT,0,world); + MPI_Bcast(&twist,1,MPI_INT,0,world); + for (i = 1; i <= atom->ntypes; i++) { + for (j = i; j <= atom->ntypes; j++) { + if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp); + MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world); + if (setflag[i][j]) { + if (me == 0) { + fread(&normal_coeffs[i][j],sizeof(double),4,fp); + fread(&tangential_coeffs[i][j],sizeof(double),3,fp); + fread(&roll_coeffs[i][j],sizeof(double),3,fp); + fread(&twist_coeffs[i][j],sizeof(double),3,fp); + fread(&cut[i][j],sizeof(double),1,fp); + } + MPI_Bcast(&normal_coeffs[i][j],4,MPI_DOUBLE,0,world); + MPI_Bcast(&tangential_coeffs[i][j],3,MPI_DOUBLE,0,world); + MPI_Bcast(&roll_coeffs[i][j],3,MPI_DOUBLE,0,world); + MPI_Bcast(&twist_coeffs[i][j],3,MPI_DOUBLE,0,world); + MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); + } + } + } +} + + +/* ---------------------------------------------------------------------- */ + +void PairGranular::reset_dt() +{ + dt = update->dt; +} + +/* ---------------------------------------------------------------------- */ + +double PairGranular::single(int i, int j, int itype, int jtype, + double rsq, double factor_coul, double factor_lj, double &fforce) +{ + double radi,radj,radsum; + double r,rinv,rsqinv,delx,dely,delz, nx, ny, nz, Reff; + double dR, dR2; + double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3,wr1,wr2,wr3; + double vtr1,vtr2,vtr3,vrel; + double mi,mj,meff,damp,ccel,tor1,tor2,tor3; + double relrot1,relrot2,relrot3,vrl1,vrl2,vrl3,vrlmag,vrlmaginv; + + double knfac, damp_normal; + double k_tangential, damp_tangential; + double Fne, Ft, Fdamp, Fntot, Fcrit, Fscrit, Frcrit; + double fs, fs1, fs2, fs3; + + //For JKR + double R2, coh, F_pulloff, delta_pulloff, dist_pulloff, a, a2, E; + double delta, t0, t1, t2, t3, t4, t5, t6; + double sqrt1, sqrt2, sqrt3, sqrt4; + + + //Rolling + double k_roll, damp_roll; + double roll1, roll2, roll3, torroll1, torroll2, torroll3; + double rollmag, rolldotn, scalefac; + double fr, fr1, fr2, fr3; + + //Twisting + double k_twist, damp_twist, mu_twist; + double signtwist, magtwist, magtortwist, Mtcrit; + double tortwist1, tortwist2, tortwist3; + + double shrmag,rsht; + int jnum; + int *ilist,*jlist,*numneigh,**firstneigh; + int *touch,**firsttouch; + double *history,*allhistory,**firsthistory; + + double *radius = atom->radius; + radi = radius[i]; + radj = radius[j]; + radsum = radi + radj; + Reff = radi*radj/(radi+radj); + + bool touchflag; + if (normal == JKR){ + R2 = Reff*Reff; + coh = normal_coeffs[itype][jtype][3]; + a = cbrt(9.0*M_PI*coh*R2/(4*E)); + delta_pulloff = a*a/Reff - 2*sqrt(M_PI*coh*a/E); + dist_pulloff = radsum+delta_pulloff; + touchflag = (rsq <= dist_pulloff*dist_pulloff); + } + else{ + touchflag = (rsq <= radsum*radsum); + } + + if (touchflag){ + fforce = 0.0; + for (int m = 0; m < single_extra; m++) svector[m] = 0.0; + return 0.0; + } + + double **x = atom->x; + delx = x[i][0] - x[j][0]; + dely = x[i][1] - x[j][1]; + delz = x[i][2] - x[j][2]; + r = sqrt(rsq); + rinv = 1.0/r; + + nx = delx*rinv; + ny = dely*rinv; + nz = delz*rinv; + + // relative translational velocity + + double **v = atom->v; + vr1 = v[i][0] - v[j][0]; + vr2 = v[i][1] - v[j][1]; + vr3 = v[i][2] - v[j][2]; + + // normal component + + vnnr = vr1*nx + vr2*ny + vr3*nz; + vn1 = nx*vnnr; + vn2 = ny*vnnr; + vn3 = nz*vnnr; + + double *rmass = atom->rmass; + int *mask = atom->mask; + mi = rmass[i]; + mj = rmass[j]; + if (fix_rigid) { + if (mass_rigid[i] > 0.0) mi = mass_rigid[i]; + if (mass_rigid[j] > 0.0) mj = mass_rigid[j]; + } + + meff = mi*mj / (mi+mj); + if (mask[i] & freeze_group_bit) meff = mj; + if (mask[j] & freeze_group_bit) meff = mi; + + delta = radsum - r; + dR = delta*Reff; + + // tangential component + + vt1 = vr1 - vn1; + vt2 = vr2 - vn2; + vt3 = vr3 - vn3; + + // relative rotational velocity + + double **omega = atom->omega; + wr1 = (radi*omega[i][0] + radj*omega[j][0]); + wr2 = (radi*omega[i][1] + radj*omega[j][1]); + wr3 = (radi*omega[i][2] + radj*omega[j][2]); + + // meff = effective mass of pair of particles + // if I or J part of rigid body, use body mass + // if I or J is frozen, meff is other particle + + int *type = atom->type; + + mi = rmass[i]; + mj = rmass[j]; + if (fix_rigid) { + // NOTE: ensure mass_rigid is current for owned+ghost atoms? + if (mass_rigid[i] > 0.0) mi = mass_rigid[i]; + if (mass_rigid[j] > 0.0) mj = mass_rigid[j]; + } + + meff = mi*mj / (mi+mj); + if (mask[i] & freeze_group_bit) meff = mj; + if (mask[j] & freeze_group_bit) meff = mi; + + delta = radsum - r; + dR = delta*Reff; + if (normal == JKR){ + dR2 = dR*dR; + t0 = coh*coh*R2*R2*E; + t1 = PI27SQ*t0; + t2 = 8*dR*dR2*E*E*E; + t3 = 4*dR2*E; + sqrt1 = MAX(0, t0*(t1+2*t2)); //In case of sqrt(0) < 0 due to precision issues + t4 = cbrt(t1+t2+THREEROOT3*M_PI*sqrt(sqrt1)); + t5 = t3/t4 + t4/E; + sqrt2 = MAX(0, 2*dR + t5); + t6 = sqrt(sqrt2); + sqrt3 = MAX(0, 4*dR - t5 + SIXROOT6*coh*M_PI*R2/(E*t6)); + a = INVROOT6*(t6 + sqrt(sqrt3)); + a2 = a*a; + knfac = FOURTHIRDS*E*a; + Fne = knfac*a2/Reff - TWOPI*a2*sqrt(4*coh*E/(M_PI*a)); + } + else{ + knfac = E; + Fne = knfac*delta; + if (normal != HOOKE) + a = sqrt(dR); + Fne *= a; + if (normal == DMT) + Fne -= 4*MY_PI*normal_coeffs[itype][jtype][3]*Reff; + } + + //Consider restricting Hooke to only have 'velocity' as an option for damping? + if (damping == VELOCITY){ + damp_normal = normal_coeffs[itype][jtype][1]; + } + else if (damping == VISCOELASTIC){ + if (normal == HOOKE) a = sqrt(dR); + damp_normal = normal_coeffs[itype][jtype][1]*a*meff; + } + else if (damping == TSUJI){ + damp_normal = normal_coeffs[itype][jtype][1]*sqrt(meff*knfac); + } + + Fdamp = -damp_normal*vnnr; + + Fntot = Fne + Fdamp; + + jnum = list->numneigh[i]; + jlist = list->firstneigh[i]; + + if (use_history){ + allhistory = fix_history->firstvalue[i]; + for (int jj = 0; jj < jnum; jj++) { + neighprev++; + if (neighprev >= jnum) neighprev = 0; + if (jlist[neighprev] == j) break; + } + history = &allhistory[size_history*neighprev]; + } + + //**************************************** + //Tangential force, including history effects + //**************************************** + + // tangential component + vt1 = vr1 - vn1; + vt2 = vr2 - vn2; + vt3 = vr3 - vn3; + + // relative rotational velocity + wr1 = (radi*omega[i][0] + radj*omega[j][0]); + wr2 = (radi*omega[i][1] + radj*omega[j][1]); + wr3 = (radi*omega[i][2] + radj*omega[j][2]); + + // relative tangential velocities + vtr1 = vt1 - (nz*wr2-ny*wr3); + vtr2 = vt2 - (nx*wr3-nz*wr1); + vtr3 = vt3 - (ny*wr1-nx*wr2); + vrel = vtr1*vtr1 + vtr2*vtr2 + vtr3*vtr3; + vrel = sqrt(vrel); + + Fcrit = fabs(Fne); + if (normal == JKR){ + F_pulloff = 3*M_PI*coh*Reff; + Fcrit = fabs(Fne + 2*F_pulloff); + } + + //------------------------------ + //Tangential forces + //------------------------------ + k_tangential = tangential_coeffs[itype][jtype][0]; + if (normal != HOOKE){ + k_tangential *= a; + } + damp_tangential = tangential_coeffs[itype][jtype][1]*damp_normal; + + if (tangential_history){ + shrmag = sqrt(history[0]*history[0] + history[1]*history[1] + + history[2]*history[2]); + + // tangential forces = history + tangential velocity damping + fs1 = -k_tangential*history[0] - damp_tangential*vtr1; + fs2 = -k_tangential*history[1] - damp_tangential*vtr2; + fs3 = -k_tangential*history[2] - damp_tangential*vtr3; + + // rescale frictional displacements and forces if needed + Fscrit = tangential_coeffs[itype][jtype][2] * Fcrit; + fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); + if (fs > Fscrit) { + if (shrmag != 0.0) { + history[0] = -1.0/k_tangential*(Fscrit*fs1/fs + damp_tangential*vtr1); + history[1] = -1.0/k_tangential*(Fscrit*fs2/fs + damp_tangential*vtr2); + history[2] = -1.0/k_tangential*(Fscrit*fs3/fs + damp_tangential*vtr3); + fs1 *= Fscrit/fs; + fs2 *= Fscrit/fs; + fs3 *= Fscrit/fs; + } else fs1 = fs2 = fs3 = 0.0; + } + } + else{ //Classic pair gran/hooke (no history) + fs = meff*damp_tangential*vrel; + if (vrel != 0.0) Ft = MIN(Fne,fs) / vrel; + else Ft = 0.0; + fs1 = -Ft*vtr1; + fs2 = -Ft*vtr2; + fs3 = -Ft*vtr3; + } + + //**************************************** + // Rolling resistance + //**************************************** + + if (roll != ROLL_NONE){ + relrot1 = omega[i][0] - omega[j][0]; + relrot2 = omega[i][1] - omega[j][1]; + relrot3 = omega[i][2] - omega[j][2]; + + // rolling velocity, see eq. 31 of Wang et al, Particuology v 23, p 49 (2015) + // This is different from the Marshall papers, which use the Bagi/Kuhn formulation + // for rolling velocity (see Wang et al for why the latter is wrong) + vrl1 = Reff*(relrot2*nz - relrot3*ny); //- 0.5*((radj-radi)/radsum)*vtr1; + vrl2 = Reff*(relrot3*nx - relrot1*nz); //- 0.5*((radj-radi)/radsum)*vtr2; + vrl3 = Reff*(relrot1*ny - relrot2*nx); //- 0.5*((radj-radi)/radsum)*vtr3; + vrlmag = sqrt(vrl1*vrl1+vrl2*vrl2+vrl3*vrl3); + if (vrlmag != 0.0) vrlmaginv = 1.0/vrlmag; + else vrlmaginv = 0.0; + + if (roll_history){ + int rhist0 = roll_history_index; + int rhist1 = rhist0 + 1; + int rhist2 = rhist1 + 1; + + // Rolling displacement + rollmag = sqrt(history[rhist0]*history[rhist0] + + history[rhist1]*history[rhist1] + + history[rhist2]*history[rhist2]); + + rolldotn = history[rhist0]*nx + history[rhist1]*ny + history[rhist2]*nz; + + k_roll = roll_coeffs[itype][jtype][0]; + damp_roll = roll_coeffs[itype][jtype][1]; + fr1 = -k_roll*history[rhist0] - damp_roll*vrl1; + fr2 = -k_roll*history[rhist1] - damp_roll*vrl2; + fr3 = -k_roll*history[rhist2] - damp_roll*vrl3; + + // rescale frictional displacements and forces if needed + Frcrit = roll_coeffs[itype][jtype][2] * Fcrit; + + fr = sqrt(fr1*fr1 + fr2*fr2 + fr3*fr3); + if (fr > Frcrit) { + if (rollmag != 0.0) { + history[rhist0] = -1.0/k_roll*(Frcrit*fr1/fr + damp_roll*vrl1); + history[rhist1] = -1.0/k_roll*(Frcrit*fr2/fr + damp_roll*vrl2); + history[rhist2] = -1.0/k_roll*(Frcrit*fr3/fr + damp_roll*vrl3); + fr1 *= Frcrit/fr; + fr2 *= Frcrit/fr; + fr3 *= Frcrit/fr; + } else fr1 = fr2 = fr3 = 0.0; + } + } + else{ // + fr = meff*roll_coeffs[itype][jtype][1]*vrlmag; + if (vrlmag != 0.0) fr = MIN(Fne, fr) / vrlmag; + else fr = 0.0; + fr1 = -fr*vrl1; + fr2 = -fr*vrl2; + fr3 = -fr*vrl3; + } + } + + //**************************************** + // Twisting torque, including history effects + //**************************************** + if (twist != TWIST_NONE){ + magtwist = relrot1*nx + relrot2*ny + relrot3*nz; //Omega_T (eq 29 of Marshall) + if (twist == TWIST_MARSHALL){ + k_twist = 0.5*k_tangential*a*a;; //eq 32 + damp_twist = 0.5*damp_tangential*a*a; + mu_twist = TWOTHIRDS*a; + } + else{ + k_twist = twist_coeffs[itype][jtype][0]; + damp_twist = twist_coeffs[itype][jtype][1]; + mu_twist = twist_coeffs[itype][jtype][2]; + } + if (twist_history){ + magtortwist = -k_twist*history[twist_history_index] - damp_twist*magtwist;//M_t torque (eq 30) + signtwist = (magtwist > 0) - (magtwist < 0); + Mtcrit = TWOTHIRDS*a*Fscrit;//critical torque (eq 44) + if (fabs(magtortwist) > Mtcrit) { + history[twist_history_index] = 1.0/k_twist*(Mtcrit*signtwist - damp_twist*magtwist); + magtortwist = -Mtcrit * signtwist; //eq 34 + } + } + else{ + if (magtwist > 0) magtortwist = -damp_twist*magtwist; + else magtortwist = 0; + } + } + + // set single_extra quantities + + svector[0] = fs1; + svector[1] = fs2; + svector[2] = fs3; + svector[3] = fs; + svector[4] = fr1; + svector[5] = fr2; + svector[6] = fr3; + svector[7] = fr; + svector[8] = magtortwist; + return 0.0; +} + +/* ---------------------------------------------------------------------- */ + +int PairGranular::pack_forward_comm(int n, int *list, double *buf, + int pbc_flag, int *pbc) +{ + int i,j,m; + + m = 0; + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = mass_rigid[j]; + } + return m; +} + +/* ---------------------------------------------------------------------- */ + +void PairGranular::unpack_forward_comm(int n, int first, double *buf) +{ + int i,m,last; + + m = 0; + last = first + n; + for (i = first; i < last; i++) + mass_rigid[i] = buf[m++]; +} + +/* ---------------------------------------------------------------------- + memory usage of local atom-based arrays + ------------------------------------------------------------------------- */ + +double PairGranular::memory_usage() +{ + double bytes = nmax * sizeof(double); + return bytes; +} + +/* ---------------------------------------------------------------------- + mixing of Young's modulus (E) +------------------------------------------------------------------------- */ + +double PairGranular::mix_stiffnessE(double Eii, double Ejj, double Gii, double Gjj) +{ + double poisii = Eii/(2.0*Gii) - 1.0; + double poisjj = Ejj/(2.0*Gjj) - 1.0; + return 1/((1-poisii*poisjj)/Eii+(1-poisjj*poisjj)/Ejj); +} + +/* ---------------------------------------------------------------------- + mixing of shear modulus (G) + ------------------------------------------------------------------------- */ + +double PairGranular::mix_stiffnessG(double Eii, double Ejj, double Gii, double Gjj) +{ + double poisii = Eii/(2.0*Gii) - 1.0; + double poisjj = Ejj/(2.0*Gjj) - 1.0; + return 1/((2.0 -poisjj)/Gii+(2.0-poisjj)/Gjj); +} + +/* ---------------------------------------------------------------------- + mixing of everything else +------------------------------------------------------------------------- */ + +double PairGranular::mix_geom(double valii, double valjj) +{ + return sqrt(valii*valjj); +} + + +/* ---------------------------------------------------------------------- + Compute pull-off distance (beyond contact) for a given radius and atom type +------------------------------------------------------------------------- */ + +double PairGranular::pulloff_distance(double radius, int itype) +{ + double E, coh, a, delta_pulloff; + coh = normal_coeffs[itype][itype][3]; + E = mix_stiffnessE(normal_coeffs[itype][itype][0], normal_coeffs[itype][itype][0], + normal_coeffs[itype][itype][2], normal_coeffs[itype][itype][2]); + a = cbrt(9*M_PI*coh*radius*radius/(4*E)); + return a*a/radius - 2*sqrt(M_PI*coh*a/E); +} + diff --git a/src/pair_granular.h b/src/pair_granular.h new file mode 100644 index 0000000000..f39f31e4cb --- /dev/null +++ b/src/pair_granular.h @@ -0,0 +1,120 @@ +/* ---------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain 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(granular,PairGranular) + +#else + +#ifndef LMP_PAIR_GRANULAR_H +#define LMP_PAIR_GRANULAR_H + +#include "pair.h" + +namespace LAMMPS_NS { + +class PairGranular : public Pair { +public: + PairGranular(class LAMMPS *); + virtual ~PairGranular(); + + void compute(int, int); + // comment next line to turn off templating +#define TEMPLATED_PAIR_GRANULAR +#ifdef TEMPLATED_PAIR_GRANULAR + template < int Tp_normal, int Tp_damping, int Tp_tangential, + int Tp_roll, int Tp_twist> + void compute_templated(int, int); +#else + void compute_untemplated(int, int, int, int, int, + int, int); +#endif + + virtual void settings(int, char **); + virtual void coeff(int, char **); + void init_style(); + double init_one(int, int); + void write_restart(FILE *); + void read_restart(FILE *); + void reset_dt(); + virtual double single(int, int, int, int, double, double, double, double &); + int pack_forward_comm(int, int *, double *, int, int *); + void unpack_forward_comm(int, int, double *); + double memory_usage(); + + protected: + double cut_global; + double dt; + int freeze_group_bit; + int use_history; + + int neighprev; + double *onerad_dynamic,*onerad_frozen; + double *maxrad_dynamic,*maxrad_frozen; + double **cut; + + class FixNeighHistory *fix_history; + + // storage of rigid body masses for use in granular interactions + + class Fix *fix_rigid; // ptr to rigid body fix, NULL if none + double *mass_rigid; // rigid mass for owned+ghost atoms + int nmax; // allocated size of mass_rigid + + virtual void allocate(); + +private: + int size_history; + + //Models + int normal, damping, tangential, roll, twist; + + //History flags + int tangential_history, roll_history, twist_history; + + //Indices of history entries + int tangential_history_index, roll_history_index, twist_history_index; + + //Flags for whether model choices have been set + int normal_set, tangential_set, damping_set, roll_set, twist_set; + + //Per-type coefficients, set in pair coeff command + double ***normal_coeffs; + double ***tangential_coeffs; + double ***roll_coeffs; + double ***twist_coeffs; + + //Optional user-specified global cutoff + double cutoff_global; + + double mix_stiffnessE(double Eii, double Ejj, double Gii, double Gjj); + double mix_stiffnessG(double Eii, double Ejj, double Gii, double Gjj); + double mix_geom(double valii, double valjj); + double pulloff_distance(double radius, int itype); +}; + +} + +#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. + + */ From 6ff1557af8c03becc5615ccebcd41334a0cf082b Mon Sep 17 00:00:00 2001 From: dsbolin Date: Tue, 12 Feb 2019 07:42:26 -0700 Subject: [PATCH 19/44] More progress on doc page --- doc/src/pair_granular.txt | 101 +++++++++++++++++++++++++------------- 1 file changed, 68 insertions(+), 33 deletions(-) diff --git a/doc/src/pair_granular.txt b/doc/src/pair_granular.txt index 8bf4f20d5d..d6b18217d8 100644 --- a/doc/src/pair_granular.txt +++ b/doc/src/pair_granular.txt @@ -14,7 +14,6 @@ :line pair_style granular command :h3 -pair_style granular/multi command :h3 [Syntax:] @@ -33,7 +32,7 @@ pair_style granular pair_coeff 1 1 hertz 1000.0 50.0 tangential mindlin 800.0 50.0 0.5 rolling sds 500.0 200.0 0.5 twisting marshall pair_coeff 2 2 hertz 200.0 20.0 tangential mindlin 300.0 50.0 0.1 rolling sds 200.0 100.0 0.1 twisting marshall :pre -pair_style granular/multi +pair_style granular pair_coeff 1 1 hertz 1000.0 50.0 tangential mindlin 800.0 50.0 0.5 rolling sds 500.0 200.0 0.5 twisting marshall pair_coeff 2 2 dmt 1000.0 50.0 800.0 10.0 tangential mindlin 800.0 50.0 0.1 roll sds 500.0 200.0 0.1 twisting marshall pair_coeff 1 2 dmt 1000.0 50.0 800.0 10.0 tangential mindlin 800.0 50.0 0.1 roll sds 500.0 200.0 0.1 twisting marshall :pre @@ -44,24 +43,17 @@ pair_coeff 1 2 dmt 1000.0 50.0 800.0 10.0 tangential mindlin 800.0 50.0 0.1 roll The {granular} styles support a variety of options for the normal, tangential, rolling and twisting forces resulting from contact between two granular particles. This expands on the options offered by the "pair gran/*"_pair_gran.html options. The total computed forces and torques depend on the combination -of choices for these various modes of motion. +of models selected for these various modes of motion. All model options and parameters are entered in the "pair_coeff"_pair_coeff.html command, as described below. Unlike e.g. "pair gran/hooke"_pair_gran.html, coefficient values are not global, but can be set to different values for various combinations of particle types, as determined by the "pair_coeff"_pair_coeff.html command. -For {pair_style granular}, coefficients can vary between particle types, but model choices -cannot. For instance, in the first -example above, the stiffness, damping, and tangential friction are different for -type 1 - type 1 and type 2 - type 2 interactions, but -both 1-1 and 2-2 interactions must have the same model form, hence all keywords are -identical between the two types. Cross-coefficients -for 1-2 interactions for the case of the {hertz} model above are set via simple -geometric mixing rules. The {granular/multi} -style removes this restriction at a small cost in computational efficiency, so that different particle types -can potentially interact via different model forms. As shown in the second example, -1-1 interactions are based on a Hertzian contact model and 2-2 interactions are based on a {dmt} model (see below). -In the case that 1-1 and 2-2 interactions have different model forms, mixing of coefficients cannot be -determined, so 1-2 interactions must be explicitly defined via the pair coeff command, otherwise an error results. +For {pair_style granular}, coefficients as well as model options can vary between particle types. +As shown in the second example, +type 1- type 1 interactions are based on a Hertzian normal contact model and 2-2 interactions are based on a {dmt} model (see below). +In that example, 1-1 and 2-2 interactions have different model forms, in which case +mixing of coefficients cannot be determined, so 1-2 interactions must be explicitly defined via the +pair coeff command, otherwise an error would result. :line @@ -70,12 +62,13 @@ for normal contact models and their required arguments are: {hooke} : \(k_n\), damping {hertz} : \(k_n\), damping -{hertz/material} : E, damping, G -{dmt} : E, damping, G, cohesion -{jkr} : E, damping, G, cohesion :ol +{hertz/material} : E, damping, \(\nu\) +{dmt} : E, damping, \(\nu\), cohesion +{jkr} : E, damping, \(\nu\), cohesion :ol -Here, \(k_n\) is spring stiffness, damping is a damping constant or a coefficient of restitution, depending on -the choice of damping model (see below), E and G are Young's modulus and shear modulus, in units of pressure, +Here, \(k_n\) is spring stiffness (with units that depend on model choice, see below); +damping is a damping constant or a coefficient of restitution, depending on +the choice of damping model; E is Young's modulus in units of force/length^2; \(\nu\) is Poisson's ratio and cohesion is a surface energy density, in units of energy/length^2. For the {hooke} model, the normal (elastic) component of force between two particles {i} and {j} is given by: @@ -88,6 +81,8 @@ Where \(\delta = R_i + R_j - \|\mathbf\{r\}_\{ij\}\|\) is the particle overlap, \(\mathbf\{r\}_\{ij\} = \mathbf\{r\}_j - \mathbf\{r\}_i\) is the vector separating the two particle centers and \(\mathbf\{n\} = \frac\{\mathbf\{r\}_\{ij\}\}\{\|\mathbf\{r\}_\{ij\}\|\}\). +Therefore, for {hooke}, the units of the spring constant \(k_n\) are {force}/{distance}, +or equivalently {mass}/{time^2}. For the {hertz} model, the normal component of force is given by: \begin\{equation\} @@ -95,6 +90,8 @@ For the {hertz} model, the normal component of force is given by: \end\{equation\} Here, \(R_\{eff\} = \frac\{R_i R_j\}\{R_i + R_j\}\) is the effective radius, denoted for simplicity as {R} from here on. +For {hertz}, the units of the spring constant \(k_n\) are {force}/{distance}^2, or equivalently +{pressure}. For the {hertz/material} model, the force is given by: \begin\{equation\} @@ -102,9 +99,9 @@ For the {hertz/material} model, the force is given by: \end\{equation\} Here, \(E_\{eff\} = E = \left(\frac\{1-\nu_i^2\}\{E_i\} + \frac\{1-\nu_j^2\}\{E_j\}\right)^\{-1\}\) -is the effectve Young's modulus, -with \(\nu_i, \nu_j \) the Poisson ratios of the particles, which are related to the -input shear and Young's moduli by \(\nu_i = E_i/2G_i - 1\). Thus, if the elastic and shear moduli of the +is the effective Young's modulus, +with \(\nu_i, \nu_j \) the Poisson ratios of the particles of types {i} and {j}. Note that + if the elastic and shear moduli of the two particles are the same, the {hertz/material} model is equivalent to the {hertz} model with \(k_N = 4/3 E_\{eff\}\) @@ -127,12 +124,12 @@ Here, {a} is the radius of the contact zone, related to the overlap \(\delta\) a LAMMPS internally inverts the equation above to solve for {a} in terms of \(\delta\), then solves for the force in the previous equation. Additionally, note that the JKR model allows for a tensile force beyond -contact (i.e. for \(\delta < 0\)), up to a maximum tensile force of \(-3\pi\gamma R\) (also known as +contact (i.e. for \(\delta < 0\)), up to a maximum of \(3\pi\gamma R\) (also known as the 'pull-off' force). Note that this is a hysteretic effect, where particles that are not contacting initially will not experience force until they come into contact \(\delta \geq 0\); as they move apart -and (\(\delta < 0\)), they experience a tensile force up to \(-3\pi\gamma R\), -at which point they will lose contact. +and (\(\delta < 0\)), they experience a tensile force up to \(3\pi\gamma R\), +at which point they lose contact. In addition to the above options, the normal force is augmented by a damping term. The optional {damping} keyword to the {pair_coeff} command followed by the model choice determines the form of the damping. @@ -167,7 +164,19 @@ Here, \(m_\{eff\} = m_i m_j/(m_i + m_j)\) is the effective mass, {a} is the cont for all models except {jkr}, for which it is given implicitly according to \(delta = a^2/R - 2\sqrt\{\pi \gamma a/E\}\). In this case, \(\gamma_N\) is the damping coefficient, in units of 1/({time}*{distance}). -The {tsuji} model is based on the work of "(Tsuji et al)"_#Tsuji1992. Here, the +The {tsuji} model is based on the work of "(Tsuji et al)"_#Tsuji1992. Here, the +damping term is given by: +\begin\{equation\} +F_\{N,damp\} = -\alpha (m_\{eff\}k_N)^\{l/2\} \mathbf\{v\}_\{N,rel\} +\end\{equation\} + +For normal contact models based on material parameters, \(k_N = 4/3Ea\). +The parameter \(\alpha\) is related to the restitution coefficient {e} according to: +\begin{equation} +\alpha = 1.2728-4.2783e+11.087e^2-22.348e^3+27.467e^4-18.022e^5+4.8218e^6 +\end{equation} + +For further details, see "(Tsuji et al)"_#Tsuji1992. :line @@ -175,13 +184,13 @@ Following the normal contact model settings, the {pair_coeff} command requires s of the tangential contact model. The required keyword {tangential} is expected, followed by the model choice and associated parameters. Currently supported tangential model choices and their expected parameters are as follows: -{nohistory} : \(\gamma_t\), \(\mu_s\) -{history} : \(k_t\), \(\gamma_t\), \(\mu_s\) :ol +{linear_nohistory} : \(\gamma_t\), \(\mu_s\) +{linear_history} : \(k_t\), \(\gamma_t\), \(\mu_s\) :ol Here, \(\gamma_t\) is the tangential damping coefficient, \(\mu_s\) is the tangential (or sliding) friction -coefficient, and \(k_t\) is the tangential stiffness. +coefficient, and \(k_t\) is the tangential stiffness coefficient. -For {nohistory}, a simple velocity-dependent Coulomb friction criterion is used, which reproduces the behavior +For {linear_nohistory}, a simple velocity-dependent Coulomb friction criterion is used, which reproduces the behavior of the {pair gran/hooke} style. The tangential force (\mathbf\{F\}_t\) is given by: \begin\{equation\} @@ -190,7 +199,33 @@ of the {pair gran/hooke} style. The tangential force (\mathbf\{F\}_t\) is given Where \(\|\mathbf\{F\}_n\) is the magnitude of the normal force, \(\mathbf\{v\}_\{t, rel\} = \mathbf\{v\}_\{t\} - (R_i\Omega_i + R_j\Omega_j) \times \mathbf\{n\}\) is the relative tangential -velocity at the point of contact, \(\mathbf\{v\}_\{t\} = \mathbf\{v\}_n - \) +velocity at the point of contact, \(\mathbf\{v\}_\{t\} = \mathbf\{v\}_R - \mathbf\{v\}_R\cdot\mathbf\{n\}\), +\(\mathbf\{v\}_R = \mathbf\{v\}_i - \mathbf\{v\}_j. + +For {linear_history}, the total tangential displacement \(\mathbf\{\xi\}\) is accumulated during the entire +duration of the contact: + +\begin\{equation\} +\mathbf\{\xi\} = \int_\{t0\}^t \mathbf\{v\}_\{t,rel\}(\tau) \mathrm\{d\}\tau +\end\{equation\} + +The tangential displacement must in the frame of reference of the contacting pair of particles, + +\begin\{equation\} +\mathbf\{\xi\} = \mathbf\{\xi'\} - \mathbf\{n\}(\mathbf\{n\} \cdot \mathbf\{\xi'\}) +\end\{equation\} + +\noindent Since the goal here is a `rotation', the equation above should be accompanied by a rescaling, so that at each step, +the displacement is first rotated into the current frame of reference $\mathbf\{\xi\}$, then updated: + +\begin\{equation\} +\mathbf\{\xi\} = \left(\mathbf\{\xi'\} - (\mathbf\{n\} \cdot \mathbf\{\xi'\})\mathbf\{n\}\right) \frac\{\|\mathbf\{\xi'\}\|\}\{\|\mathbf\{\xi'\}\| - \mathbf\{n\}\cdot\mathbf\{\xi'\}\} +\label\{eq:rotate_displacements\} +\end\{equation\} + + +a simple velocity-dependent Coulomb friction criterion is used, which reproduces the behavior +of the {pair gran/hooke} style. The tangential force (\mathbf\{F\}_t\) is given by: :link(Brill1996) From d8e8a0d2d24fcbbf26b5b60fb876ea3d85ba023b Mon Sep 17 00:00:00 2001 From: "Dan S. Bolintineanu" Date: Mon, 18 Feb 2019 09:58:34 -0700 Subject: [PATCH 20/44] More changes to pair granular: - tangential damping now set by scaling the normal damping - some fixes to the twisting coefficients for the Marshall twist model - progress (completion?) of doc page --- doc/src/pair_granular.txt | 529 ++++++++++++++++++++++++++++----- src/GRANULAR/pair_granular.cpp | 364 +++++++++++------------ 2 files changed, 619 insertions(+), 274 deletions(-) diff --git a/doc/src/pair_granular.txt b/doc/src/pair_granular.txt index d6b18217d8..ff2ee94be0 100644 --- a/doc/src/pair_granular.txt +++ b/doc/src/pair_granular.txt @@ -17,69 +17,79 @@ pair_style granular command :h3 [Syntax:] -pair_style style cutoff :pre +pair_style granular cutoff :pre -style = {granular} or {granular/multi} :ulb,l cutoff = global cutoff (optional). See discussion below. :l :ule [Examples:] pair_style granular -pair_coeff * * hertz 1000.0 50.0 tangential mindlin 800.0 50.0 0.4 :pre +pair_coeff * * hooke 1000.0 50.0 tangential linear_nohistory 1.0 0.4 :pre pair_style granular -pair_coeff 1 1 hertz 1000.0 50.0 tangential mindlin 800.0 50.0 0.5 rolling sds 500.0 200.0 0.5 twisting marshall -pair_coeff 2 2 hertz 200.0 20.0 tangential mindlin 300.0 50.0 0.1 rolling sds 200.0 100.0 0.1 twisting marshall :pre +pair_coeff * * hertz 1000.0 50.0 tangential linear_history 800.0 1.0 0.4 :pre pair_style granular -pair_coeff 1 1 hertz 1000.0 50.0 tangential mindlin 800.0 50.0 0.5 rolling sds 500.0 200.0 0.5 twisting marshall -pair_coeff 2 2 dmt 1000.0 50.0 800.0 10.0 tangential mindlin 800.0 50.0 0.1 roll sds 500.0 200.0 0.1 twisting marshall -pair_coeff 1 2 dmt 1000.0 50.0 800.0 10.0 tangential mindlin 800.0 50.0 0.1 roll sds 500.0 200.0 0.1 twisting marshall :pre +pair_coeff * * hertz 1000.0 0.3 tangential linear_history 800.0 1.0 0.4 damping tsuji :pre +pair_style granular +pair_coeff 1 1 jkr 1000.0 50.0 tangential linear_history 800.0 1.0 0.5 rolling sds 500.0 200.0 0.5 twisting marshall +pair_coeff 2 2 hertz 200.0 20.0 tangential linear_history 300.0 1.0 0.1 rolling sds 200.0 100.0 0.1 twisting marshall :pre + +pair_style granular +pair_coeff 1 1 hertz 1000.0 50.0 tangential linear_history 800.0 0.5 0.5 rolling sds 500.0 200.0 0.5 twisting marshall +pair_coeff 2 2 dmt 1000.0 50.0 0.3 10.0 tangential linear_history 800.0 0.5 0.1 roll sds 500.0 200.0 0.1 twisting marshall +pair_coeff 1 2 dmt 1000.0 50.0 0.3 10.0 tangential linear_history 800.0 0.5 0.1 roll sds 500.0 200.0 0.1 twisting marshall :pre [Description:] The {granular} styles support a variety of options for the normal, tangential, rolling and twisting forces resulting from contact between two granular particles. This expands on the options offered -by the "pair gran/*"_pair_gran.html options. The total computed forces and torques depend on the combination -of models selected for these various modes of motion. +by the "pair gran/*"_pair_gran.html pair styles. The total computed forces and torques are the +sum of various models selected for the normal, tangential, rolling and twisting modes of motion. -All model options and parameters are entered in the "pair_coeff"_pair_coeff.html command, as described below. +All model choices and parameters are entered in the "pair_coeff"_pair_coeff.html command, as described below. Unlike e.g. "pair gran/hooke"_pair_gran.html, coefficient values are not global, but can be set to different values for -various combinations of particle types, as determined by the "pair_coeff"_pair_coeff.html command. -For {pair_style granular}, coefficients as well as model options can vary between particle types. -As shown in the second example, -type 1- type 1 interactions are based on a Hertzian normal contact model and 2-2 interactions are based on a {dmt} model (see below). +different combinations of particle types, as determined by the "pair_coeff"_pair_coeff.html command. +If the contact model choice is the same for two particle types, the mixing for the cross-coefficients can be carried out +automatically. This is shown in the second example, where model choices are the same for type 1 - type 1 as for type 2 - type2 +interactions, but coefficients are different. In this case, the coefficients for type 2 - type interactions can be +determined from mixing rules discussed below. +For additional flexibility, coefficients as well as model forms can vary between particle types, +as shown in the third example: +type 1- type 1 interactions are based on a Hertzian normal contact model and 2-2 interactions are based on a DMT cohesive model (see below). In that example, 1-1 and 2-2 interactions have different model forms, in which case mixing of coefficients cannot be determined, so 1-2 interactions must be explicitly defined via the -pair coeff command, otherwise an error would result. +{pair_coeff 1 2} command, otherwise an error would result. :line The first required keyword for the {pair_coeff} command is the normal contact model. Currently supported options for normal contact models and their required arguments are: -{hooke} : \(k_n\), damping -{hertz} : \(k_n\), damping -{hertz/material} : E, damping, \(\nu\) -{dmt} : E, damping, \(\nu\), cohesion -{jkr} : E, damping, \(\nu\), cohesion :ol +{hooke} : \(k_n\), \(\eta_\{n0\}\) (or \(e\)) +{hertz} : \(k_n\), \(\eta_\{n0\}\) (or \(e\)) +{hertz/material} : E, \(\eta_\{n0\}\) (or \(e\)), \(\nu\) +{dmt} : E, \(\eta_\{n0\}\) (or \(e\)), \(\nu\), \(\gamma\) +{jkr} : E, \(\eta_\{n0\}\) (or \(e\)), \(\nu\), \(\gamma\) :ol Here, \(k_n\) is spring stiffness (with units that depend on model choice, see below); -damping is a damping constant or a coefficient of restitution, depending on -the choice of damping model; E is Young's modulus in units of force/length^2; \(\nu\) is Poisson's ratio -and cohesion is a surface energy density, in units of energy/length^2. +\(\eta_\{n0\}\) is a damping prefactor (or, in its place a coefficient of restitution +\(e\), depending on the choice of damping mode, see below); E is Young's modulus +in units of {force}/{length}^2, i.e. {pressure}; \(\nu\) is Poisson's ratio +and \(\gamma\) is a surface energy density, in units of {energy}/{length}^2. -For the {hooke} model, the normal (elastic) component of force between two particles {i} and {j} is given by: +For the {hooke} model, the normal, elastic component of force acting on particle {i} due to +contact with particle {j} is given by: \begin\{equation\} \mathbf\{F\}_\{ne, Hooke\} = k_N \delta_\{ij\} \mathbf\{n\} \end\{equation\} Where \(\delta = R_i + R_j - \|\mathbf\{r\}_\{ij\}\|\) is the particle overlap, \(R_i, R_j\) are the particle radii, -\(\mathbf\{r\}_\{ij\} = \mathbf\{r\}_j - \mathbf\{r\}_i\) is the vector separating the -two particle centers +\(\mathbf\{r\}_\{ij\} = \mathbf\{r\}_i - \mathbf\{r\}_j\) is the vector separating the +two particle centers (note the i-j ordering so that \(F_\{ne\}\) is positive for repulsion), and \(\mathbf\{n\} = \frac\{\mathbf\{r\}_\{ij\}\}\{\|\mathbf\{r\}_\{ij\}\|\}\). Therefore, for {hooke}, the units of the spring constant \(k_n\) are {force}/{distance}, or equivalently {mass}/{time^2}. @@ -90,7 +100,7 @@ For the {hertz} model, the normal component of force is given by: \end\{equation\} Here, \(R_\{eff\} = \frac\{R_i R_j\}\{R_i + R_j\}\) is the effective radius, denoted for simplicity as {R} from here on. -For {hertz}, the units of the spring constant \(k_n\) are {force}/{distance}^2, or equivalently +For {hertz}, the units of the spring constant \(k_n\) are {force}/{length}^2, or equivalently {pressure}. For the {hertz/material} model, the force is given by: @@ -101,17 +111,17 @@ For the {hertz/material} model, the force is given by: Here, \(E_\{eff\} = E = \left(\frac\{1-\nu_i^2\}\{E_i\} + \frac\{1-\nu_j^2\}\{E_j\}\right)^\{-1\}\) is the effective Young's modulus, with \(\nu_i, \nu_j \) the Poisson ratios of the particles of types {i} and {j}. Note that - if the elastic and shear moduli of the +if the elastic and shear moduli of the two particles are the same, the {hertz/material} model is equivalent to the {hertz} model with \(k_N = 4/3 E_\{eff\}\) -The {dmt} model corresponds to the Derjaguin-Muller-Toporov model, +The {dmt} model corresponds to the "(Derjaguin-Muller-Toporov)"_#DMT1975 cohesive model, where the force is simply Hertz with an additional attractive cohesion term: \begin\{equation\} \mathbf\{F\}_\{ne, dmt\} = \left(\frac\{4\}\{3\} E R^\{1/2\}\delta_\{ij\}^\{3/2\} - 4\pi\gamma R\right)\mathbf\{n\} \end\{equation\} -The {jkr} model is the Johnson-Kendall-Roberts model, where the force is computed as: +The {jkr} model is the "(Johnson-Kendall-Roberts)"_#JKR1971 model, where the force is computed as: \begin\{equation\} \label\{eq:force_jkr\} \mathbf\{F\}_\{ne, jkr\} = \left(\frac\{4Ea^3\}\{3R\} - 2\pi a^2\sqrt\{\frac\{4\gamma E\}\{\pi a\}\}\right)\mathbf\{n\} @@ -131,11 +141,25 @@ will not experience force until they come into contact \(\delta \geq 0\); as the and (\(\delta < 0\)), they experience a tensile force up to \(3\pi\gamma R\), at which point they lose contact. -In addition to the above options, the normal force is augmented by a damping term. The optional -{damping} keyword to the {pair_coeff} command followed by the model choice determines the form of the damping. -The damping coefficient that was specified for the normal model -settings is used in computing the damping term, as described below. Note this damping parameter -may be interpreted differently depending on the model choice. +:line + +In addition, the normal force is augmented by a damping term of the following +general form: + +\begin\{equation\} +\mathbf\{F\}_\{n,damp\} = -\eta_n \mathbf\{v\}_\{n,rel\} +\end\{equation\} + +Here, \(\mathbf\{v\}_\{n,rel\} = (\mathbf\{v\}_j - \mathbf\{v\}_i) \cdot \mathbf\{n\}\) +is the component of relative velocity along \(\mathbf\{n\}\). + +The optional {damping} keyword to the {pair_coeff} command followed by a keyword +determines the model form of the damping factor \(\eta_n\), and the interpretation +of the \(\eta_\{n0\}\) or \(e\) coefficients specified as part of the normal contact +model settings. The {damping} keyword and corresponding +model form selection may be appended anywhere in the {pair coeff} command. +Note that the choice of damping model affects both the +normal and tangential damping (and depending on other settings, potentially also the twisting damping). The options for the damping model currently supported are: {velocity} @@ -144,91 +168,414 @@ The options for the damping model currently supported are: If the {damping} keyword is not specified, the {viscoelastic} model is used by default. -For {damping velocity}, the normal damping is simply proportional to the velocity: +For {damping velocity}, the normal damping is simply equal to the user-specified damping +coefficient in the {normal} model: + \begin\{equation\} -F_\{N,damp\} = -\gamma_N\mathbf\{v\}_\{N,rel\} +\eta_n = \eta_\{n0\}\ \end\{equation\} -Here, \(\gamma_N\) is the damping coefficient, in units of {mass}/{time}, -\(\mathbf\{v\}_\{N,rel\} = (\mathbf\{v\}_i - \mathbf\{v\}_j) \cdot \mathbf\{n\}\) -is the component of relative velocity along the direction of the vector \(\mathbf\{n\}\) that connects the centers of -particles {i} and {j}. +Here, \(\gamma_n\) is the damping coefficient specified for the normal contact model, in units of {mass}/{time}, The {damping viscoelastic} model is based on the viscoelastic treatment of "(Brilliantov et al)"_#Brill1996, where the normal damping is given by: \begin\{equation\} -F_\{N,damp\} = -\gamma_N a m_\{eff\} \mathbf\{v\}_\{N,rel\} +\eta_n = \eta_\{n0\}\ a m_\{eff\} \end\{equation\} Here, \(m_\{eff\} = m_i m_j/(m_i + m_j)\) is the effective mass, {a} is the contact radius, given by \(a =\sqrt\{R\delta\}\) for all models except {jkr}, for which it is given implicitly according to \(delta = a^2/R - 2\sqrt\{\pi \gamma a/E\}\). -In this case, \(\gamma_N\) is the damping coefficient, in units of 1/({time}*{distance}). +In this case, \eta_\{n0\}\ is in units of 1/({time}*{distance}). The {tsuji} model is based on the work of "(Tsuji et al)"_#Tsuji1992. Here, the -damping term is given by: +damping coefficient specified as part of the normal model is intepreted +as a restitution coefficient \(e\). The damping constant \(\eta_n\) is given by: + \begin\{equation\} -F_\{N,damp\} = -\alpha (m_\{eff\}k_N)^\{l/2\} \mathbf\{v\}_\{N,rel\} +\eta_n = \alpha (m_\{eff\}k_n)^\{1/2\} \end\{equation\} -For normal contact models based on material parameters, \(k_N = 4/3Ea\). +For normal contact models based on material parameters, \(k_n = 4/3Ea\). The parameter \(\alpha\) is related to the restitution coefficient {e} according to: -\begin{equation} -\alpha = 1.2728-4.2783e+11.087e^2-22.348e^3+27.467e^4-18.022e^5+4.8218e^6 -\end{equation} -For further details, see "(Tsuji et al)"_#Tsuji1992. +\begin\{equation\} +\alpha = 1.2728-4.2783e+11.087e^2-22.348e^3+27.467e^4-18.022e^5+4.8218e^6 +\end\{equation\} + +The dimensionless coefficient of restitution \(e\) specified as part of the normal contact model +parameters should be between 0 and 1, but no error check is performed on this. + +The total normal force is computed as the sum of the elastic and damping components: + +\begin\{equation\} +\mathbf\{F\}_n = \mathbf\{F\}_\{ne\} + \mathbf\{F\}_\{n,damp\} +\end\{equation\} :line -Following the normal contact model settings, the {pair_coeff} command requires specification -of the tangential contact model. The required keyword {tangential} is expected, followed by the model choice and associated -parameters. Currently supported tangential model choices and their expected parameters are as follows: +The {pair_coeff} command also requires specification +of the tangential contact model. The required keyword {tangential} is expected, followed by the model +choice and associated parameters. Currently supported tangential model choices and their +expected parameters are as follows: -{linear_nohistory} : \(\gamma_t\), \(\mu_s\) -{linear_history} : \(k_t\), \(\gamma_t\), \(\mu_s\) :ol +{linear_nohistory} : \(x_\{\gamma,t\}\), \(\mu_s\) +{linear_history} : \(k_t\), \(x_\{\gamma,t\}\), \(\mu_s\) :ol -Here, \(\gamma_t\) is the tangential damping coefficient, \(\mu_s\) is the tangential (or sliding) friction -coefficient, and \(k_t\) is the tangential stiffness coefficient. +Here, \(x_\{\gamma,t\}\) is a dimensionless multiplier for the normal damping \(\eta_n\) +that determines the magnitude of the +tangential damping, \(\mu_t\) is the tangential (or sliding) friction +coefficient, and \(k_t\) is the tangential stiffness coefficient. -For {linear_nohistory}, a simple velocity-dependent Coulomb friction criterion is used, which reproduces the behavior +For {tangential linear_nohistory}, a simple velocity-dependent Coulomb friction criterion is used, +which mimics the behavior of the {pair gran/hooke} style. The tangential force (\mathbf\{F\}_t\) is given by: \begin\{equation\} -\mathbf\{F\}_t = -min(\mu_s \|\mathbf\{F\}_n\|, \gamma_t m_\{eff\}\|\mathbf\{v\}_\{t, rel\}\|) \mathbf\{t\} +\mathbf\{F\}_t = -min(\mu_t F_\{n0\}, \|\mathbf\{F\}_\mathrm\{t,damp\}\|) \mathbf\{t\} \end\{equation\} -Where \(\|\mathbf\{F\}_n\) is the magnitude of the normal force, -\(\mathbf\{v\}_\{t, rel\} = \mathbf\{v\}_\{t\} - (R_i\Omega_i + R_j\Omega_j) \times \mathbf\{n\}\) is the relative tangential -velocity at the point of contact, \(\mathbf\{v\}_\{t\} = \mathbf\{v\}_R - \mathbf\{v\}_R\cdot\mathbf\{n\}\), -\(\mathbf\{v\}_R = \mathbf\{v\}_i - \mathbf\{v\}_j. +The tangential damping force \(\mathbf\{F\}_\mathrm\{t,damp\}\) is given by: -For {linear_history}, the total tangential displacement \(\mathbf\{\xi\}\) is accumulated during the entire +\begin\{equation\} +\mathbf\{F\}_\mathrm\{t,damp\} = -\eta_t \mathbf\{v\}_\{t,rel\} +\end\{equation\} + +The tangetial damping prefactor \(\eta_t\) is calculated by scaling the normal damping \(\eta_n\) (see above): +\begin\{equation\} +\eta_t = -x_\{\gamma,t\} \eta_n +\end\{equation\} + +The normal damping prefactor \(\eta_n\) is determined by the choice of the {damping} keyword, as discussed above. +Thus, the {damping} keyword also affects the tangential damping. +The parameter \(x_\{\gamma,t\}\) is a scaling coefficient. Several works in the literature use +\(x_\{\gamma,t\} = 1\) ("Marshall"_#Marshall2009, "Tsuji et al"_#Tsuji1992, "Silbert et al"_#Silbert2001). +The relative tangential velocity at the point of contact is given by +\(\mathbf\{v\}_\{t, rel\} = \mathbf\{v\}_\{t\} - (R_i\Omega_i + R_j\Omega_j) \times \mathbf\{n\}\), +where \(\mathbf\{v\}_\{t\} = \mathbf\{v\}_r - \mathbf\{v\}_r\cdot\mathbf\{n\}\), +\(\mathbf\{v\}_r = \mathbf\{v\}_j - \mathbf\{v\}_i\). The direction of the applied force is +\(\mathbf\{t\} = \mathbf\{v_\{t,rel\}\}/\|\mathbf\{v_\{t,rel\}\}\|\). + +The normal force value \(F_\{n0\}\) used to compute the critical force +depends on the form of the contact model. For non-cohesive models +({hertz}, {hertz/material}, {hooke}), it is given by the magnitude of the normal force: + +\begin\{equation\} +F_\{n0\} = \|\mathbf\{F\}_n\| +\end\{equation\} + +For cohesive models such as {jkr} and {dmt}, the critical force is adjusted so that the critical tangential +force approaches \(\mu_t F_\{pulloff\}\), see "Marshall"_#Marshall2009, equation 43, and "Thornton"_#. +For both models, \(F_\{n0\}\) takes the form: + +\begin\{equation\} +F_\{n0\} = \|\mathbf\{F\}_ne + 2 F_\{pulloff\}\| +\end\{equation\} + +Where \(F_\{pulloff\} = 3\pi \gamma R \) for {jkr}, and \(F_\{pulloff\} = 4\pi \gamma R \) for {dmt}. + +For {tangential linear_history}, the tangential force is given by: + +\begin\{equation\} +\mathbf\{F\}_t = -min(\mu_t F_\{n0\}, \|-k_t\mathbf\{\xi\} + \mathbf\{F\}_\mathrm\{t,damp\}\|) \mathbf\{t\} +\end\{equation\} + +Here, \(\mathbf\{\xi\}\) is the tangential displacement accumulated during the entire duration of the contact: \begin\{equation\} \mathbf\{\xi\} = \int_\{t0\}^t \mathbf\{v\}_\{t,rel\}(\tau) \mathrm\{d\}\tau \end\{equation\} -The tangential displacement must in the frame of reference of the contacting pair of particles, - -\begin\{equation\} -\mathbf\{\xi\} = \mathbf\{\xi'\} - \mathbf\{n\}(\mathbf\{n\} \cdot \mathbf\{\xi'\}) -\end\{equation\} - -\noindent Since the goal here is a `rotation', the equation above should be accompanied by a rescaling, so that at each step, -the displacement is first rotated into the current frame of reference $\mathbf\{\xi\}$, then updated: +This accumlated tangential displacement must be adjusted to account for changes +in the frame of reference +of the contacting pair of particles during contact. This occurs due to the overall motion of the contacting particles +in a rigid-body-like fashion during the duration of the contact. There are two modes of motion +that are relevant: the 'tumbling' rotation of the contacting pair, which changes the orientation of the +plane in which tangential displacement occurs; and 'spinning' rotation of the contacting pair +about the vector connecting their centers of mass (\(\mathbf\{n\}\)). +Corrections due to the former mode of motion are +made by rotating the accumulated displacement into the plane that is tangential +to the contact vector at each step, +or equivalently removing any component of the tangential displacement +that lies along \(\mathbf\{n\}\), and rescaling to preserve the magnitude. +This folllows the discussion in "Luding"_#Luding2008, see equation 17 and +relevant discussion in that work: \begin\{equation\} \mathbf\{\xi\} = \left(\mathbf\{\xi'\} - (\mathbf\{n\} \cdot \mathbf\{\xi'\})\mathbf\{n\}\right) \frac\{\|\mathbf\{\xi'\}\|\}\{\|\mathbf\{\xi'\}\| - \mathbf\{n\}\cdot\mathbf\{\xi'\}\} \label\{eq:rotate_displacements\} \end\{equation\} +Here, \(\mathbf\{\xi'\}\) is the accumulated displacement prior to the current time step and +\(\mathbf\{\xi\}\) is the corrected displacement. Corrections to the displacement +due to the second mode of motion described above (rotations about \(\mathbf\{n\}\)) +are not currently implemented, but are expected to be minor for most simulations. -a simple velocity-dependent Coulomb friction criterion is used, which reproduces the behavior -of the {pair gran/hooke} style. The tangential force (\mathbf\{F\}_t\) is given by: +Furthermore, when the tangential force exceeds the critical force, +the tangential displacement is re-scaled to match the value for the critical force (see "Luding"_#Luding2008, +equation 20 and related discussion): +\begin\{equation\} +\mathbf\{\xi\} = -\frac\{1\}\{k_t\}\left(\mu_t F_\{n0\}\mathbf\{t\} + \mathbf\{F\}_\{t,damp\}\right) +\end\{equation\} - :link(Brill1996) +The tangential force is added to the total normal force (elastic plus damping) to produce the total force +on the particle. The tangential force also acts at the contact point to induce a torque on each +particle according to: + +\begin\{equation\} +\mathbf\{\tau\}_i = -R_i \mathbf\{n\} \times \mathbf\{F\}_t +\end\{equation\} + +\begin\{equation\} +\mathbf\{\tau\}_j = -R_j \mathbf\{n\} \times \mathbf\{F\}_t +\end\{equation\} + +:line + +The optional {rolling} keyword enables rolling friction, which resists pure rolling +motion of particles. The options currently supported are: + +{none} +{sds} : \(k_\{roll\}\), \(\gamma_\{roll\}\), \(\mu_\{roll\}\) :ol + +If the {rolling} keyword is not specified, the model defaults to {none}. + +For {rolling sds}, rolling friction is computed via a spring-dashpot-slider, using a +'pseudo-force' formulation, as detailed by "Luding"_#Luding2008. Unlike the formulation +in "Marshall"_#Marshall2009, this allows for the required adjustment of +rolling displacement due to changes in the frame of referenece of the contacting pair. +The rolling pseudo-force is computed analogously to the tangential force: + +\begin\{equation\} +\mathbf\{F\}_\{roll,0\} = k_\{roll\} \mathbf\{\xi\}_\{roll\} - \gamma_\{roll\} \mathbf\{v\}_\{roll\} +\end\{equation\} + +Here, \(\mathbf\{v\}_\{roll\} = -R(\mathbf\{\Omega\}_i - \mathbf\{\Omega\}_j) \times \mathbf\{n\}\) is the +relative rolling velocity, as given in "Wang et al"_#Wang2015 and "Luding"_#Luding2008. This differs +from the expressions given by "Kuhn and Bagi"_#Kuhn2004 and used in "Marshall"_#Marshall2009; +see "Wang et al"_#Wang2015 for details. The rolling displacement is given by: + +\begin\{equation\} +\mathbf\{\xi\}_\{roll\} = \int_\{t_0\}^t \mathbf\{v\}_\{roll\} (\tau) \mathrm\{d\} \tau +\end\{equation\} + +A Coulomb friction criterion truncates the rolling pseudo-force if it exceeds a critical value: +\begin\{equation\} +\mathbf\{F\}_\{roll\} = min(\mu_\{roll\} F_\{n,0\}, \|\mathbf\{F\}_\{roll,0\}\|)\mathbf\{k\} +\end\{equation\} + +Here, \(\mathbf\{k\} = \mathbf\{v\}_\{roll\}/\|\mathbf\{v\}_\{roll\}\|\) is the direction of the pseudo-force. +As with tangential displacement, the rolling displacement is rescaled when the critical +force is exceeded, so that the spring length corresponds the critical force. Additionally, the +displacement is adjusted to account for rotations of the frame of reference of the two +contacting particles in a manner analogous to the tangential displacement. + +The rolling pseudo-force does not contribute to the total force on either particle (hence 'pseudo'), +but acts only to induce an equal and opposite torque on each particle, according to: + +\begin\{equation\} +\tau_\{roll,i\} = R_\{eff\} \mathbf\{n\} \times \mathbf\{F\}_\{roll\} +\end\{equation\} + +\begin\{equation\} +\tau_\{roll,j\} = -\tau_\{roll,i\} +\end\{equation\} + +:line + +The optional {twisting} keyword enables twisting friction, which resists +rotation of two contacting particles about the vector \(\mathbf\{n\}\) that connects their +centers. The options currently supported are: + +{none} +{sds} : \(k_\{twist\}\), \(\gamma_\{twist\}\), \(\mu_\{twist\}\) +{marshall} :ol + +If the {twisting} keyword is not specified, the model defaults to {none}. + +For both {twisting sds} and {twisting marshall}, a history-dependent spring-dashpot-slider is used to compute the twisting +torque. Because twisting displacement is a scalar, there is no need to adjust for changes +in the frame of reference due to rotations of the particle pair. The formulation in +"Marshall"_#Marshall2009 therefore provides the most straightforward treatment: + +\begin\{equation\} +\tau_\{twist,0\} = -k_\{twist\}\xi_\{twist\} - \gamma_\{twist\}\Omega_\{twist\} +\end\{equation\} + +Here \(\xi_\{twist\} = \int_\{t_0\}^t \Omega_\{twist\} (\tau) \mathrm\{d\}\tau\) is the twisting +angular displacement, and \(\Omega_\{twist\} = (\mathbf\{\Omega\}_i - \mathbf\{\Omega\}_j) \cdot \mathbf\{n\}\) +is the relative twisting angular velocity. The torque is then truncated according to: + +\begin\{equation\} +\tau_\{twist\} = min(\mu_\{twist\} F_\{n,0\}, \tau_\{twist,0\}) +\end\{equation\} + +Similar to the sliding and rolling displacement, the angular displacement is +rescaled so that it corresponds to the critical value if the twisting torque +exceeds this critical value: + +\begin\{equation\} +\xi_\{twist\} = \frac\{1\}\{k_\{twist\}\} (\mu_\{twist\} F_\{n,0\}sgn(\Omega_\{twist\}) - \gamma_\{twist\}\Omega_\{twist\}) +\end\{equation\} + +For {twisting sds}, the coefficients \(k_\{twist\}, \gamma_\{twist\}\) and \(\mu_\{twist\}\) are +simply the user input parameters that follow the {twisting sds} keywords in the {pair_coeff} command. + +For {twisting_marshall}, the coefficients are expressed in terms of sliding friction coefficients, +as discussed in "Marshall"_#Marshall2009 (see equations 32 and 33 of that work): + +\begin\{equation\} +k_\{twist\} = 0.5k_ta^2 +\end\{equation\} + +\begin\{equation\} +\eta_\{twist\} = 0.5\eta_ta^2 +\end\{equation\} + +\begin\{equation\} +\mu_\{twist\} = \frac\{2\}\{3\}a\mu_t +\end\{equation\} + +Finally, the twisting torque on each particle is given by: + +\begin\{equation\} +\mathbf\{\tau\}_\{twist,i\} = \tau_\{twist\}\mathbf\{n\} +\end\{equation\} + +\begin\{equation\} +\mathbf\{\tau\}_\{twist,j\} = -\mathbf\{\tau\}_\{twist,i\} +\end\{equation\} + +:line + +LAMMPS automatically sets pairwise cutoff values for {pair_style granular} based on particle radii (and in the case +of {jkr} pulloff distances). In the vast majority of situations, this is adequate. +However, a cutoff value can optionally be appended to the {pair_style granular} command to specify +a global cutoff (i.e. a cutoff for all atom types). Additionally, the optional {cutoff} keyword +can be passed to the {pair_coeff} command, followed by a cutoff value. +This will set a pairwise cutoff for the atom types in the {pair_coeff} command. +These options may be useful in some rare cases where the automatic cutoff determination is not sufficient, e.g. +if particle diameters are being modified via the {fix adapt} command. In that case, the global cutoff +specified as part of the {pair_style granular} command is applied to all atom types, unless it is +overridden for a given atom type combination by the {cutoff} value specified in the {pair coeff} command. +If {cutoff} is only specified in the {pair coeff} command and no global +cutoff is appended to the {pair_style granular} command, then LAMMPS will use that cutoff for the specified +atom type combination, and automatically set pairwise cutoffs for the remaining atom types. + +:line + +Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are +functionally the same as the corresponding style without the suffix. +They have been optimized to run faster, depending on your available +hardware, as discussed on the "Speed packages"_Speed_packages.html doc +page. The accelerated styles take the same arguments and should +produce the same results, except for round-off and precision issues. + +These accelerated styles are part of the GPU, USER-INTEL, KOKKOS, +USER-OMP and OPT packages, respectively. They are only enabled if +LAMMPS was built with those packages. See the "Build +package"_Build_package.html doc page for more info. + +You can specify the accelerated styles explicitly in your input script +by including their suffix, or you can use the "-suffix command-line +switch"_Run_options.html when you invoke LAMMPS, or you can use the +"suffix"_suffix.html command in your input script. + +See the "Speed packages"_Speed_packages.html doc page for more +instructions on how to use the accelerated styles effectively. + +:line + +[Mixing, shift, table, tail correction, restart, rRESPA info]: + +The "pair_modify"_pair_modify.html mix, shift, table, and tail options +are not relevant for granular pair styles. + +Mixing of coefficients is carried out using geometric averaging for +most quantities, e.g. if friction coefficient for type 1-type 1 interactions +is set to \(\mu_1\), and friction coefficient for type 2-type 2 interactions +is set to \(\mu_2\), the friction coefficient for type1-type2 interactions +is computed as \(\sqrt\{\mu_1\mu_2\}\) (unless explictly specified to +a different value by a {pair_coeff 1 2 ...} command. The exception to this is +elastic modulus, only applicable to {hertz/material}, {dmt} and {jkr} normal +contact models. In that case, the effective elastic modulus is computed as: + +\begin\{equation\} +E_\{eff,ij\} = \left(\frac\{1-\nu_i^2\}\{E_i\} + \frac\{1-\nu_j^2\}\{E_j\}\right)^\{-1\} +\end\{equation\} + +If the {i-j} coefficients \(E_\{ij\}\) and \(\nu_\{ij\}\) are explictly specified, +the effective modulus is computed as: + +\begin\{equation\} +E_\{eff,ij\} = \left(\frac\{1-\nu_\{ij\}^2\}\{E_\{ij\}\} + \frac\{1-\nu_\{ij\}^2\}\{E_\{ij\}\}\right)^\{-1\} +\end\{equation\} + +or + +\begin\{equation\} +E_\{eff,ij\} = \frac\{E_\{ij\}\}\{2(1-\nu_\{ij\})\} +\end\{equation\} + +These pair styles write their information to "binary restart +files"_restart.html, so a pair_style command does not need to be +specified in an input script that reads a restart file. + +These pair styles can only be used via the {pair} keyword of the +"run_style respa"_run_style.html command. They do not support the +{inner}, {middle}, {outer} keywords. + +The single() function of these pair styles returns 0.0 for the energy +of a pairwise interaction, since energy is not conserved in these +dissipative potentials. It also returns only the normal component of +the pairwise interaction force. However, the single() function also +calculates 10 extra pairwise quantities. The first 3 are the +components of the tangential force between particles I and J, acting +on particle I. The 4th is the magnitude of this tangential force. +The next 3 (5-7) are the components of the relative velocity in the +normal direction (along the line joining the 2 sphere centers). The +last 3 (8-10) the components of the relative velocity in the +tangential direction. + +These extra quantities can be accessed by the "compute +pair/local"_compute_pair_local.html command, as {p1}, {p2}, ..., +{p10}. + +:line + +[Restrictions:] + +All the granular pair styles are part of the GRANULAR package. It is +only enabled if LAMMPS was built with that package. See the "Build +package"_Build_package.html doc page for more info. + +These pair styles require that atoms store torque and angular velocity +(omega) as defined by the "atom_style"_atom_style.html. They also +require a per-particle radius is stored. The {sphere} atom style does +all of this. + +This pair style requires you to use the "comm_modify vel +yes"_comm_modify.html command so that velocities are stored by ghost +atoms. + +These pair styles will not restart exactly when using the +"read_restart"_read_restart.html command, though they should provide +statistically similar results. This is because the forces they +compute depend on atom velocities. See the +"read_restart"_read_restart.html command for more details. + +[Related commands:] + +"pair_coeff"_pair_coeff.html + +[Default:] + +For the {pair_coeff} settings: {damping viscoelastic}, {rolling none}, {twisting none} + +[References:] + + :link(Brill1996) [(Brilliantov et al, 1996)] Brilliantov, N. V., Spahn, F., Hertzsch, J. M., & Poschel, T. (1996). Model for collisions in granular gases. Physical review E, 53(5), 5382. @@ -236,5 +583,33 @@ Model for collisions in granular gases. Physical review E, 53(5), 5382. [(Tsuji et al, 1992)] Tsuji, Y., Tanaka, T., & Ishida, T. (1992). Lagrangian numerical simulation of plug flow of cohesionless particles in a horizontal pipe. Powder technology, 71(3), 239-250. + :link(JKR1971) + [(Johnson et al, 1971)] Johnson, K. L., Kendall, K., & Roberts, A. D. (1971). + Surface energy and the contact of elastic solids. Proc. R. Soc. Lond. A, 324(1558), 301-313. - \ No newline at end of file + :link(DMT1975) + [Derjaguin et al, 1975)] Derjaguin, B. V., Muller, V. M., & Toporov, Y. P. (1975). Effect of contact deformations on the + adhesion of particles. Journal of Colloid and interface science, 53(2), 314-326. + + :link(Luding2008) + [(Luding, 2008)] Luding, S. (2008). Cohesive, frictional powders: contact models for tension. Granular matter, 10(4), 235. + + :link(Marshall2009) + [(Marshall, 2009)] Marshall, J. S. (2009). Discrete-element modeling of particulate aerosol flows. + Journal of Computational Physics, 228(5), 1541-1561. + + :link(Silbert2001) + [(Silbert, 2001)] Silbert, L. E., Ertas, D., Grest, G. S., Halsey, T. C., Levine, D., & Plimpton, S. J. (2001). + Granular flow down an inclined plane: Bagnold scaling and rheology. Physical Review E, 64(5), 051302. + + :link(Kuhn2004) + [(Kuhn and Bagi, 2005)] Kuhn, M. R., & Bagi, K. (2004). Contact rolling and deformation in granular media. + International journal of solids and structures, 41(21), 5793-5820. + + :link(Wang2015) + [(Wang et al, 2015)] Wang, Y., Alonso-Marroquin, F., & Guo, W. W. (2015). + Rolling and sliding in 3-D discrete element models. Particuology, 23, 49-55. + + :link(Thornton1991) + [(Thornton, 1991)] Thornton, C. (1991). Interparticle sliding in the presence of adhesion. + J. Phys. D: Appl. Phys. 24 1942 \ No newline at end of file diff --git a/src/GRANULAR/pair_granular.cpp b/src/GRANULAR/pair_granular.cpp index 3713b9251c..5631240fea 100644 --- a/src/GRANULAR/pair_granular.cpp +++ b/src/GRANULAR/pair_granular.cpp @@ -52,8 +52,8 @@ using namespace MathConst; enum {HOOKE, HERTZ, HERTZ_MATERIAL, DMT, JKR}; enum {VELOCITY, VISCOELASTIC, TSUJI}; enum {TANGENTIAL_NOHISTORY, TANGENTIAL_HISTORY, TANGENTIAL_MINDLIN}; -enum {TWIST_NONE, TWIST_NOHISTORY, TWIST_SDS, TWIST_MARSHALL}; -enum {ROLL_NONE, ROLL_NOHISTORY, ROLL_SDS}; +enum {TWIST_NONE, TWIST_SDS, TWIST_MARSHALL}; +enum {ROLL_NONE, ROLL_SDS}; /* ---------------------------------------------------------------------- */ @@ -136,9 +136,9 @@ void PairGranular::compute(int eflag, int vflag) double wr1,wr2,wr3; double vtr1,vtr2,vtr3,vrel; - double knfac, damp_normal; + double knfac, damp_normal, damp_normal_prefactor; double k_tangential, damp_tangential; - double Fne, Ft, Fdamp, Fntot, Fcrit, Fscrit, Frcrit; + double Fne, Ft, Fdamp, Fntot, Fncrit, Fscrit, Frcrit; double fs, fs1, fs2, fs3; double mi,mj,meff,damp,ccel,tor1,tor2,tor3; @@ -324,10 +324,12 @@ void PairGranular::compute(int eflag, int vflag) } else{ knfac = E; //Hooke - Fne = knfac*delta; a = sqrt(dR); - if (normal_model[itype][jtype] != HOOKE) + if (normal_model[itype][jtype] != HOOKE){ Fne *= a; + knfac *= a; + } + Fne = knfac*delta; if (normal_model[itype][jtype] == DMT) Fne -= 4*MY_PI*normal_coeffs[itype][jtype][3]*Reff; } @@ -343,7 +345,8 @@ void PairGranular::compute(int eflag, int vflag) damp_normal = sqrt(meff*knfac); } - Fdamp = -normal_coeffs[itype][jtype][1]*damp_normal*vnnr; + damp_normal_prefactor = normal_coeffs[itype][jtype][1]*damp_normal; + Fdamp = -damp_normal_prefactor*vnnr; Fntot = Fne + Fdamp; @@ -376,17 +379,21 @@ void PairGranular::compute(int eflag, int vflag) if (normal_model[itype][jtype] == JKR){ F_pulloff = 3*M_PI*coh*Reff; - Fcrit = fabs(Fne + 2*F_pulloff); + Fncrit = fabs(Fne + 2*F_pulloff); + } + else if (normal_model[itype][jtype] == DMT){ + F_pulloff = 4*M_PI*coh*Reff; + Fncrit = fabs(Fne + 2*F_pulloff); } else{ - Fcrit = fabs(Fne); + Fncrit = fabs(Fntot); } //------------------------------ //Tangential forces //------------------------------ k_tangential = tangential_coeffs[itype][jtype][0]; - damp_tangential = tangential_coeffs[itype][jtype][1]*damp_normal; + damp_tangential = tangential_coeffs[itype][jtype][1]*damp_normal_prefactor; if (tangential_history){ shrmag = sqrt(history[0]*history[0] + history[1]*history[1] + @@ -419,7 +426,7 @@ void PairGranular::compute(int eflag, int vflag) fs3 = -k_tangential*history[2] - damp_tangential*vtr3; // rescale frictional displacements and forces if needed - Fscrit = tangential_coeffs[itype][jtype][2] * Fcrit; + Fscrit = tangential_coeffs[itype][jtype][2] * Fncrit; fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); if (fs > Fscrit) { if (shrmag != 0.0) { @@ -460,64 +467,53 @@ void PairGranular::compute(int eflag, int vflag) if (vrlmag != 0.0) vrlmaginv = 1.0/vrlmag; else vrlmaginv = 0.0; - if (roll_history){ - int rhist0 = roll_history_index; - int rhist1 = rhist0 + 1; - int rhist2 = rhist1 + 1; + int rhist0 = roll_history_index; + int rhist1 = rhist0 + 1; + int rhist2 = rhist1 + 1; - // Rolling displacement - rollmag = sqrt(history[rhist0]*history[rhist0] + - history[rhist1]*history[rhist1] + - history[rhist2]*history[rhist2]); + // Rolling displacement + rollmag = sqrt(history[rhist0]*history[rhist0] + + history[rhist1]*history[rhist1] + + history[rhist2]*history[rhist2]); - rolldotn = history[rhist0]*nx + history[rhist1]*ny + history[rhist2]*nz; + rolldotn = history[rhist0]*nx + history[rhist1]*ny + history[rhist2]*nz; - if (historyupdate){ - if (fabs(rolldotn) < EPSILON) rolldotn = 0; - if (rolldotn > 0){ //Rotate into tangential plane - scalefac = rollmag/(rollmag - rolldotn); - history[rhist0] -= rolldotn*nx; - history[rhist1] -= rolldotn*ny; - history[rhist2] -= rolldotn*nz; - //Also rescale to preserve magnitude - history[rhist0] *= scalefac; - history[rhist1] *= scalefac; - history[rhist2] *= scalefac; - } - history[rhist0] += vrl1*dt; - history[rhist1] += vrl2*dt; - history[rhist2] += vrl3*dt; - } - - - k_roll = roll_coeffs[itype][jtype][0]; - damp_roll = roll_coeffs[itype][jtype][1]; - fr1 = -k_roll*history[rhist0] - damp_roll*vrl1; - fr2 = -k_roll*history[rhist1] - damp_roll*vrl2; - fr3 = -k_roll*history[rhist2] - damp_roll*vrl3; - - // rescale frictional displacements and forces if needed - Frcrit = roll_coeffs[itype][jtype][2] * Fcrit; - - fr = sqrt(fr1*fr1 + fr2*fr2 + fr3*fr3); - if (fr > Frcrit) { - if (rollmag != 0.0) { - history[rhist0] = -1.0/k_roll*(Frcrit*fr1/fr + damp_roll*vrl1); - history[rhist1] = -1.0/k_roll*(Frcrit*fr2/fr + damp_roll*vrl2); - history[rhist2] = -1.0/k_roll*(Frcrit*fr3/fr + damp_roll*vrl3); - fr1 *= Frcrit/fr; - fr2 *= Frcrit/fr; - fr3 *= Frcrit/fr; - } else fr1 = fr2 = fr3 = 0.0; + if (historyupdate){ + if (fabs(rolldotn) < EPSILON) rolldotn = 0; + if (rolldotn > 0){ //Rotate into tangential plane + scalefac = rollmag/(rollmag - rolldotn); + history[rhist0] -= rolldotn*nx; + history[rhist1] -= rolldotn*ny; + history[rhist2] -= rolldotn*nz; + //Also rescale to preserve magnitude + history[rhist0] *= scalefac; + history[rhist1] *= scalefac; + history[rhist2] *= scalefac; } + history[rhist0] += vrl1*dt; + history[rhist1] += vrl2*dt; + history[rhist2] += vrl3*dt; } - else{ // - fr = meff*roll_coeffs[itype][jtype][1]*vrlmag; - if (vrlmag != 0.0) fr = MIN(Fne, fr) / vrlmag; - else fr = 0.0; - fr1 = -fr*vrl1; - fr2 = -fr*vrl2; - fr3 = -fr*vrl3; + + k_roll = roll_coeffs[itype][jtype][0]; + damp_roll = roll_coeffs[itype][jtype][1]; + fr1 = -k_roll*history[rhist0] - damp_roll*vrl1; + fr2 = -k_roll*history[rhist1] - damp_roll*vrl2; + fr3 = -k_roll*history[rhist2] - damp_roll*vrl3; + + // rescale frictional displacements and forces if needed + Frcrit = roll_coeffs[itype][jtype][2] * Fncrit; + + fr = sqrt(fr1*fr1 + fr2*fr2 + fr3*fr3); + if (fr > Frcrit) { + if (rollmag != 0.0) { + history[rhist0] = -1.0/k_roll*(Frcrit*fr1/fr + damp_roll*vrl1); + history[rhist1] = -1.0/k_roll*(Frcrit*fr2/fr + damp_roll*vrl2); + history[rhist2] = -1.0/k_roll*(Frcrit*fr3/fr + damp_roll*vrl3); + fr1 *= Frcrit/fr; + fr2 *= Frcrit/fr; + fr3 *= Frcrit/fr; + } else fr1 = fr2 = fr3 = 0.0; } } @@ -527,30 +523,24 @@ void PairGranular::compute(int eflag, int vflag) if (twist_model[itype][jtype] != TWIST_NONE){ magtwist = relrot1*nx + relrot2*ny + relrot3*nz; //Omega_T (eq 29 of Marshall) if (twist_model[itype][jtype] == TWIST_MARSHALL){ - k_twist = 0.5*k_tangential*a*a;; //eq 32 + k_twist = 0.5*k_tangential*a*a;; //eq 32 of Marshall paper damp_twist = 0.5*damp_tangential*a*a; - mu_twist = TWOTHIRDS*a; + mu_twist = TWOTHIRDS*a*tangential_coeffs[itype][jtype][2]; } else{ k_twist = twist_coeffs[itype][jtype][0]; damp_twist = twist_coeffs[itype][jtype][1]; mu_twist = twist_coeffs[itype][jtype][2]; } - if (twist_model[itype][jtype] > 1){ - if (historyupdate){ - history[twist_history_index] += magtwist*dt; - } - magtortwist = -k_twist*history[twist_history_index] - damp_twist*magtwist;//M_t torque (eq 30) - signtwist = (magtwist > 0) - (magtwist < 0); - Mtcrit = TWOTHIRDS*a*Fscrit;//critical torque (eq 44) - if (fabs(magtortwist) > Mtcrit) { - history[twist_history_index] = 1.0/k_twist*(Mtcrit*signtwist - damp_twist*magtwist); - magtortwist = -Mtcrit * signtwist; //eq 34 - } + if (historyupdate){ + history[twist_history_index] += magtwist*dt; } - else{ - if (magtwist > 0) magtortwist = -damp_twist*magtwist; - else magtortwist = 0; + magtortwist = -k_twist*history[twist_history_index] - damp_twist*magtwist;//M_t torque (eq 30) + signtwist = (magtwist > 0) - (magtwist < 0); + Mtcrit = mu_twist*Fncrit;//critical torque (eq 44) + if (fabs(magtortwist) > Mtcrit) { + history[twist_history_index] = 1.0/k_twist*(Mtcrit*signtwist - damp_twist*magtwist); + magtortwist = -Mtcrit * signtwist; //eq 34 } } // Apply forces & torques @@ -747,7 +737,7 @@ void PairGranular::coeff(int narg, char **arg) normal_coeffs_one[3] = force->numeric(FLERR,arg[iarg+4]); //cohesion iarg += 5; } - else if (strcmp(arg[iarg], "damp") == 0){ + else if (strcmp(arg[iarg], "damping") == 0){ if (iarg+1 >= narg) error->all(FLERR, "Illegal pair_coeff command, not enough parameters provided for damping model"); if (strcmp(arg[iarg+1], "velocity") == 0){ damping_model_one = VELOCITY; @@ -757,10 +747,12 @@ void PairGranular::coeff(int narg, char **arg) damping_model_one = VISCOELASTIC; iarg += 1; } - else if (strcmp(arg[iarg], "tsuji") == 0){ + else if (strcmp(arg[iarg+1], "tsuji") == 0){ damping_model_one = TSUJI; iarg += 1; } + else error->all(FLERR, "Illegal pair_coeff command, unrecognized damping model"); + iarg += 1; } else if (strcmp(arg[iarg], "tangential") == 0){ if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for tangential model"); @@ -785,23 +777,18 @@ void PairGranular::coeff(int narg, char **arg) roll_model_one = ROLL_NONE; iarg += 2; } - else{ + else if (strcmp(arg[iarg+1], "sds") == 0){ if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for rolling model"); - if (strcmp(arg[iarg+1], "nohistory") == 0){ - roll_model_one = ROLL_NOHISTORY; - } - else if (strcmp(arg[iarg+1], "sds") == 0){ - roll_model_one = ROLL_SDS; - roll_history = 1; - } - else{ - error->all(FLERR, "Illegal pair_coeff command, rolling friction model not recognized"); - } + roll_model_one = ROLL_SDS; + roll_history = 1; roll_coeffs_one[0] = force->numeric(FLERR,arg[iarg+2]); //kR roll_coeffs_one[1] = force->numeric(FLERR,arg[iarg+3]); //gammaR roll_coeffs_one[2] = force->numeric(FLERR,arg[iarg+4]); //rolling friction coeff. iarg += 5; } + else{ + error->all(FLERR, "Illegal pair_coeff command, rolling friction model not recognized"); + } } else if (strcmp(arg[iarg], "twisting") == 0){ if (iarg + 1 >= narg) error->all(FLERR, "Illegal pair_coeff command, not enough parameters"); @@ -814,22 +801,17 @@ void PairGranular::coeff(int narg, char **arg) twist_history = 1; iarg += 2; } - else{ + else if (strcmp(arg[iarg+1], "sds") == 0){ if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for twist model"); - if (strcmp(arg[iarg+1], "nohistory") == 0){ - twist_model_one = TWIST_NOHISTORY; - } - else if (strcmp(arg[iarg+1], "sds") == 0){ twist_model_one = TWIST_SDS; twist_history = 1; - } - else{ + twist_coeffs_one[0] = force->numeric(FLERR,arg[iarg+2]); //kt + twist_coeffs_one[1] = force->numeric(FLERR,arg[iarg+3]); //gammat + twist_coeffs_one[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. + iarg += 5; + } + else{ error->all(FLERR, "Illegal pair_coeff command, twisting friction model not recognized"); - } - twist_coeffs_one[0] = force->numeric(FLERR,arg[iarg+2]); //kt - twist_coeffs_one[1] = force->numeric(FLERR,arg[iarg+3]); //gammat - twist_coeffs_one[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. - iarg += 5; } } else if (strcmp(arg[iarg], "cutoff") == 0){ @@ -1063,7 +1045,6 @@ double PairGranular::init_one(int i, int j) for (int k = 0; k < 3; k++) tangential_coeffs[i][j][k] = tangential_coeffs[j][i][k] = mix_geom(tangential_coeffs[i][i][k], tangential_coeffs[j][j][k]); - if (roll_model[i][j] != ROLL_NONE){ for (int k = 0; k < 3; k++) roll_coeffs[i][j][k] = roll_coeffs[j][i][k] = mix_geom(roll_coeffs[i][i][k], roll_coeffs[j][j][k]); @@ -1082,44 +1063,44 @@ double PairGranular::init_one(int i, int j) // if there is no current information about radius/cutoff of type i and j). // we assign cutoff = max(cut[i][j]) for i,j such that cut[i][j] > 0.0. double pulloff; - if (cutoff_global < 0){ - if (cutoff_type[i][j] < 0){ - if (((maxrad_dynamic[i] > 0.0) && (maxrad_dynamic[j] > 0.0)) || - ((maxrad_dynamic[i] > 0.0) && (maxrad_frozen[j] > 0.0)) || - ((maxrad_frozen[i] > 0.0) && (maxrad_dynamic[j] > 0.0))) { // radius info about both i and j exist - cutoff = maxrad_dynamic[i]+maxrad_dynamic[j]; - if (normal_model[i][j] == JKR){ - pulloff = pulloff_distance(maxrad_dynamic[i], maxrad_dynamic[j], i, j); - cutoff += pulloff; - } - else{ - pulloff = 0; - } - if (normal_model[i][j] == JKR) - pulloff = pulloff_distance(maxrad_frozen[i], maxrad_dynamic[j], i, j); - cutoff = MAX(cutoff, maxrad_frozen[i]+maxrad_dynamic[j]+pulloff); + if (cutoff_type[i][j] < 0 && cutoff_global < 0){ + if (((maxrad_dynamic[i] > 0.0) && (maxrad_dynamic[j] > 0.0)) || + ((maxrad_dynamic[i] > 0.0) && (maxrad_frozen[j] > 0.0)) || + ((maxrad_frozen[i] > 0.0) && (maxrad_dynamic[j] > 0.0))) { // radius info about both i and j exist + cutoff = maxrad_dynamic[i]+maxrad_dynamic[j]; + if (normal_model[i][j] == JKR){ + pulloff = pulloff_distance(maxrad_dynamic[i], maxrad_dynamic[j], i, j); + cutoff += pulloff; + } + else{ + pulloff = 0; + } - if (normal_model[i][j] == JKR) - pulloff = pulloff_distance(maxrad_dynamic[i], maxrad_frozen[j], i, j); - cutoff = MAX(cutoff,maxrad_dynamic[i]+maxrad_frozen[j]+pulloff); - } - else { // radius info about either i or j does not exist (i.e. not present and not about to get poured; set to largest value to not interfere with neighbor list) - double cutmax = 0.0; - for (int k = 1; k <= atom->ntypes; k++) { - cutmax = MAX(cutmax,2.0*maxrad_dynamic[k]); - cutmax = MAX(cutmax,2.0*maxrad_frozen[k]); - } - cutoff = cutmax; - } + if (normal_model[i][j] == JKR) + pulloff = pulloff_distance(maxrad_frozen[i], maxrad_dynamic[j], i, j); + cutoff = MAX(cutoff, maxrad_frozen[i]+maxrad_dynamic[j]+pulloff); + + if (normal_model[i][j] == JKR) + pulloff = pulloff_distance(maxrad_dynamic[i], maxrad_frozen[j], i, j); + cutoff = MAX(cutoff,maxrad_dynamic[i]+maxrad_frozen[j]+pulloff); } - else{ - cutoff = cutoff_type[i][j]; + else { // radius info about either i or j does not exist (i.e. not present and not about to get poured; set to largest value to not interfere with neighbor list) + double cutmax = 0.0; + for (int k = 1; k <= atom->ntypes; k++) { + cutmax = MAX(cutmax,2.0*maxrad_dynamic[k]); + cutmax = MAX(cutmax,2.0*maxrad_frozen[k]); + } + cutoff = cutmax; } } - else{ + else if (cutoff_type[i][j] > 0){ + cutoff = cutoff_type[i][j]; + } + else if (cutoff_global > 0){ cutoff = cutoff_global; } + return cutoff; } @@ -1211,9 +1192,9 @@ double PairGranular::single(int i, int j, int itype, int jtype, double mi,mj,meff,damp,ccel,tor1,tor2,tor3; double relrot1,relrot2,relrot3,vrl1,vrl2,vrl3,vrlmag,vrlmaginv; - double knfac, damp_normal; + double knfac, damp_normal, damp_normal_prefactor; double k_tangential, damp_tangential; - double Fne, Ft, Fdamp, Fntot, Fcrit, Fscrit, Frcrit; + double Fne, Ft, Fdamp, Fntot, Fncrit, Fscrit, Frcrit; double fs, fs1, fs2, fs3; //For JKR @@ -1357,10 +1338,12 @@ double PairGranular::single(int i, int j, int itype, int jtype, } else{ knfac = E; - Fne = knfac*delta; a = sqrt(dR); - if (normal_model[itype][jtype] != HOOKE) + if (normal_model[itype][jtype] != HOOKE){ Fne *= a; + knfac *= a; + } + Fne = knfac*delta; if (normal_model[itype][jtype] == DMT) Fne -= 4*MY_PI*normal_coeffs[itype][jtype][3]*Reff; } @@ -1376,7 +1359,8 @@ double PairGranular::single(int i, int j, int itype, int jtype, damp_normal = normal_coeffs[itype][jtype][1]*sqrt(meff*knfac); } - Fdamp = -damp_normal*vnnr; + damp_normal_prefactor = normal_coeffs[itype][jtype][1]*damp_normal; + Fdamp = -damp_normal_prefactor*vnnr; Fntot = Fne + Fdamp; @@ -1416,20 +1400,21 @@ double PairGranular::single(int i, int j, int itype, int jtype, if (normal_model[itype][jtype] == JKR){ F_pulloff = 3*M_PI*coh*Reff; - Fcrit = fabs(Fne + 2*F_pulloff); + Fncrit = fabs(Fne + 2*F_pulloff); + } + else if (normal_model[itype][jtype] == DMT){ + F_pulloff = 4*M_PI*coh*Reff; + Fncrit = fabs(Fne + 2*F_pulloff); } else{ - Fcrit = fabs(Fne); + Fncrit = fabs(Fntot); } //------------------------------ //Tangential forces //------------------------------ k_tangential = tangential_coeffs[itype][jtype][0]; - if (normal_model[itype][jtype] != HOOKE){ - k_tangential *= a; - } - damp_tangential = tangential_coeffs[itype][jtype][1]*damp_normal; + damp_tangential = tangential_coeffs[itype][jtype][1]*damp_normal_prefactor; if (tangential_history){ shrmag = sqrt(history[0]*history[0] + history[1]*history[1] + @@ -1441,7 +1426,7 @@ double PairGranular::single(int i, int j, int itype, int jtype, fs3 = -k_tangential*history[2] - damp_tangential*vtr3; // rescale frictional displacements and forces if needed - Fscrit = tangential_coeffs[itype][jtype][2] * Fcrit; + Fscrit = tangential_coeffs[itype][jtype][2] * Fncrit; fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); if (fs > Fscrit) { if (shrmag != 0.0) { @@ -1482,47 +1467,38 @@ double PairGranular::single(int i, int j, int itype, int jtype, if (vrlmag != 0.0) vrlmaginv = 1.0/vrlmag; else vrlmaginv = 0.0; - if (roll_history){ - int rhist0 = roll_history_index; - int rhist1 = rhist0 + 1; - int rhist2 = rhist1 + 1; + int rhist0 = roll_history_index; + int rhist1 = rhist0 + 1; + int rhist2 = rhist1 + 1; - // Rolling displacement - rollmag = sqrt(history[rhist0]*history[rhist0] + - history[rhist1]*history[rhist1] + - history[rhist2]*history[rhist2]); + // Rolling displacement + rollmag = sqrt(history[rhist0]*history[rhist0] + + history[rhist1]*history[rhist1] + + history[rhist2]*history[rhist2]); - rolldotn = history[rhist0]*nx + history[rhist1]*ny + history[rhist2]*nz; + rolldotn = history[rhist0]*nx + history[rhist1]*ny + history[rhist2]*nz; - k_roll = roll_coeffs[itype][jtype][0]; - damp_roll = roll_coeffs[itype][jtype][1]; - fr1 = -k_roll*history[rhist0] - damp_roll*vrl1; - fr2 = -k_roll*history[rhist1] - damp_roll*vrl2; - fr3 = -k_roll*history[rhist2] - damp_roll*vrl3; + k_roll = roll_coeffs[itype][jtype][0]; + damp_roll = roll_coeffs[itype][jtype][1]; + fr1 = -k_roll*history[rhist0] - damp_roll*vrl1; + fr2 = -k_roll*history[rhist1] - damp_roll*vrl2; + fr3 = -k_roll*history[rhist2] - damp_roll*vrl3; - // rescale frictional displacements and forces if needed - Frcrit = roll_coeffs[itype][jtype][2] * Fcrit; + // rescale frictional displacements and forces if needed + Frcrit = roll_coeffs[itype][jtype][2] * Fncrit; - fr = sqrt(fr1*fr1 + fr2*fr2 + fr3*fr3); - if (fr > Frcrit) { - if (rollmag != 0.0) { - history[rhist0] = -1.0/k_roll*(Frcrit*fr1/fr + damp_roll*vrl1); - history[rhist1] = -1.0/k_roll*(Frcrit*fr2/fr + damp_roll*vrl2); - history[rhist2] = -1.0/k_roll*(Frcrit*fr3/fr + damp_roll*vrl3); - fr1 *= Frcrit/fr; - fr2 *= Frcrit/fr; - fr3 *= Frcrit/fr; - } else fr1 = fr2 = fr3 = 0.0; - } - } - else{ // - fr = meff*roll_coeffs[itype][jtype][1]*vrlmag; - if (vrlmag != 0.0) fr = MIN(Fne, fr) / vrlmag; - else fr = 0.0; - fr1 = -fr*vrl1; - fr2 = -fr*vrl2; - fr3 = -fr*vrl3; + fr = sqrt(fr1*fr1 + fr2*fr2 + fr3*fr3); + if (fr > Frcrit) { + if (rollmag != 0.0) { + history[rhist0] = -1.0/k_roll*(Frcrit*fr1/fr + damp_roll*vrl1); + history[rhist1] = -1.0/k_roll*(Frcrit*fr2/fr + damp_roll*vrl2); + history[rhist2] = -1.0/k_roll*(Frcrit*fr3/fr + damp_roll*vrl3); + fr1 *= Frcrit/fr; + fr2 *= Frcrit/fr; + fr3 *= Frcrit/fr; + } else fr1 = fr2 = fr3 = 0.0; } + } //**************************************** @@ -1533,25 +1509,19 @@ double PairGranular::single(int i, int j, int itype, int jtype, if (twist_model[itype][jtype] == TWIST_MARSHALL){ k_twist = 0.5*k_tangential*a*a;; //eq 32 damp_twist = 0.5*damp_tangential*a*a; - mu_twist = TWOTHIRDS*a; + mu_twist = TWOTHIRDS*a*tangential_coeffs[itype][jtype][2];; } else{ k_twist = twist_coeffs[itype][jtype][0]; damp_twist = twist_coeffs[itype][jtype][1]; mu_twist = twist_coeffs[itype][jtype][2]; } - if (twist_history){ - magtortwist = -k_twist*history[twist_history_index] - damp_twist*magtwist;//M_t torque (eq 30) - signtwist = (magtwist > 0) - (magtwist < 0); - Mtcrit = TWOTHIRDS*a*Fscrit;//critical torque (eq 44) - if (fabs(magtortwist) > Mtcrit) { - history[twist_history_index] = 1.0/k_twist*(Mtcrit*signtwist - damp_twist*magtwist); - magtortwist = -Mtcrit * signtwist; //eq 34 - } - } - else{ - if (magtwist > 0) magtortwist = -damp_twist*magtwist; - else magtortwist = 0; + magtortwist = -k_twist*history[twist_history_index] - damp_twist*magtwist;//M_t torque (eq 30) + signtwist = (magtwist > 0) - (magtwist < 0); + Mtcrit = mu_twist*Fncrit;//critical torque (eq 44) + if (fabs(magtortwist) > Mtcrit) { + history[twist_history_index] = 1.0/k_twist*(Mtcrit*signtwist - damp_twist*magtwist); + magtortwist = -Mtcrit * signtwist; //eq 34 } } From ff795e761a02300b790daa77ce98d806bdfc96b8 Mon Sep 17 00:00:00 2001 From: "Dan S. Bolintineanu" Date: Tue, 19 Feb 2019 14:31:27 -0700 Subject: [PATCH 21/44] Added generalized granular option to fix wall/gran and fix wall/gran/region; some minor bug fixes for pair granular --- doc/src/pair_granular.txt | 13 +- src/GRANULAR/fix_wall_gran.cpp | 948 +++++++++++++++++--------- src/GRANULAR/fix_wall_gran.h | 45 +- src/GRANULAR/fix_wall_gran_region.cpp | 105 +-- src/GRANULAR/fix_wall_gran_region.h | 2 +- src/GRANULAR/pair_granular.cpp | 55 +- src/GRANULAR/pair_granular.h | 4 +- 7 files changed, 743 insertions(+), 429 deletions(-) diff --git a/doc/src/pair_granular.txt b/doc/src/pair_granular.txt index ff2ee94be0..911e3cc1dc 100644 --- a/doc/src/pair_granular.txt +++ b/doc/src/pair_granular.txt @@ -533,14 +533,16 @@ the pairwise interaction force. However, the single() function also calculates 10 extra pairwise quantities. The first 3 are the components of the tangential force between particles I and J, acting on particle I. The 4th is the magnitude of this tangential force. -The next 3 (5-7) are the components of the relative velocity in the -normal direction (along the line joining the 2 sphere centers). The -last 3 (8-10) the components of the relative velocity in the -tangential direction. +The next 3 (5-7) are the components of the rolling torque acting on +particle I. The next entry (8) is the magnitude of the rolling torque. +The next entry (9) is the magnitude of the twisting torque acting +about the vector connecting the two particle centers. +The last 3 (10-12) are the components of the vector connecting +the centers of the two particles (x_I - x_J). These extra quantities can be accessed by the "compute pair/local"_compute_pair_local.html command, as {p1}, {p2}, ..., -{p10}. +{p12}. :line @@ -568,6 +570,7 @@ compute depend on atom velocities. See the [Related commands:] "pair_coeff"_pair_coeff.html +"pair gran/*"_pair_gran.html [Default:] diff --git a/src/GRANULAR/fix_wall_gran.cpp b/src/GRANULAR/fix_wall_gran.cpp index d3129b7cdb..6e8cba7b4f 100644 --- a/src/GRANULAR/fix_wall_gran.cpp +++ b/src/GRANULAR/fix_wall_gran.cpp @@ -39,11 +39,24 @@ using namespace MathConst; // XYZ PLANE need to be 0,1,2 enum{XPLANE=0,YPLANE=1,ZPLANE=2,ZCYLINDER,REGION}; -enum{HOOKE,HOOKE_HISTORY,HERTZ_HISTORY,JKR_ROLLING,DMT_ROLLING}; +enum{HOOKE,HOOKE_HISTORY,HERTZ_HISTORY,GRANULAR}; enum{NONE,CONSTANT,EQUAL}; -enum {TSUJI, BRILLIANTOV}; -enum {INDEP, BRILLROLL}; +#define PI27SQ 266.47931882941264802866 // 27*PI**2 +#define THREEROOT3 5.19615242270663202362 // 3*sqrt(3) +#define SIXROOT6 14.69693845669906728801 // 6*sqrt(6) +#define INVROOT6 0.40824829046386307274 // 1/sqrt(6) +#define FOURTHIRDS 1.333333333333333 // 4/3 +#define THREEQUARTERS 0.75 // 3/4 +#define TWOPI 6.28318530717959 // 2*PI + +#define EPSILON 1e-10 + +enum {NORMAL_HOOKE, NORMAL_HERTZ, HERTZ_MATERIAL, DMT, JKR}; +enum {VELOCITY, VISCOELASTIC, TSUJI}; +enum {TANGENTIAL_NOHISTORY, TANGENTIAL_HISTORY, TANGENTIAL_MINDLIN}; +enum {TWIST_NONE, TWIST_SDS, TWIST_MARSHALL}; +enum {ROLL_NONE, ROLL_SDS}; #define BIG 1.0e20 #define EPSILON 1e-10 @@ -51,7 +64,7 @@ enum {INDEP, BRILLROLL}; /* ---------------------------------------------------------------------- */ FixWallGran::FixWallGran(LAMMPS *lmp, int narg, char **arg) : - Fix(lmp, narg, arg), idregion(NULL), shearone(NULL), fix_rigid(NULL), mass_rigid(NULL) + Fix(lmp, narg, arg), idregion(NULL), history_one(NULL), fix_rigid(NULL), mass_rigid(NULL) { if (narg < 4) error->all(FLERR,"Illegal fix wall/gran command"); @@ -66,19 +79,18 @@ FixWallGran::FixWallGran(LAMMPS *lmp, int narg, char **arg) : if (strcmp(arg[3],"hooke") == 0) pairstyle = HOOKE; else if (strcmp(arg[3],"hooke/history") == 0) pairstyle = HOOKE_HISTORY; else if (strcmp(arg[3],"hertz/history") == 0) pairstyle = HERTZ_HISTORY; - else if (strcmp(arg[3],"dmt/rolling") == 0) pairstyle = DMT_ROLLING; - //else if (strcmp(arg[3],"jkr/rolling") == 0) pairstyle = JKR_ROLLING; + else if (strcmp(arg[3],"granular") == 0) pairstyle = GRANULAR; else error->all(FLERR,"Invalid fix wall/gran interaction style"); - history = restart_peratom = 1; - if (pairstyle == HOOKE) history = restart_peratom = 0; + use_history = restart_peratom = 1; + if (pairstyle == HOOKE) use_history = restart_peratom = 0; // wall/particle coefficients int iarg; - if (pairstyle != JKR_ROLLING && pairstyle != DMT_ROLLING) { - sheardim = 3; + if (pairstyle != GRANULAR) { + size_history = 3; if (narg < 11) error->all(FLERR,"Illegal fix wall/gran command"); kn = force->numeric(FLERR,arg[4]); @@ -103,46 +115,157 @@ FixWallGran::FixWallGran(LAMMPS *lmp, int narg, char **arg) : kn /= force->nktv2p; kt /= force->nktv2p; } - iarg = 10; } else { - if (narg < 12) error->all(FLERR,"Illegal fix wall/gran command"); - - sheardim = 7; - Emod = force->numeric(FLERR,arg[4]); - Gmod = force->numeric(FLERR,arg[5]); - xmu = force->numeric(FLERR,arg[6]); - gamman = force->numeric(FLERR,arg[7]); - Ecoh = force->numeric(FLERR,arg[8]); - kR = force->numeric(FLERR,arg[9]); - muR = force->numeric(FLERR,arg[10]); - etaR = force->numeric(FLERR,arg[11]); - - //Defaults - normaldamp = TSUJI; - rollingdamp = INDEP; - - iarg = 12; - for (int iiarg=iarg; iiarg < narg; ++iiarg){ - if (strcmp(arg[iiarg], "normaldamp") == 0){ - if(iiarg+2 > narg) error->all(FLERR, "Invalid fix/wall/gran region command"); - if (strcmp(arg[iiarg+1],"tsuji") == 0){ - normaldamp = TSUJI; - alpha = gamman; - } - else if (strcmp(arg[iiarg+1],"brilliantov") == 0) normaldamp = BRILLIANTOV; - else error->all(FLERR, "Invalid normal damping model for fix wall/gran dmt/rolling"); - iarg += 2; + iarg = 4; + damping_model = VISCOELASTIC; + roll_model = twist_model = NONE; + while (iarg < narg){ + if (strcmp(arg[iarg], "hooke") == 0){ + if (iarg + 2 >= narg) error->all(FLERR,"Illegal fix wall/gran command, not enough parameters provided for Hooke option"); + normal_model = NORMAL_HOOKE; + normal_coeffs[0] = force->numeric(FLERR,arg[iarg+1]); //kn + normal_coeffs[1] = force->numeric(FLERR,arg[iarg+2]); //damping + iarg += 3; } - if (strcmp(arg[iiarg], "rollingdamp") == 0){ - if(iiarg+2 > narg) error->all(FLERR, "Invalid fix/wall/gran region command"); - if (strcmp(arg[iarg+1],"independent") == 0) rollingdamp = INDEP; - else if (strcmp(arg[iarg+1],"brilliantov") == 0) rollingdamp = BRILLROLL; - else error->all(FLERR, "Invalid rolling damping model for fix wall/gran dmt/rolling"); - iarg += 2; + else if (strcmp(arg[iarg], "hertz") == 0){ + int num_coeffs = 2; + if (iarg + num_coeffs >= narg) error->all(FLERR,"Illegal fix wall/gran command, not enough parameters provided for Hertz option"); + normal_model = NORMAL_HERTZ; + normal_coeffs[0] = force->numeric(FLERR,arg[iarg+1]); //kn + normal_coeffs[1] = force->numeric(FLERR,arg[iarg+2]); //damping + iarg += num_coeffs+1; + } + else if (strcmp(arg[iarg], "hertz/material") == 0){ + int num_coeffs = 3; + if (iarg + num_coeffs >= narg) error->all(FLERR,"Illegal fix wall/gran command, not enough parameters provided for Hertz option"); + normal_model = HERTZ_MATERIAL; + Emod = force->numeric(FLERR,arg[iarg+1]); //E + normal_coeffs[1] = force->numeric(FLERR,arg[iarg+2]); //damping + poiss = force->numeric(FLERR,arg[iarg+3]); //Poisson's ratio + normal_coeffs[0] = Emod/(2*(1-poiss))*FOURTHIRDS; + normal_coeffs[2] = poiss; + iarg += num_coeffs+1; + } + else if (strcmp(arg[iarg], "dmt") == 0){ + if (iarg + 4 >= narg) error->all(FLERR,"Illegal fix wall/gran command, not enough parameters provided for Hertz option"); + normal_model = DMT; + Emod = force->numeric(FLERR,arg[iarg+1]); //E + normal_coeffs[1] = force->numeric(FLERR,arg[iarg+2]); //damping + poiss = force->numeric(FLERR,arg[iarg+3]); //Poisson's ratio + normal_coeffs[0] = Emod/(2*(1-poiss))*FOURTHIRDS; + normal_coeffs[2] = poiss; + normal_coeffs[3] = force->numeric(FLERR,arg[iarg+4]); //cohesion + iarg += 5; + } + else if (strcmp(arg[iarg], "jkr") == 0){ + if (iarg + 4 >= narg) error->all(FLERR,"Illegal wall/gran command, not enough parameters provided for JKR option"); + beyond_contact = 1; + normal_model = JKR; + Emod = force->numeric(FLERR,arg[iarg+1]); //E + normal_coeffs[1] = force->numeric(FLERR,arg[iarg+2]); //damping + poiss = force->numeric(FLERR,arg[iarg+3]); //Poisson's ratio + normal_coeffs[0] = Emod/(2*(1-poiss))*FOURTHIRDS; + normal_coeffs[2] = poiss; + normal_coeffs[3] = force->numeric(FLERR,arg[iarg+4]); //cohesion + iarg += 5; + } + else if (strcmp(arg[iarg], "damping") == 0){ + if (iarg+1 >= narg) error->all(FLERR, "Illegal wall/gran command, not enough parameters provided for damping model"); + if (strcmp(arg[iarg+1], "velocity") == 0){ + damping_model = VELOCITY; + iarg += 1; + } + else if (strcmp(arg[iarg+1], "viscoelastic") == 0){ + damping_model = VISCOELASTIC; + iarg += 1; + } + else if (strcmp(arg[iarg+1], "tsuji") == 0){ + damping_model = TSUJI; + iarg += 1; + } + else error->all(FLERR, "Illegal wall/gran command, unrecognized damping model"); + iarg += 1; + } + else if (strcmp(arg[iarg], "tangential") == 0){ + if (iarg + 1 >= narg) error->all(FLERR,"Illegal pair_coeff command, must specify tangential model after 'tangential' keyword"); + if (strcmp(arg[iarg+1], "linear_nohistory") == 0){ + if (iarg + 3 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for tangential model"); + tangential_model = TANGENTIAL_NOHISTORY; + tangential_coeffs[0] = 0; + tangential_coeffs[1] = force->numeric(FLERR,arg[iarg+2]); //gammat + tangential_coeffs[2] = force->numeric(FLERR,arg[iarg+3]); //friction coeff. + iarg += 4; + } + else if (strcmp(arg[iarg+1], "linear_history") == 0){ + if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for tangential model"); + tangential_model = TANGENTIAL_HISTORY; + tangential_history = 1; + tangential_coeffs[0] = force->numeric(FLERR,arg[iarg+2]); //kt + tangential_coeffs[1] = force->numeric(FLERR,arg[iarg+3]); //gammat + tangential_coeffs[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. + iarg += 5; + } + else{ + error->all(FLERR, "Illegal pair_coeff command, tangential model not recognized"); + } + } + else if (strcmp(arg[iarg], "rolling") == 0){ + if (iarg + 1 >= narg) error->all(FLERR, "Illegal wall/gran command, not enough parameters"); + if (strcmp(arg[iarg+1], "none") == 0){ + roll_model = ROLL_NONE; + iarg += 2; + } + else if (strcmp(arg[iarg+1], "sds") == 0){ + if (iarg + 4 >= narg) error->all(FLERR,"Illegal wall/gran command, not enough parameters provided for rolling model"); + roll_model = ROLL_SDS; + roll_history = 1; + roll_coeffs[0] = force->numeric(FLERR,arg[iarg+2]); //kR + roll_coeffs[1] = force->numeric(FLERR,arg[iarg+3]); //gammaR + roll_coeffs[2] = force->numeric(FLERR,arg[iarg+4]); //rolling friction coeff. + iarg += 5; + } + else{ + error->all(FLERR, "Illegal wall/gran command, rolling friction model not recognized"); + } + } + else if (strcmp(arg[iarg], "twisting") == 0){ + if (iarg + 1 >= narg) error->all(FLERR, "Illegal wall/gran command, not enough parameters"); + if (strcmp(arg[iarg+1], "none") == 0){ + twist_model = TWIST_NONE; + iarg += 2; + } + else if (strcmp(arg[iarg+1], "marshall") == 0){ + twist_model = TWIST_MARSHALL; + twist_history = 1; + iarg += 2; + } + else if (strcmp(arg[iarg+1], "sds") == 0){ + if (iarg + 4 >= narg) error->all(FLERR,"Illegal wall/gran command, not enough parameters provided for twist model"); + twist_model = TWIST_SDS; + twist_history = 1; + twist_coeffs[0] = force->numeric(FLERR,arg[iarg+2]); //kt + twist_coeffs[1] = force->numeric(FLERR,arg[iarg+3]); //gammat + twist_coeffs[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. + iarg += 5; + } + else{ + error->all(FLERR, "Illegal wall/gran command, twisting friction model not recognized"); + } + } + else if (strcmp(arg[iarg], "xplane") == 0 || + strcmp(arg[iarg], "yplane") == 0 || + strcmp(arg[iarg], "zplane") == 0 || + strcmp(arg[iarg], "zcylinder") == 0 || + strcmp(arg[iarg], "region") == 0){ + break; + } + else{ + error->all(FLERR, "Illegal fix wall/gran command"); } } + size_history = (normal_model == JKR) + 3*tangential_history + 3*roll_history + twist_history; } // wallstyle args @@ -216,11 +339,10 @@ FixWallGran::FixWallGran(LAMMPS *lmp, int narg, char **arg) : iarg += 3; } else if (strcmp(arg[iarg],"store_contacts") == 0){ peratom_flag = 1; - size_peratom_cols = 8; //Could make this a user input option? + size_peratom_cols = 8; peratom_freq = 1; iarg += 1; } else error->all(FLERR,"Illegal fix wall/gran command"); - } if (wallstyle == XPLANE && domain->xperiodic) @@ -252,7 +374,7 @@ FixWallGran::FixWallGran(LAMMPS *lmp, int narg, char **arg) : // perform initial allocation of atom-based arrays // register with Atom class - shearone = NULL; + history_one = NULL; grow_arrays(atom->nmax); atom->add_callback(0); atom->add_callback(1); @@ -260,14 +382,14 @@ FixWallGran::FixWallGran(LAMMPS *lmp, int narg, char **arg) : nmax = 0; mass_rigid = NULL; - // initialize shear history as if particle is not touching region - // shearone will be NULL for wallstyle = REGION + // initialize history as if particle is not touching region + // history_one will be NULL for wallstyle = REGION - if (history && shearone) { + if (use_history && history_one) { int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) - for (int j = 0; j < sheardim; j++) - shearone[i][j] = 0.0; + for (int j = 0; j < size_history; j++) + history_one[i][j] = 0.0; } if (peratom_flag){ @@ -292,7 +414,7 @@ FixWallGran::~FixWallGran() // delete local storage delete [] idregion; - memory->destroy(shearone); + memory->destroy(history_one); memory->destroy(mass_rigid); } @@ -323,6 +445,34 @@ void FixWallGran::init() for (i = 0; i < modify->nfix; i++) if (modify->fix[i]->rigid_flag) break; if (i < modify->nfix) fix_rigid = modify->fix[i]; + + tangential_history_index = 0; + if (roll_history){ + if (tangential_history) roll_history_index = 3; + else roll_history_index = 0; + } + if (twist_history){ + if (tangential_history){ + if (roll_history) twist_history_index = 6; + else twist_history_index = 3; + } + else{ + if (roll_history) twist_history_index = 3; + else twist_history_index = 0; + } + } + if (normal_model == JKR){ + tangential_history_index += 1; + roll_history_index += 1; + twist_history_index += 1; + } + + if (damping_model == TSUJI){ + double cor = normal_coeffs[1]; + normal_coeffs[1] = 1.2728-4.2783*cor+11.087*pow(cor,2)-22.348*pow(cor,3)+ + 27.467*pow(cor,4)-18.022*pow(cor,5)+ + 4.8218*pow(cor,6); + } } /* ---------------------------------------------------------------------- */ @@ -346,10 +496,10 @@ void FixWallGran::post_force(int /*vflag*/) double dx,dy,dz,del1,del2,delxy,delr,rsq,rwall,meff; double vwall[3]; - // do not update shear history during setup + // do not update history during setup - shearupdate = 1; - if (update->setupflag) shearupdate = 0; + history_update = 1; + if (update->setupflag) history_update = 0; // if just reneighbored: // update rigid body masses for owned atoms if using FixRigid @@ -395,7 +545,7 @@ void FixWallGran::post_force(int /*vflag*/) // if wall was set to NULL, it's skipped since lo/hi are infinity // compute force and torque on atom if close enough to wall // via wall potential matched to pair potential - // set shear if pair potential stores history + // set history if pair potential stores history double **x = atom->x; double **v = atom->v; @@ -450,12 +600,27 @@ void FixWallGran::post_force(int /*vflag*/) rsq = dx*dx + dy*dy + dz*dz; - if (rsq > radius[i]*radius[i]) { - if (history) - for (j = 0; j < sheardim; j++) - shearone[i][j] = 0.0; + double rad; + if (pairstyle == GRANULAR && normal_model == JKR){ + rad = radius[i] + pulloff_distance(radius[i]); + } + else + rad = radius[i]; - } else { + if (rsq > rad*rad) { + if (use_history) + for (j = 0; j < size_history; j++) + history_one[i][j] = 0.0; + } + else { + if (pairstyle == GRANULAR && normal_model == JKR && use_history){ + if ((history_one[i][0] == 0) && (rsq > radius[i]*radius[i])){ + // Particles have not contacted yet, and are outside of contact distance + for (j = 0; j < size_history; j++) + history_one[i][j] = 0.0; + continue; + } + } // meff = effective mass of sphere // if I is part of rigid body, use body mass @@ -484,20 +649,16 @@ void FixWallGran::post_force(int /*vflag*/) omega[i],torque[i],radius[i],meff, contact); else if (pairstyle == HOOKE_HISTORY) hooke_history(rsq,dx,dy,dz,vwall,v[i],f[i], - omega[i],torque[i],radius[i],meff,shearone[i], + omega[i],torque[i],radius[i],meff,history_one[i], contact); else if (pairstyle == HERTZ_HISTORY) hertz_history(rsq,dx,dy,dz,vwall,rwall,v[i],f[i], - omega[i],torque[i],radius[i],meff,shearone[i], + omega[i],torque[i],radius[i],meff,history_one[i], contact); - else if (pairstyle == DMT_ROLLING) - dmt_rolling(rsq,dx,dy,dz,vwall,rwall,v[i],f[i], - omega[i],torque[i],radius[i],meff,shearone[i], + else if (pairstyle == GRANULAR) + granular(rsq,dx,dy,dz,vwall,rwall,v[i],f[i], + omega[i],torque[i],radius[i],meff,history_one[i], contact); - /*else if (pairstyle == JKR_ROLLING) - jkr_rolling(rsq,dx,dy,dz,vwall,rwall,v[i],f[i], - omega[i],torque[i],radius[i],meff,shearone[i], - contact);*/ } } } @@ -605,7 +766,7 @@ void FixWallGran::hooke(double rsq, double dx, double dy, double dz, void FixWallGran::hooke_history(double rsq, double dx, double dy, double dz, double *vwall, double *v, double *f, double *omega, double *torque, - double radius, double meff, double *shear, + double radius, double meff, double *history, double *contact) { double r,vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3; @@ -657,28 +818,28 @@ void FixWallGran::hooke_history(double rsq, double dx, double dy, double dz, // shear history effects - if (shearupdate) { - shear[0] += vtr1*dt; - shear[1] += vtr2*dt; - shear[2] += vtr3*dt; + if (history_update) { + history[0] += vtr1*dt; + history[1] += vtr2*dt; + history[2] += vtr3*dt; } - shrmag = sqrt(shear[0]*shear[0] + shear[1]*shear[1] + shear[2]*shear[2]); + shrmag = sqrt(history[0]*history[0] + history[1]*history[1] + history[2]*history[2]); // rotate shear displacements - rsht = shear[0]*dx + shear[1]*dy + shear[2]*dz; + rsht = history[0]*dx + history[1]*dy + history[2]*dz; rsht = rsht*rsqinv; - if (shearupdate) { - shear[0] -= rsht*dx; - shear[1] -= rsht*dy; - shear[2] -= rsht*dz; + if (history_update) { + history[0] -= rsht*dx; + history[1] -= rsht*dy; + history[2] -= rsht*dz; } // tangential forces = shear + tangential velocity damping - fs1 = - (kt*shear[0] + meff*gammat*vtr1); - fs2 = - (kt*shear[1] + meff*gammat*vtr2); - fs3 = - (kt*shear[2] + meff*gammat*vtr3); + fs1 = - (kt*history[0] + meff*gammat*vtr1); + fs2 = - (kt*history[1] + meff*gammat*vtr2); + fs3 = - (kt*history[2] + meff*gammat*vtr3); // rescale frictional displacements and forces if needed @@ -687,11 +848,11 @@ void FixWallGran::hooke_history(double rsq, double dx, double dy, double dz, if (fs > fn) { if (shrmag != 0.0) { - shear[0] = (fn/fs) * (shear[0] + meff*gammat*vtr1/kt) - + history[0] = (fn/fs) * (history[0] + meff*gammat*vtr1/kt) - meff*gammat*vtr1/kt; - shear[1] = (fn/fs) * (shear[1] + meff*gammat*vtr2/kt) - + history[1] = (fn/fs) * (history[1] + meff*gammat*vtr2/kt) - meff*gammat*vtr2/kt; - shear[2] = (fn/fs) * (shear[2] + meff*gammat*vtr3/kt) - + history[2] = (fn/fs) * (history[2] + meff*gammat*vtr3/kt) - meff*gammat*vtr3/kt; fs1 *= fn/fs ; fs2 *= fn/fs; @@ -728,7 +889,7 @@ void FixWallGran::hooke_history(double rsq, double dx, double dy, double dz, void FixWallGran::hertz_history(double rsq, double dx, double dy, double dz, double *vwall, double rwall, double *v, double *f, double *omega, double *torque, - double radius, double meff, double *shear, + double radius, double meff, double *history, double *contact) { double r,vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3; @@ -787,28 +948,28 @@ void FixWallGran::hertz_history(double rsq, double dx, double dy, double dz, // shear history effects - if (shearupdate) { - shear[0] += vtr1*dt; - shear[1] += vtr2*dt; - shear[2] += vtr3*dt; + if (history_update) { + history[0] += vtr1*dt; + history[1] += vtr2*dt; + history[2] += vtr3*dt; } - shrmag = sqrt(shear[0]*shear[0] + shear[1]*shear[1] + shear[2]*shear[2]); + shrmag = sqrt(history[0]*history[0] + history[1]*history[1] + history[2]*history[2]); - // rotate shear displacements + // rotate history displacements - rsht = shear[0]*dx + shear[1]*dy + shear[2]*dz; + rsht = history[0]*dx + history[1]*dy + history[2]*dz; rsht = rsht*rsqinv; - if (shearupdate) { - shear[0] -= rsht*dx; - shear[1] -= rsht*dy; - shear[2] -= rsht*dz; + if (history_update) { + history[0] -= rsht*dx; + history[1] -= rsht*dy; + history[2] -= rsht*dz; } // tangential forces = shear + tangential velocity damping - fs1 = -polyhertz * (kt*shear[0] + meff*gammat*vtr1); - fs2 = -polyhertz * (kt*shear[1] + meff*gammat*vtr2); - fs3 = -polyhertz * (kt*shear[2] + meff*gammat*vtr3); + fs1 = -polyhertz * (kt*history[0] + meff*gammat*vtr1); + fs2 = -polyhertz * (kt*history[1] + meff*gammat*vtr2); + fs3 = -polyhertz * (kt*history[2] + meff*gammat*vtr3); // rescale frictional displacements and forces if needed @@ -817,11 +978,11 @@ void FixWallGran::hertz_history(double rsq, double dx, double dy, double dz, if (fs > fn) { if (shrmag != 0.0) { - shear[0] = (fn/fs) * (shear[0] + meff*gammat*vtr1/kt) - + history[0] = (fn/fs) * (history[0] + meff*gammat*vtr1/kt) - meff*gammat*vtr1/kt; - shear[1] = (fn/fs) * (shear[1] + meff*gammat*vtr2/kt) - + history[1] = (fn/fs) * (history[1] + meff*gammat*vtr2/kt) - meff*gammat*vtr2/kt; - shear[2] = (fn/fs) * (shear[2] + meff*gammat*vtr3/kt) - + history[2] = (fn/fs) * (history[2] + meff*gammat*vtr3/kt) - meff*gammat*vtr3/kt; fs1 *= fn/fs ; fs2 *= fn/fs; @@ -854,268 +1015,366 @@ void FixWallGran::hertz_history(double rsq, double dx, double dy, double dz, } -void FixWallGran::dmt_rolling(double rsq, double dx, double dy, double dz, +void FixWallGran::granular(double rsq, double dx, double dy, double dz, double *vwall, double rwall, double *v, double *f, double *omega, double *torque, - double radius, double meff, double *shear, + double radius, double meff, double *history, double *contact) { - int i,j,ii,jj,inum,jnum; - int itype,jtype; - double xtmp,ytmp,ztmp,delx,dely,delz,fx,fy,fz,nx,ny,nz; - double radi,radj,radsum,r,rinv,rsqinv,R,a; - double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3; - double wr1,wr2,wr3; - double vtr1,vtr2,vtr3,vrel; - double kn, kt, k_Q, k_R, eta_N, eta_T, eta_Q, eta_R; - double Fhz, Fdamp, Fdmt, Fne, Fntot, Fscrit, Frcrit; - double overlap; - double mi,mj,damp,ccel,tor1,tor2,tor3; - double relrot1,relrot2,relrot3,vrl1,vrl2,vrl3,vrlmag,vrlmaginv; - double rollmag, rolldotn, scalefac; - double fr, fr1, fr2, fr3; - double signtwist, magtwist, magtortwist, Mtcrit; - double fs,fs1,fs2,fs3,roll1,roll2,roll3,torroll1,torroll2,torroll3; - double tortwist1, tortwist2, tortwist3; - double shrmag,rsht; + int i,j,ii,jj,inum,jnum,itype,jtype; + double xtmp,ytmp,ztmp,delx,dely,delz,fx,fy,fz,nx,ny,nz; + double radi,radj,radsum,r,rinv,rsqinv; + double Reff, delta, dR, dR2; - r = sqrt(rsq); - rinv = 1.0/r; - rsqinv = 1.0/rsq; + double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3; + double wr1,wr2,wr3; + double vtr1,vtr2,vtr3,vrel; - radsum = radius + rwall; - if (rwall == 0) R = radius; - else R = radius*rwall/(radius+rwall); + double knfac, damp_normal, damp_normal_prefactor; + double k_tangential, damp_tangential; + double Fne, Ft, Fdamp, Fntot, Fncrit, Fscrit, Frcrit; + double fs, fs1, fs2, fs3; - nx = dx*rinv; - ny = dy*rinv; - nz = dz*rinv; + double mi,mj,damp,ccel,tor1,tor2,tor3; + double relrot1,relrot2,relrot3,vrl1,vrl2,vrl3,vrlmag,vrlmaginv; - // relative translational velocity + //For JKR + double R2, coh, F_pulloff, delta_pulloff, dist_pulloff, a, a2, E; + double t0, t1, t2, t3, t4, t5, t6; + double sqrt1, sqrt2, sqrt3, sqrt4; - vr1 = v[0] - vwall[0]; - vr2 = v[1] - vwall[1]; - vr3 = v[2] - vwall[2]; + //Rolling + double k_roll, damp_roll; + double roll1, roll2, roll3, torroll1, torroll2, torroll3; + double rollmag, rolldotn, scalefac; + double fr, fr1, fr2, fr3; - // normal component + //Twisting + double k_twist, damp_twist, mu_twist; + double signtwist, magtwist, magtortwist, Mtcrit; + double tortwist1, tortwist2, tortwist3; - vnnr = vr1*nx + vr2*ny + vr3*nz; //v_R . n - vn1 = nx*vnnr; - vn2 = ny*vnnr; - vn3 = nz*vnnr; + double shrmag,rsht; + int *ilist,*jlist,*numneigh,**firstneigh; + int *touch,**firsttouch; + double *allhistory,**firsthistory; + r = sqrt(rsq); + radsum = rwall + radius; - //**************************************** - //Normal force = Hertzian contact + DMT + damping - //**************************************** - overlap = radsum - r; - a = sqrt(R*overlap); - kn = 4.0/3.0*Emod*a; - Fhz = kn*overlap; + E = normal_coeffs[0]; - //Damping (based on Tsuji et al) - if (normaldamp == BRILLIANTOV) eta_N = a*meff*gamman; - else if (normaldamp == TSUJI) eta_N=alpha*sqrt(meff*kn); + radsum = radius + rwall; + if (rwall == 0) Reff = radius; + else Reff = radius*rwall/(radius+rwall); - Fdamp = -eta_N*vnnr; //F_nd eq 23 and Zhao eq 19 + rinv = 1.0/r; - //DMT - Fdmt = -4*MY_PI*Ecoh*R; + nx = dx*rinv; + ny = dy*rinv; + nz = dz*rinv; - Fne = Fhz + Fdmt; - Fntot = Fne + Fdamp; + // relative translational velocity - //**************************************** - //Tangential force, including shear history effects - //**************************************** + vr1 = v[0] - vwall[0]; + vr2 = v[1] - vwall[1]; + vr3 = v[2] - vwall[2]; - // tangential component - vt1 = vr1 - vn1; - vt2 = vr2 - vn2; - vt3 = vr3 - vn3; + // normal component - // relative rotational velocity + vnnr = vr1*nx + vr2*ny + vr3*nz; //v_R . n + vn1 = nx*vnnr; + vn2 = ny*vnnr; + vn3 = nz*vnnr; - wr1 = radius*omega[0] * rinv; - wr2 = radius*omega[1] * rinv; - wr3 = radius*omega[2] * rinv; + delta = radsum - r; + dR = delta*Reff; + if (normal_model == JKR){ + history[0] = 1.0; + E *= THREEQUARTERS; + R2=Reff*Reff; + coh = normal_coeffs[3]; + dR2 = dR*dR; + t0 = coh*coh*R2*R2*E; + t1 = PI27SQ*t0; + t2 = 8*dR*dR2*E*E*E; + t3 = 4*dR2*E; + sqrt1 = MAX(0, t0*(t1+2*t2)); //In case of sqrt(0) < 0 due to precision issues + t4 = cbrt(t1+t2+THREEROOT3*M_PI*sqrt(sqrt1)); + t5 = t3/t4 + t4/E; + sqrt2 = MAX(0, 2*dR + t5); + t6 = sqrt(sqrt2); + sqrt3 = MAX(0, 4*dR - t5 + SIXROOT6*coh*M_PI*R2/(E*t6)); + a = INVROOT6*(t6 + sqrt(sqrt3)); + a2 = a*a; + knfac = normal_coeffs[0]*a; + Fne = knfac*a2/Reff - TWOPI*a2*sqrt(4*coh*E/(M_PI*a)); + } + else{ + knfac = E; //Hooke + a = sqrt(dR); + if (normal_model != HOOKE){ + Fne *= a; + knfac *= a; + } + Fne = knfac*delta; + if (normal_model == DMT) + Fne -= 4*MY_PI*normal_coeffs[3]*Reff; + } - // relative tangential velocities - vtr1 = vt1 - (nz*wr2-ny*wr3); - vtr2 = vt2 - (nx*wr3-nz*wr1); - vtr3 = vt3 - (ny*wr1-nx*wr2); - vrel = vtr1*vtr1 + vtr2*vtr2 + vtr3*vtr3; - vrel = sqrt(vrel); + if (damping_model == VELOCITY){ + damp_normal = 1; + } + else if (damping_model == VISCOELASTIC){ + damp_normal = a*meff; + } + else if (damping_model == TSUJI){ + damp_normal = sqrt(meff*knfac); + } - // shear history effects - shrmag = sqrt(shear[0]*shear[0] + shear[1]*shear[1] + - shear[2]*shear[2]); + damp_normal_prefactor = normal_coeffs[1]*damp_normal; + Fdamp = -damp_normal_prefactor*vnnr; - // Rotate and update shear displacements. - // See e.g. eq. 17 of Luding, Gran. Matter 2008, v10,p235 - if (shearupdate) { - rsht = shear[0]*nx + shear[1]*ny + shear[2]*nz; - if (fabs(rsht) < EPSILON) rsht = 0; - if (rsht > 0){ - scalefac = shrmag/(shrmag - rsht); //if rhst == shrmag, contacting pair has rotated 90 deg. in one step, in which case you deserve a crash! - shear[0] -= rsht*nx; - shear[1] -= rsht*ny; - shear[2] -= rsht*nz; - //Also rescale to preserve magnitude - shear[0] *= scalefac; - shear[1] *= scalefac; - shear[2] *= scalefac; - } - //Update shear history - shear[0] += vtr1*dt; - shear[1] += vtr2*dt; - shear[2] += vtr3*dt; - } + Fntot = Fne + Fdamp; - // tangential forces = shear + tangential velocity damping - // following Zhao and Marshall Phys Fluids v20, p043302 (2008) - kt=8.0*Gmod*a; + //**************************************** + //Tangential force, including history effects + //**************************************** - eta_T = eta_N; //Based on discussion in Marshall; eta_T can also be an independent parameter - fs1 = -kt*shear[0] - eta_T*vtr1; //eq 26 - fs2 = -kt*shear[1] - eta_T*vtr2; - fs3 = -kt*shear[2] - eta_T*vtr3; + // tangential component + vt1 = vr1 - vn1; + vt2 = vr2 - vn2; + vt3 = vr3 - vn3; - // rescale frictional displacements and forces if needed - Fscrit = xmu * fabs(Fne); - // For JKR, use eq 43 of Marshall. For DMT, use Fne instead + // relative rotational velocity + wr1 = radius*omega[0] * rinv; + wr2 = radius*omega[1] * rinv; + wr3 = radius*omega[2] * rinv; - shrmag = sqrt(shear[0]*shear[0] + shear[1]*shear[1] + shear[2]*shear[2]); + // relative tangential velocities + vtr1 = vt1 - (nz*wr2-ny*wr3); + vtr2 = vt2 - (nx*wr3-nz*wr1); + vtr3 = vt3 - (ny*wr1-nx*wr2); + vrel = vtr1*vtr1 + vtr2*vtr2 + vtr3*vtr3; + vrel = sqrt(vrel); - fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); - if (fs > Fscrit) { - if (shrmag != 0.0) { - //shear[0] = (Fcrit/fs) * (shear[0] + eta_T*vtr1/kt) - eta_T*vtr1/kt; - //shear[1] = (Fcrit/fs) * (shear[1] + eta_T*vtr1/kt) - eta_T*vtr1/kt; - //shear[2] = (Fcrit/fs) * (shear[2] + eta_T*vtr1/kt) - eta_T*vtr1/kt; - shear[0] = -1.0/kt*(Fscrit*fs1/fs + eta_T*vtr1); //Same as above, but simpler (check!) - shear[1] = -1.0/kt*(Fscrit*fs2/fs + eta_T*vtr2); - shear[2] = -1.0/kt*(Fscrit*fs3/fs + eta_T*vtr3); - fs1 *= Fscrit/fs; - fs2 *= Fscrit/fs; - fs3 *= Fscrit/fs; - } else fs1 = fs2 = fs3 = 0.0; - } + if (normal_model == JKR){ + F_pulloff = 3*M_PI*coh*Reff; + Fncrit = fabs(Fne + 2*F_pulloff); + } + else if (normal_model == DMT){ + F_pulloff = 4*M_PI*coh*Reff; + Fncrit = fabs(Fne + 2*F_pulloff); + } + else{ + Fncrit = fabs(Fntot); + } - //**************************************** - // Rolling force, including shear history effects - //**************************************** + //------------------------------ + //Tangential forces + //------------------------------ + k_tangential = tangential_coeffs[0]; + damp_tangential = tangential_coeffs[1]*damp_normal_prefactor; - relrot1 = omega[0]; //- omega[j][0]; TODO: figure out how to - relrot2 = omega[1]; //- omega[j][1]; incorporate wall angular - relrot3 = omega[2]; //- omega[j][2]; velocity + int thist0 = tangential_history_index; + int thist1 = thist0 + 1; + int thist2 = thist1 + 1; - // rolling velocity, see eq. 31 of Wang et al, Particuology v 23, p 49 (2015) - // This is different from the Marshall papers, which use the Bagi/Kuhn formulation - // for rolling velocity (see Wang et al for why the latter is wrong) - vrl1 = R*(relrot2*nz - relrot3*ny); //- 0.5*((radj-radi)/radsum)*vtr1; - vrl2 = R*(relrot3*nx - relrot1*nz); //- 0.5*((radj-radi)/radsum)*vtr2; - vrl3 = R*(relrot1*ny - relrot2*nx); //- 0.5*((radj-radi)/radsum)*vtr3; - vrlmag = sqrt(vrl1*vrl1+vrl2*vrl2+vrl3*vrl3); - if (vrlmag != 0.0) vrlmaginv = 1.0/vrlmag; - else vrlmaginv = 0.0; + if (tangential_history){ + shrmag = sqrt(history[thist0]*history[thist0] + history[thist1]*history[thist1] + + history[thist2]*history[thist2]); - // Rolling displacement - rollmag = sqrt(shear[3]*shear[3] + shear[4]*shear[4] + shear[5]*shear[5]); - rolldotn = shear[3]*nx + shear[4]*ny + shear[5]*nz; + // Rotate and update displacements. + // See e.g. eq. 17 of Luding, Gran. Matter 2008, v10,p235 + if (history_update) { + rsht = history[thist0]*nx + history[thist1]*ny + history[thist2]*nz; + if (fabs(rsht) < EPSILON) rsht = 0; + if (rsht > 0){ + scalefac = shrmag/(shrmag - rsht); //if rhst == shrmag, contacting pair has rotated 90 deg. in one step, in which case you deserve a crash! + history[thist0] -= rsht*nx; + history[thist1] -= rsht*ny; + history[thist2] -= rsht*nz; + //Also rescale to preserve magnitude + history[thist0] *= scalefac; + history[thist1] *= scalefac; + history[thist2] *= scalefac; + } + //Update history + history[thist0] += vtr1*dt; + history[thist1] += vtr2*dt; + history[thist2] += vtr3*dt; + } - if (shearupdate) { - if (fabs(rolldotn) < EPSILON) rolldotn = 0; - if (rolldotn > 0){ //Rotate into tangential plane - scalefac = rollmag/(rollmag - rolldotn); - shear[3] -= rolldotn*nx; - shear[4] -= rolldotn*ny; - shear[5] -= rolldotn*nz; - //Also rescale to preserve magnitude - shear[3] *= scalefac; - shear[4] *= scalefac; - shear[5] *= scalefac; - } - shear[3] += vrl1*dt; - shear[4] += vrl2*dt; - shear[5] += vrl3*dt; - } + // tangential forces = history + tangential velocity damping + fs1 = -k_tangential*history[thist0] - damp_tangential*vtr1; + fs2 = -k_tangential*history[thist1] - damp_tangential*vtr2; + fs3 = -k_tangential*history[thist2] - damp_tangential*vtr3; - if (rollingdamp == BRILLROLL) etaR = muR*fabs(Fne); - fr1 = -kR*shear[3] - etaR*vrl1; - fr2 = -kR*shear[4] - etaR*vrl2; - fr3 = -kR*shear[5] - etaR*vrl3; + // rescale frictional displacements and forces if needed + Fscrit = tangential_coeffs[2] * Fncrit; + fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); + if (fs > Fscrit) { + if (shrmag != 0.0) { + history[thist0] = -1.0/k_tangential*(Fscrit*fs1/fs + damp_tangential*vtr1); + history[thist1] = -1.0/k_tangential*(Fscrit*fs2/fs + damp_tangential*vtr2); + history[thist2] = -1.0/k_tangential*(Fscrit*fs3/fs + damp_tangential*vtr3); + fs1 *= Fscrit/fs; + fs2 *= Fscrit/fs; + fs3 *= Fscrit/fs; + } else fs1 = fs2 = fs3 = 0.0; + } + } + else{ //Classic pair gran/hooke (no history) + fs = meff*damp_tangential*vrel; + if (vrel != 0.0) Ft = MIN(Fne,fs) / vrel; + else Ft = 0.0; + fs1 = -Ft*vtr1; + fs2 = -Ft*vtr2; + fs3 = -Ft*vtr3; + } - // rescale frictional displacements and forces if needed - Frcrit = muR * fabs(Fne); - rollmag = sqrt(shear[3]*shear[3] + shear[4]*shear[4] + shear[5]*shear[5]); + //**************************************** + // Rolling resistance + //**************************************** - fr = sqrt(fr1*fr1 + fr2*fr2 + fr3*fr3); - if (fr > Frcrit) { - if (rollmag != 0.0) { - shear[3] = -1.0/kR*(Frcrit*fr1/fr + etaR*vrl1); - shear[4] = -1.0/kR*(Frcrit*fr2/fr + etaR*vrl2); - shear[5] = -1.0/kR*(Frcrit*fr3/fr + etaR*vrl3); - fr1 *= Frcrit/fr; - fr2 *= Frcrit/fr; - fr3 *= Frcrit/fr; - } else fr1 = fr2 = fr3 = 0.0; - } + if (roll_model != ROLL_NONE){ + relrot1 = omega[0]; + relrot2 = omega[1]; + relrot3 = omega[2]; + // rolling velocity, see eq. 31 of Wang et al, Particuology v 23, p 49 (2015) + // This is different from the Marshall papers, which use the Bagi/Kuhn formulation + // for rolling velocity (see Wang et al for why the latter is wrong) + vrl1 = Reff*(relrot2*nz - relrot3*ny); //- 0.5*((radj-radi)/radsum)*vtr1; + vrl2 = Reff*(relrot3*nx - relrot1*nz); //- 0.5*((radj-radi)/radsum)*vtr2; + vrl3 = Reff*(relrot1*ny - relrot2*nx); //- 0.5*((radj-radi)/radsum)*vtr3; + vrlmag = sqrt(vrl1*vrl1+vrl2*vrl2+vrl3*vrl3); + if (vrlmag != 0.0) vrlmaginv = 1.0/vrlmag; + else vrlmaginv = 0.0; - //**************************************** - // Twisting torque, including shear history effects - //**************************************** - magtwist = relrot1*nx + relrot2*ny + relrot3*nz; //Omega_T (eq 29 of Marshall) - shear[6] += magtwist*dt; - k_Q = 0.5*kt*a*a;; //eq 32 - eta_Q = 0.5*eta_T*a*a; - magtortwist = -k_Q*shear[6] - eta_Q*magtwist;//M_t torque (eq 30) + int rhist0 = roll_history_index; + int rhist1 = rhist0 + 1; + int rhist2 = rhist1 + 1; - signtwist = (magtwist > 0) - (magtwist < 0); - Mtcrit=TWOTHIRDS*a*Fscrit;//critical torque (eq 44) - if (fabs(magtortwist) > Mtcrit){ - shear[6] = 1.0/k_Q*(Mtcrit*signtwist - eta_Q*magtwist); - magtortwist = -Mtcrit * signtwist; //eq 34 - } + // Rolling displacement + rollmag = sqrt(history[rhist0]*history[rhist0] + + history[rhist1]*history[rhist1] + + history[rhist2]*history[rhist2]); - // Apply forces & torques + rolldotn = history[rhist0]*nx + history[rhist1]*ny + history[rhist2]*nz; - fx = nx*Fntot + fs1; - fy = ny*Fntot + fs2; - fz = nz*Fntot + fs3; + if (history_update){ + if (fabs(rolldotn) < EPSILON) rolldotn = 0; + if (rolldotn > 0){ //Rotate into tangential plane + scalefac = rollmag/(rollmag - rolldotn); + history[rhist0] -= rolldotn*nx; + history[rhist1] -= rolldotn*ny; + history[rhist2] -= rolldotn*nz; + //Also rescale to preserve magnitude + history[rhist0] *= scalefac; + history[rhist1] *= scalefac; + history[rhist2] *= scalefac; + } + history[rhist0] += vrl1*dt; + history[rhist1] += vrl2*dt; + history[rhist2] += vrl3*dt; + } - f[0] += fx; - f[1] += fy; - f[2] += fz; + k_roll = roll_coeffs[0]; + damp_roll = roll_coeffs[1]; + fr1 = -k_roll*history[rhist0] - damp_roll*vrl1; + fr2 = -k_roll*history[rhist1] - damp_roll*vrl2; + fr3 = -k_roll*history[rhist2] - damp_roll*vrl3; - tor1 = ny*fs3 - nz*fs2; - tor2 = nz*fs1 - nx*fs3; - tor3 = nx*fs2 - ny*fs1; + // rescale frictional displacements and forces if needed + Frcrit = roll_coeffs[2] * Fncrit; - torque[0] -= radi*tor1; - torque[1] -= radi*tor2; - torque[2] -= radi*tor3; + fr = sqrt(fr1*fr1 + fr2*fr2 + fr3*fr3); + if (fr > Frcrit) { + if (rollmag != 0.0) { + history[rhist0] = -1.0/k_roll*(Frcrit*fr1/fr + damp_roll*vrl1); + history[rhist1] = -1.0/k_roll*(Frcrit*fr2/fr + damp_roll*vrl2); + history[rhist2] = -1.0/k_roll*(Frcrit*fr3/fr + damp_roll*vrl3); + fr1 *= Frcrit/fr; + fr2 *= Frcrit/fr; + fr3 *= Frcrit/fr; + } else fr1 = fr2 = fr3 = 0.0; + } + } - tortwist1 = magtortwist * nx; - tortwist2 = magtortwist * ny; - tortwist3 = magtortwist * nz; + //**************************************** + // Twisting torque, including history effects + //**************************************** + if (twist_model != TWIST_NONE){ + magtwist = relrot1*nx + relrot2*ny + relrot3*nz; //Omega_T (eq 29 of Marshall) + if (twist_model == TWIST_MARSHALL){ + k_twist = 0.5*k_tangential*a*a;; //eq 32 of Marshall paper + damp_twist = 0.5*damp_tangential*a*a; + mu_twist = TWOTHIRDS*a*tangential_coeffs[2]; + } + else{ + k_twist = twist_coeffs[0]; + damp_twist = twist_coeffs[1]; + mu_twist = twist_coeffs[2]; + } + if (history_update){ + history[twist_history_index] += magtwist*dt; + } + magtortwist = -k_twist*history[twist_history_index] - damp_twist*magtwist;//M_t torque (eq 30) + signtwist = (magtwist > 0) - (magtwist < 0); + Mtcrit = mu_twist*Fncrit;//critical torque (eq 44) + if (fabs(magtortwist) > Mtcrit) { + history[twist_history_index] = 1.0/k_twist*(Mtcrit*signtwist - damp_twist*magtwist); + magtortwist = -Mtcrit * signtwist; //eq 34 + } + } + // Apply forces & torques - torque[0] += tortwist1; - torque[1] += tortwist2; - torque[2] += tortwist3; + fx = nx*Fntot + fs1; + fy = ny*Fntot + fs2; + fz = nz*Fntot + fs3; - torroll1 = R*(ny*fr3 - nz*fr2); //n cross fr - torroll2 = R*(nz*fr1 - nx*fr3); - torroll3 = R*(nx*fr2 - ny*fr1); + if (peratom_flag){ + contact[1] = fx; + contact[2] = fy; + contact[3] = fz; + } - torque[0] += torroll1; - torque[1] += torroll2; - torque[2] += torroll3; + f[0] += fx; + f[1] += fy; + f[2] += fz; + tor1 = ny*fs3 - nz*fs2; + tor2 = nz*fs1 - nx*fs3; + tor3 = nx*fs2 - ny*fs1; + + torque[0] -= radius*tor1; + torque[1] -= radius*tor2; + torque[2] -= radius*tor3; + + if (twist_model != TWIST_NONE){ + tortwist1 = magtortwist * nx; + tortwist2 = magtortwist * ny; + tortwist3 = magtortwist * nz; + + torque[0] += tortwist1; + torque[1] += tortwist2; + torque[2] += tortwist3; + } + + if (roll_model != ROLL_NONE){ + torroll1 = Reff*(ny*fr3 - nz*fr2); //n cross fr + torroll2 = Reff*(nz*fr1 - nx*fr3); + torroll3 = Reff*(nx*fr2 - ny*fr1); + + torque[0] += torroll1; + torque[1] += torroll2; + torque[2] += torroll3; + } } + /* ---------------------------------------------------------------------- memory usage of local atom-based arrays ------------------------------------------------------------------------- */ @@ -1124,7 +1383,7 @@ double FixWallGran::memory_usage() { int nmax = atom->nmax; double bytes = 0.0; - if (history) bytes += nmax*sheardim * sizeof(double); // shear history + if (use_history) bytes += nmax*size_history * sizeof(double); // shear history if (fix_rigid) bytes += nmax * sizeof(int); // mass_rigid if (peratom_flag) bytes += nmax*size_peratom_cols*sizeof(double); //store contacts return bytes; @@ -1136,7 +1395,7 @@ double FixWallGran::memory_usage() void FixWallGran::grow_arrays(int nmax) { - if (history) memory->grow(shearone,nmax,sheardim,"fix_wall_gran:shearone"); + if (use_history) memory->grow(history_one,nmax,size_history,"fix_wall_gran:history_one"); if (peratom_flag){ memory->grow(array_atom,nmax,size_peratom_cols,"fix_wall_gran:array_atom"); } @@ -1148,9 +1407,9 @@ void FixWallGran::grow_arrays(int nmax) void FixWallGran::copy_arrays(int i, int j, int /*delflag*/) { - if (history) - for (int m = 0; m < sheardim; m++) - shearone[j][m] = shearone[i][m]; + if (use_history) + for (int m = 0; m < size_history; m++) + history_one[j][m] = history_one[i][m]; if (peratom_flag){ for (int m = 0; m < size_peratom_cols; m++) array_atom[j][m] = array_atom[i][m]; @@ -1163,9 +1422,9 @@ void FixWallGran::copy_arrays(int i, int j, int /*delflag*/) void FixWallGran::set_arrays(int i) { - if (history) - for (int m = 0; m < sheardim; m++) - shearone[i][m] = 0; + if (use_history) + for (int m = 0; m < size_history; m++) + history_one[i][m] = 0; if (peratom_flag){ for (int m = 0; m < size_peratom_cols; m++) array_atom[i][m] = 0; @@ -1179,9 +1438,9 @@ void FixWallGran::set_arrays(int i) int FixWallGran::pack_exchange(int i, double *buf) { int n = 0; - if (history){ - for (int m = 0; m < sheardim; m++) - buf[n++] = shearone[i][m]; + if (use_history){ + for (int m = 0; m < size_history; m++) + buf[n++] = history_one[i][m]; } if (peratom_flag){ for (int m = 0; m < size_peratom_cols; m++) @@ -1197,9 +1456,9 @@ int FixWallGran::pack_exchange(int i, double *buf) int FixWallGran::unpack_exchange(int nlocal, double *buf) { int n = 0; - if (history){ - for (int m = 0; m < sheardim; m++) - shearone[nlocal][m] = buf[n++]; + if (use_history){ + for (int m = 0; m < size_history; m++) + history_one[nlocal][m] = buf[n++]; } if (peratom_flag){ for (int m = 0; m < size_peratom_cols; m++) @@ -1214,12 +1473,12 @@ int FixWallGran::unpack_exchange(int nlocal, double *buf) int FixWallGran::pack_restart(int i, double *buf) { - if (!history) return 0; + if (!use_history) return 0; int n = 0; - buf[n++] = sheardim + 1; - for (int m = 0; m < sheardim; m++) - buf[n++] = shearone[i][m]; + buf[n++] = size_history + 1; + for (int m = 0; m < size_history; m++) + buf[n++] = history_one[i][m]; return n; } @@ -1229,7 +1488,7 @@ int FixWallGran::pack_restart(int i, double *buf) void FixWallGran::unpack_restart(int nlocal, int nth) { - if (!history) return; + if (!use_history) return; double **extra = atom->extra; @@ -1239,8 +1498,8 @@ void FixWallGran::unpack_restart(int nlocal, int nth) for (int i = 0; i < nth; i++) m += static_cast (extra[nlocal][m]); m++; - for (int i = 0; i < sheardim; i++) - shearone[nlocal][i] = extra[nlocal][m++]; + for (int i = 0; i < size_history; i++) + history_one[nlocal][i] = extra[nlocal][m++]; } /* ---------------------------------------------------------------------- @@ -1249,8 +1508,8 @@ void FixWallGran::unpack_restart(int nlocal, int nth) int FixWallGran::maxsize_restart() { - if (!history) return 0; - return 1 + sheardim; + if (!use_history) return 0; + return 1 + size_history; } /* ---------------------------------------------------------------------- @@ -1259,8 +1518,8 @@ int FixWallGran::maxsize_restart() int FixWallGran::size_restart(int /*nlocal*/) { - if (!history) return 0; - return 1 + sheardim; + if (!use_history) return 0; + return 1 + size_history; } /* ---------------------------------------------------------------------- */ @@ -1270,3 +1529,12 @@ void FixWallGran::reset_dt() dt = update->dt; } +double FixWallGran::pulloff_distance(double radius){ + double coh, E, a, dist; + coh = normal_coeffs[3]; + E = normal_coeffs[0]*THREEQUARTERS; + a = cbrt(9*M_PI*coh*radius/(4*E)); + dist = a*a/radius - 2*sqrt(M_PI*coh*a/E); + return dist; +} + diff --git a/src/GRANULAR/fix_wall_gran.h b/src/GRANULAR/fix_wall_gran.h index 4212b96544..07c6c131cf 100644 --- a/src/GRANULAR/fix_wall_gran.h +++ b/src/GRANULAR/fix_wall_gran.h @@ -54,12 +54,11 @@ class FixWallGran : public Fix { void hertz_history(double, double, double, double, double *, double, double *, double *, double *, double *, double, double, double *, double *); - void dmt_rolling(double, double, double, double, double *, double, - double *, double *, double *, double *, double, double, - double *, double *); - // void jkr_rolling(double, double, double, double, double *, double, - // double *, double *, double *, double *, double, double, - // double *, double *); + void granular(double, double, double, double, double *, double, + double *, double *, double *, double *, double, double, + double *, double *); + + double pulloff_distance(double); protected: int wallstyle,wiggle,wshear,axis; @@ -67,23 +66,43 @@ class FixWallGran : public Fix { bigint time_origin; double kn,kt,gamman,gammat,xmu; - //For DMT/ROLLING - int normaldamp, rollingdamp; - double Emod, Gmod, alpha, Ecoh, kR, muR, etaR; + //For granular + //Model choices + int normal_model, damping_model; + int tangential_model, roll_model, twist_model; + int beyond_contact; + + //History flags + int normal_history, tangential_history, roll_history, twist_history; + + //Indices of history entries + int normal_history_index; + int tangential_history_index; + int roll_history_index; + int twist_history_index; + + //Material coefficients + double Emod, poiss, Gmod; + + //Contact model coefficients + double normal_coeffs[4]; + double tangential_coeffs[3]; + double roll_coeffs[3]; + double twist_coeffs[3]; double lo,hi,cylradius; double amplitude,period,omega,vshear; double dt; char *idregion; - int history; // if particle/wall interaction stores history - int shearupdate; // flag for whether shear history is updated - int sheardim; // # of shear history values per contact + int use_history; // if particle/wall interaction stores history + int history_update; // flag for whether shear history is updated + int size_history; // # of shear history values per contact // shear history for single contact per particle - double **shearone; + double **history_one; // rigid body masses for use in granular interactions diff --git a/src/GRANULAR/fix_wall_gran_region.cpp b/src/GRANULAR/fix_wall_gran_region.cpp index 17e16cb16b..95b34e0929 100644 --- a/src/GRANULAR/fix_wall_gran_region.cpp +++ b/src/GRANULAR/fix_wall_gran_region.cpp @@ -39,7 +39,8 @@ using namespace MathConst; // same as FixWallGran -enum{HOOKE,HOOKE_HISTORY,HERTZ_HISTORY,JKR_ROLLING,DMT_ROLLING}; +enum{HOOKE,HOOKE_HISTORY,HERTZ_HISTORY,GRANULAR}; +enum {NORMAL_HOOKE, NORMAL_HERTZ, HERTZ_MATERIAL, DMT, JKR}; #define BIG 1.0e20 @@ -47,7 +48,7 @@ enum{HOOKE,HOOKE_HISTORY,HERTZ_HISTORY,JKR_ROLLING,DMT_ROLLING}; FixWallGranRegion::FixWallGranRegion(LAMMPS *lmp, int narg, char **arg) : FixWallGran(lmp, narg, arg), region(NULL), region_style(NULL), ncontact(NULL), - walls(NULL), shearmany(NULL), c2r(NULL) + walls(NULL), history_many(NULL), c2r(NULL) { restart_global = 1; motion_resetflag = 0; @@ -66,17 +67,17 @@ FixWallGranRegion::FixWallGranRegion(LAMMPS *lmp, int narg, char **arg) : // re-allocate atom-based arrays with nshear // do not register with Atom class, since parent class did that - memory->destroy(shearone); - shearone = NULL; + memory->destroy(history_one); + history_one = NULL; ncontact = NULL; walls = NULL; - shearmany = NULL; + history_many = NULL; grow_arrays(atom->nmax); // initialize shear history as if particle is not touching region - if (history) { + if (use_history) { int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) ncontact[i] = 0; @@ -92,7 +93,7 @@ FixWallGranRegion::~FixWallGranRegion() memory->destroy(ncontact); memory->destroy(walls); - memory->destroy(shearmany); + memory->destroy(history_many); } /* ---------------------------------------------------------------------- */ @@ -138,8 +139,8 @@ void FixWallGranRegion::post_force(int /*vflag*/) // do not update shear history during setup - shearupdate = 1; - if (update->setupflag) shearupdate = 0; + history_update = 1; + if (update->setupflag) history_update = 0; // if just reneighbored: // update rigid body masses for owned atoms if using FixRigid @@ -188,7 +189,12 @@ void FixWallGranRegion::post_force(int /*vflag*/) if (mask[i] & groupbit) { if (!region->match(x[i][0],x[i][1],x[i][2])) continue; - nc = region->surface(x[i][0],x[i][1],x[i][2],radius[i]); + if (pairstyle == GRANULAR && normal_model == JKR){ + nc = region->surface(x[i][0],x[i][1],x[i][2],radius[i]+pulloff_distance(radius[i])); + } + else{ + nc = region->surface(x[i][0],x[i][1],x[i][2],radius[i]); + } if (nc > tmax) error->one(FLERR,"Too many wall/gran/region contacts for one particle"); @@ -198,7 +204,7 @@ void FixWallGranRegion::post_force(int /*vflag*/) // also set c2r[] = indices into region->contact[] for each of N contacts // process zero or one contact here, otherwise invoke update_contacts() - if (history) { + if (use_history) { if (nc == 0) { ncontact[i] = 0; continue; @@ -209,8 +215,8 @@ void FixWallGranRegion::post_force(int /*vflag*/) if (ncontact[i] == 0) { ncontact[i] = 1; walls[i][0] = iwall; - for (m = 0; m < sheardim; m++) - shearmany[i][0][m] = 0.0; + for (m = 0; m < size_history; m++) + history_many[i][0][m] = 0.0; } else if (ncontact[i] > 1 || iwall != walls[i][0]) update_contacts(i,nc); } else update_contacts(i,nc); @@ -224,13 +230,20 @@ void FixWallGranRegion::post_force(int /*vflag*/) rsq = region->contact[ic].r*region->contact[ic].r; + if (pairstyle == GRANULAR && normal_model == JKR){ + if (history_many[i][c2r[ic]][0] == 0.0 && rsq > radius[i]*radius[i]){ + for (m = 0; m < size_history; m++) + history_many[i][0][m] = 0.0; + continue; + } + } + dx = region->contact[ic].delx; dy = region->contact[ic].dely; dz = region->contact[ic].delz; if (regiondynamic) region->velocity_contact(vwall, x[i], ic); - // meff = effective mass of sphere // if I is part of rigid body, use body mass @@ -259,13 +272,13 @@ void FixWallGranRegion::post_force(int /*vflag*/) else if (pairstyle == HOOKE_HISTORY) hooke_history(rsq,dx,dy,dz,vwall,v[i],f[i], omega[i],torque[i],radius[i],meff, - shearmany[i][c2r[ic]], contact); + history_many[i][c2r[ic]], contact); else if (pairstyle == HERTZ_HISTORY) hertz_history(rsq,dx,dy,dz,vwall,region->contact[ic].radius, v[i],f[i],omega[i],torque[i], - radius[i],meff,shearmany[i][c2r[ic]], contact); - else if (pairstyle == DMT_ROLLING) - dmt_rolling(rsq,dx,dy,dz,vwall,region->contact[ic].radius, v[i],f[i],omega[i],torque[i], radius[i],meff,shearmany[i][c2r[ic]], contact); + radius[i],meff,history_many[i][c2r[ic]], contact); + else if (pairstyle == GRANULAR) + granular(rsq,dx,dy,dz,vwall,region->contact[ic].radius, v[i],f[i],omega[i],torque[i], radius[i],meff,history_many[i][c2r[ic]], contact); } } @@ -294,8 +307,8 @@ void FixWallGranRegion::update_contacts(int i, int nc) if (region->contact[m].iwall == walls[i][iold]) break; if (m >= nc) { ilast = ncontact[i]-1; - for (j = 0; j < sheardim; j++) - shearmany[i][iold][j] = shearmany[i][ilast][j]; + for (j = 0; j < size_history; j++) + history_many[i][iold][j] = history_many[i][ilast][j]; walls[i][iold] = walls[i][ilast]; ncontact[i]--; } else iold++; @@ -317,8 +330,8 @@ void FixWallGranRegion::update_contacts(int i, int nc) iadd = ncontact[i]; c2r[iadd] = inew; - for (j = 0; j < sheardim; j++) - shearmany[i][iadd][j] = 0.0; + for (j = 0; j < size_history; j++) + history_many[i][iadd][j] = 0.0; walls[i][iadd] = iwall; ncontact[i]++; } @@ -333,10 +346,10 @@ double FixWallGranRegion::memory_usage() { int nmax = atom->nmax; double bytes = 0.0; - if (history) { // shear history + if (use_history) { // shear history bytes += nmax * sizeof(int); // ncontact bytes += nmax*tmax * sizeof(int); // walls - bytes += nmax*tmax*sheardim * sizeof(double); // shearmany + bytes += nmax*tmax*size_history * sizeof(double); // history_many } if (fix_rigid) bytes += nmax * sizeof(int); // mass_rigid return bytes; @@ -348,10 +361,10 @@ double FixWallGranRegion::memory_usage() void FixWallGranRegion::grow_arrays(int nmax) { - if (history) { + if (use_history) { memory->grow(ncontact,nmax,"fix_wall_gran:ncontact"); memory->grow(walls,nmax,tmax,"fix_wall_gran:walls"); - memory->grow(shearmany,nmax,tmax,sheardim,"fix_wall_gran:shearmany"); + memory->grow(history_many,nmax,tmax,size_history,"fix_wall_gran:history_many"); } if (peratom_flag){ memory->grow(array_atom,nmax,size_peratom_cols,"fix_wall_gran:array_atom"); @@ -366,12 +379,12 @@ void FixWallGranRegion::copy_arrays(int i, int j, int /*delflag*/) { int m,n,iwall; - if (history){ + if (use_history){ n = ncontact[i]; for (iwall = 0; iwall < n; iwall++) { walls[j][iwall] = walls[i][iwall]; - for (m = 0; m < sheardim; m++) - shearmany[j][iwall][m] = shearmany[i][iwall][m]; + for (m = 0; m < size_history; m++) + history_many[j][iwall][m] = history_many[i][iwall][m]; } ncontact[j] = ncontact[i]; } @@ -388,7 +401,7 @@ void FixWallGranRegion::copy_arrays(int i, int j, int /*delflag*/) void FixWallGranRegion::set_arrays(int i) { - if (history) + if (use_history) ncontact[i] = 0; if (peratom_flag){ for (int m = 0; m < size_peratom_cols; m++) @@ -405,13 +418,13 @@ int FixWallGranRegion::pack_exchange(int i, double *buf) int m; int n = 0; - if (history){ + if (use_history){ int count = ncontact[i]; buf[n++] = ubuf(count).d; for (int iwall = 0; iwall < count; iwall++) { buf[n++] = ubuf(walls[i][iwall]).d; - for (m = 0; m < sheardim; m++) - buf[n++] = shearmany[i][iwall][m]; + for (m = 0; m < size_history; m++) + buf[n++] = history_many[i][iwall][m]; } } if (peratom_flag){ @@ -432,12 +445,12 @@ int FixWallGranRegion::unpack_exchange(int nlocal, double *buf) int n = 0; - if (history){ + if (use_history){ int count = ncontact[nlocal] = (int) ubuf(buf[n++]).i; for (int iwall = 0; iwall < count; iwall++) { walls[nlocal][iwall] = (int) ubuf(buf[n++]).i; - for (m = 0; m < sheardim; m++) - shearmany[nlocal][iwall][m] = buf[n++]; + for (m = 0; m < size_history; m++) + history_many[nlocal][iwall][m] = buf[n++]; } } if (peratom_flag){ @@ -456,7 +469,7 @@ int FixWallGranRegion::pack_restart(int i, double *buf) { int m; - if (!history) return 0; + if (!use_history) return 0; int n = 1; int count = ncontact[i]; @@ -464,8 +477,8 @@ int FixWallGranRegion::pack_restart(int i, double *buf) buf[n++] = ubuf(count).d; for (int iwall = 0; iwall < count; iwall++) { buf[n++] = ubuf(walls[i][iwall]).d; - for (m = 0; m < sheardim; m++) - buf[n++] = shearmany[i][iwall][m]; + for (m = 0; m < size_history; m++) + buf[n++] = history_many[i][iwall][m]; } buf[0] = n; return n; @@ -479,7 +492,7 @@ void FixWallGranRegion::unpack_restart(int nlocal, int nth) { int k; - if (!history) return; + if (!use_history) return; double **extra = atom->extra; @@ -492,8 +505,8 @@ void FixWallGranRegion::unpack_restart(int nlocal, int nth) int count = ncontact[nlocal] = (int) ubuf(extra[nlocal][m++]).i; for (int iwall = 0; iwall < count; iwall++) { walls[nlocal][iwall] = (int) ubuf(extra[nlocal][m++]).i; - for (k = 0; k < sheardim; k++) - shearmany[nlocal][iwall][k] = extra[nlocal][m++]; + for (k = 0; k < size_history; k++) + history_many[nlocal][iwall][k] = extra[nlocal][m++]; } } @@ -503,8 +516,8 @@ void FixWallGranRegion::unpack_restart(int nlocal, int nth) int FixWallGranRegion::maxsize_restart() { - if (!history) return 0; - return 2 + tmax*(sheardim+1); + if (!use_history) return 0; + return 2 + tmax*(size_history+1); } /* ---------------------------------------------------------------------- @@ -513,8 +526,8 @@ int FixWallGranRegion::maxsize_restart() int FixWallGranRegion::size_restart(int nlocal) { - if (!history) return 0; - return 2 + ncontact[nlocal]*(sheardim+1); + if (!use_history) return 0; + return 2 + ncontact[nlocal]*(size_history+1); } /* ---------------------------------------------------------------------- diff --git a/src/GRANULAR/fix_wall_gran_region.h b/src/GRANULAR/fix_wall_gran_region.h index 8d1b6d533a..fd40e27e4c 100644 --- a/src/GRANULAR/fix_wall_gran_region.h +++ b/src/GRANULAR/fix_wall_gran_region.h @@ -54,7 +54,7 @@ class FixWallGranRegion : public FixWallGran { int tmax; // max # of region walls one particle can touch int *ncontact; // # of shear contacts per particle int **walls; // which wall each contact is with - double ***shearmany; // shear history per particle per contact + double ***history_many; // history per particle per contact int *c2r; // contact to region mapping // c2r[i] = index of Ith contact in // region-contact[] list of contacts diff --git a/src/GRANULAR/pair_granular.cpp b/src/GRANULAR/pair_granular.cpp index 5631240fea..ac0b668854 100644 --- a/src/GRANULAR/pair_granular.cpp +++ b/src/GRANULAR/pair_granular.cpp @@ -45,6 +45,7 @@ using namespace MathConst; #define SIXROOT6 14.69693845669906728801 // 6*sqrt(6) #define INVROOT6 0.40824829046386307274 // 1/sqrt(6) #define FOURTHIRDS 1.333333333333333 // 4/3 +#define THREEQUARTERS 0.75 // 3/4 #define TWOPI 6.28318530717959 // 2*PI #define EPSILON 1e-10 @@ -63,7 +64,7 @@ PairGranular::PairGranular(LAMMPS *lmp) : Pair(lmp) no_virial_fdotr_compute = 1; fix_history = NULL; - single_extra = 9; + single_extra = 12; svector = new double[single_extra]; neighprev = 0; @@ -238,10 +239,11 @@ void PairGranular::compute(int eflag, int vflag) radsum = radi + radj; E = normal_coeffs[itype][jtype][0]; - Reff = radi*radj/(radi+radj); + Reff = radi*radj/radsum; touchflag = false; if (normal_model[itype][jtype] == JKR){ + E *= THREEQUARTERS; if (touch[jj]){ R2 = Reff*Reff; coh = normal_coeffs[itype][jtype][3]; @@ -319,17 +321,17 @@ void PairGranular::compute(int eflag, int vflag) sqrt3 = MAX(0, 4*dR - t5 + SIXROOT6*coh*M_PI*R2/(E*t6)); a = INVROOT6*(t6 + sqrt(sqrt3)); a2 = a*a; - knfac = FOURTHIRDS*E*a; + knfac = normal_coeffs[itype][jtype][0]*a; Fne = knfac*a2/Reff - TWOPI*a2*sqrt(4*coh*E/(M_PI*a)); } else{ knfac = E; //Hooke + Fne = knfac*delta; a = sqrt(dR); if (normal_model[itype][jtype] != HOOKE){ Fne *= a; knfac *= a; } - Fne = knfac*delta; if (normal_model[itype][jtype] == DMT) Fne -= 4*MY_PI*normal_coeffs[itype][jtype][3]*Reff; } @@ -711,9 +713,9 @@ void PairGranular::coeff(int narg, char **arg) } else if (strcmp(arg[iarg], "hertz/material") == 0){ int num_coeffs = 3; - if (iarg + num_coeffs >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hertz option"); - normal_model_one = HERTZ; - normal_coeffs_one[0] = force->numeric(FLERR,arg[iarg+1])*FOURTHIRDS; //E + if (iarg + num_coeffs >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hertz/material option"); + normal_model_one = HERTZ_MATERIAL; + normal_coeffs_one[0] = force->numeric(FLERR,arg[iarg+1]); //E normal_coeffs_one[1] = force->numeric(FLERR,arg[iarg+2]); //damping normal_coeffs_one[2] = force->numeric(FLERR,arg[iarg+3]); //Poisson's ratio iarg += num_coeffs+1; @@ -721,10 +723,10 @@ void PairGranular::coeff(int narg, char **arg) else if (strcmp(arg[iarg], "dmt") == 0){ if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hertz option"); normal_model_one = DMT; - normal_coeffs_one[0] = force->numeric(FLERR,arg[iarg+1])*FOURTHIRDS; //E + normal_coeffs_one[0] = force->numeric(FLERR,arg[iarg+1]); //E normal_coeffs_one[1] = force->numeric(FLERR,arg[iarg+2]); //damping normal_coeffs_one[2] = force->numeric(FLERR,arg[iarg+3]); //Poisson's ratio - normal_coeffs_one[3] = force->numeric(FLERR,arg[iarg+3]); //cohesion + normal_coeffs_one[3] = force->numeric(FLERR,arg[iarg+4]); //cohesion iarg += 5; } else if (strcmp(arg[iarg], "jkr") == 0){ @@ -755,21 +757,27 @@ void PairGranular::coeff(int narg, char **arg) iarg += 1; } else if (strcmp(arg[iarg], "tangential") == 0){ - if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for tangential model"); + if (iarg + 1 >= narg) error->all(FLERR,"Illegal pair_coeff command, must specify tangential model after 'tangential' keyword"); if (strcmp(arg[iarg+1], "linear_nohistory") == 0){ + if (iarg + 3 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for tangential model"); tangential_model_one = TANGENTIAL_NOHISTORY; + tangential_coeffs_one[0] = 0; + tangential_coeffs_one[1] = force->numeric(FLERR,arg[iarg+2]); //gammat + tangential_coeffs_one[2] = force->numeric(FLERR,arg[iarg+3]); //friction coeff. + iarg += 4; } else if (strcmp(arg[iarg+1], "linear_history") == 0){ + if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for tangential model"); tangential_model_one = TANGENTIAL_HISTORY; tangential_history = 1; + tangential_coeffs_one[0] = force->numeric(FLERR,arg[iarg+2]); //kt + tangential_coeffs_one[1] = force->numeric(FLERR,arg[iarg+3]); //gammat + tangential_coeffs_one[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. + iarg += 5; } else{ error->all(FLERR, "Illegal pair_coeff command, tangential model not recognized"); } - tangential_coeffs_one[0] = force->numeric(FLERR,arg[iarg+2]); //kt - tangential_coeffs_one[1] = force->numeric(FLERR,arg[iarg+3]); //gammat - tangential_coeffs_one[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. - iarg += 5; } else if (strcmp(arg[iarg], "rolling") == 0){ if (iarg + 1 >= narg) error->all(FLERR, "Illegal pair_coeff command, not enough parameters"); @@ -842,7 +850,7 @@ void PairGranular::coeff(int narg, char **arg) if (normal_model_one != HERTZ && normal_model_one != HOOKE){ Emod[i][j] = Emod[j][i] = normal_coeffs_one[0]; poiss[i][j] = poiss[j][i] = normal_coeffs_one[2]; - normal_coeffs[i][j][0] = normal_coeffs[j][i][0] = mix_stiffnessE(Emod[i][j], Emod[i][j], poiss[i][j], poiss[i][j]); + normal_coeffs[i][j][0] = normal_coeffs[j][i][0] = FOURTHIRDS*mix_stiffnessE(Emod[i][j], Emod[i][j], poiss[i][j], poiss[i][j]); } else{ normal_coeffs[i][j][0] = normal_coeffs[j][i][0] = normal_coeffs_one[0]; @@ -1068,14 +1076,13 @@ double PairGranular::init_one(int i, int j) if (((maxrad_dynamic[i] > 0.0) && (maxrad_dynamic[j] > 0.0)) || ((maxrad_dynamic[i] > 0.0) && (maxrad_frozen[j] > 0.0)) || ((maxrad_frozen[i] > 0.0) && (maxrad_dynamic[j] > 0.0))) { // radius info about both i and j exist + cutoff = maxrad_dynamic[i]+maxrad_dynamic[j]; + pulloff = 0.0; if (normal_model[i][j] == JKR){ pulloff = pulloff_distance(maxrad_dynamic[i], maxrad_dynamic[j], i, j); cutoff += pulloff; } - else{ - pulloff = 0; - } if (normal_model[i][j] == JKR) pulloff = pulloff_distance(maxrad_frozen[i], maxrad_dynamic[j], i, j); @@ -1224,10 +1231,12 @@ double PairGranular::single(int i, int j, int itype, int jtype, radi = radius[i]; radj = radius[j]; radsum = radi + radj; - Reff = radi*radj/(radi+radj); + Reff = radi*radj/radsum; bool touchflag; + E = normal_coeffs[itype][jtype][0]; if (normal_model[itype][jtype] == JKR){ + E *= THREEQUARTERS; R2 = Reff*Reff; coh = normal_coeffs[itype][jtype][3]; a = cbrt(9.0*M_PI*coh*R2/(4*E)); @@ -1333,7 +1342,7 @@ double PairGranular::single(int i, int j, int itype, int jtype, sqrt3 = MAX(0, 4*dR - t5 + SIXROOT6*coh*M_PI*R2/(E*t6)); a = INVROOT6*(t6 + sqrt(sqrt3)); a2 = a*a; - knfac = FOURTHIRDS*E*a; + knfac = normal_coeffs[itype][jtype][0]*a; Fne = knfac*a2/Reff - TWOPI*a2*sqrt(4*coh*E/(M_PI*a)); } else{ @@ -1348,7 +1357,6 @@ double PairGranular::single(int i, int j, int itype, int jtype, Fne -= 4*MY_PI*normal_coeffs[itype][jtype][3]*Reff; } - //Consider restricting Hooke to only have 'velocity' as an option for damping? if (damping_model[itype][jtype] == VELOCITY){ damp_normal = normal_coeffs[itype][jtype][1]; } @@ -1536,6 +1544,9 @@ double PairGranular::single(int i, int j, int itype, int jtype, svector[6] = fr3; svector[7] = fr; svector[8] = magtortwist; + svector[9] = delx; + svector[10] = dely; + svector[11] = delz; return 0.0; } @@ -1614,7 +1625,7 @@ double PairGranular::pulloff_distance(double radi, double radj, int itype, int j Reff = radi*radj/(radi+radj); if (Reff <= 0) return 0; coh = normal_coeffs[itype][itype][3]; - E = normal_coeffs[itype][jtype][0]; + E = normal_coeffs[itype][jtype][0]*THREEQUARTERS; a = cbrt(9*M_PI*coh*Reff/(4*E)); return a*a/Reff - 2*sqrt(M_PI*coh*a/E); } diff --git a/src/GRANULAR/pair_granular.h b/src/GRANULAR/pair_granular.h index 625ff17c72..7bce3831f1 100644 --- a/src/GRANULAR/pair_granular.h +++ b/src/GRANULAR/pair_granular.h @@ -65,9 +65,9 @@ public: private: int size_history; - //Models choices + //Model choices int **normal_model, **damping_model; - double **tangential_model, **roll_model, **twist_model; + int **tangential_model, **roll_model, **twist_model; //History flags int normal_history, tangential_history, roll_history, twist_history; From 4e26ca29f7d43b75b729e3c23f54566dd155ba63 Mon Sep 17 00:00:00 2001 From: "Dan S. Bolintineanu" Date: Tue, 19 Feb 2019 16:47:13 -0700 Subject: [PATCH 22/44] Changes to new generalized granular pair styles and fix wall/gran -Clean-up of unused variables in code -Bug fix for single method of pair granular -Changes to fix wall/gran to fix issues with JKR -Doc page updates for fix wall/gran and fix wall/gran/region --- doc/src/fix_wall_gran.txt | 53 +++++++++++++++--------- doc/src/fix_wall_gran_region.txt | 43 ++++++++++++------- src/GRANULAR/fix_wall_gran.cpp | 16 +++---- src/GRANULAR/pair_gran_hooke_history.cpp | 4 -- src/GRANULAR/pair_granular.cpp | 50 +++++++--------------- 5 files changed, 85 insertions(+), 81 deletions(-) diff --git a/doc/src/fix_wall_gran.txt b/doc/src/fix_wall_gran.txt index 871ee2e5d1..096bec4920 100644 --- a/doc/src/fix_wall_gran.txt +++ b/doc/src/fix_wall_gran.txt @@ -11,18 +11,21 @@ fix wall/gran/omp command :h3 [Syntax:] -fix ID group-ID wall/gran fstyle Kn Kt gamma_n gamma_t xmu dampflag wallstyle args keyword values ... :pre +fix ID group-ID wall/gran fstyle fstyle_params wallstyle args keyword values ... :pre ID, group-ID are documented in "fix"_fix.html command :ulb,l wall/gran = style name of this fix command :l fstyle = style of force interactions between particles and wall :l - possible choices: hooke, hooke/history, hertz/history :pre -Kn = elastic constant for normal particle repulsion (force/distance units or pressure units - see discussion below) :l -Kt = elastic constant for tangential contact (force/distance units or pressure units - see discussion below) :l -gamma_n = damping coefficient for collisions in normal direction (1/time units or 1/time-distance units - see discussion below) :l -gamma_t = damping coefficient for collisions in tangential direction (1/time units or 1/time-distance units - see discussion below) :l -xmu = static yield criterion (unitless value between 0.0 and 1.0e4) :l -dampflag = 0 or 1 if tangential damping force is excluded or included :l + possible choices: hooke, hooke/history, hertz/history, granular :pre +fstyle_params = parameters associated with force interaction style :l + For {hooke}, {hooke/history}, and {hertz/history}, {fstyle_params} are: + Kn = elastic constant for normal particle repulsion (force/distance units or pressure units - see discussion below) + Kt = elastic constant for tangential contact (force/distance units or pressure units - see discussion below) + gamma_n = damping coefficient for collisions in normal direction (1/time units or 1/time-distance units - see discussion below) + gamma_t = damping coefficient for collisions in tangential direction (1/time units or 1/time-distance units - see discussion below) + xmu = static yield criterion (unitless value between 0.0 and 1.0e4) + dampflag = 0 or 1 if tangential damping force is excluded or included :pre + For {granular}, {fstyle_params} are set using the same syntax as for the {pair_coeff} command of "pair_style granular"_pair_granular.html :pre wallstyle = {xplane} or {yplane} or {zplane} or {zcylinder} :l args = list of arguments for a particular style :l {xplane} or {yplane} or {zplane} args = lo hi @@ -44,7 +47,10 @@ keyword = {wiggle} or {shear} :l fix 1 all wall/gran hooke 200000.0 NULL 50.0 NULL 0.5 0 xplane -10.0 10.0 fix 1 all wall/gran hooke/history 200000.0 NULL 50.0 NULL 0.5 0 zplane 0.0 NULL -fix 2 all wall/gran hooke 100000.0 20000.0 50.0 30.0 0.5 1 zcylinder 15.0 wiggle z 3.0 2.0 :pre +fix 2 all wall/gran hooke 100000.0 20000.0 50.0 30.0 0.5 1 zcylinder 15.0 wiggle z 3.0 2.0 +fix 3 all wall/gran granular hooke 1000.0 50.0 tangential linear_nohistory 1.0 0.4 zplane 0.0 NULL +fix 4 all wall/gran granular jkr 1000.0 50.0 tangential linear_history 800.0 1.0 0.5 rolling sds 500.0 200.0 0.5 twisting marshall zcylinder 15.0 wiggle z 3.0 2.0 +fix 5 all wall/gran granular dmt 1000.0 50.0 0.3 10.0 tangential linear_history 800.0 0.5 0.1 roll sds 500.0 200.0 0.1 twisting marshall zplane 0.0 NULL :pre [Description:] @@ -54,31 +60,39 @@ close enough to touch it. The nature of the wall/particle interactions are determined by the {fstyle} setting. It can be any of the styles defined by the -"pair_style granular"_pair_gran.html commands. Currently this is -{hooke}, {hooke/history}, or {hertz/history}. The equation for the +"pair_style gran/*"_pair_gran.html or the more general "pair_style granular"_pair_granular.html" +commands. Currently the options are {hooke}, {hooke/history}, or {hertz/history} for the former, +and {granular} with all the possible options of the associated {pair_coeff} command +for the latter. The equation for the force between the wall and particles touching it is the same as the -corresponding equation on the "pair_style granular"_pair_gran.html doc -page, in the limit of one of the two particles going to infinite +corresponding equation on the "pair_style gran/*"_pair_gran.html +and "pair_style_granular"_pair_granular.html doc +pages, in the limit of one of the two particles going to infinite radius and mass (flat wall). Specifically, delta = radius - r = overlap of particle with wall, m_eff = mass of particle, and the -effective radius of contact = RiRj/Ri+Rj is just the radius of the -particle. +effective radius of contact = RiRj/Ri+Rj is set to the radius +of the particle. The parameters {Kn}, {Kt}, {gamma_n}, {gamma_t}, {xmu} and {dampflag} have the same meaning and units as those specified with the -"pair_style granular"_pair_gran.html commands. This means a NULL can +"pair_style gran/*"_pair_gran.html commands. This means a NULL can be used for either {Kt} or {gamma_t} as described on that page. If a NULL is used for {Kt}, then a default value is used where {Kt} = 2/7 {Kn}. If a NULL is used for {gamma_t}, then a default value is used where {gamma_t} = 1/2 {gamma_n}. +All the model choices for cohesion, tangential friction, rolling friction +and twisting friction supported by the "pair_style granular"_pair_granular.html +through its {pair_coeff} command are also supported for walls. These are discussed +in greater detail on the doc page for "pair_style granular"_pair_granular.html. + Note that you can choose a different force styles and/or different -values for the 6 wall/particle coefficients than for particle/particle +values for the wall/particle coefficients than for particle/particle interactions. E.g. if you wish to model the wall as a different material. NOTE: As discussed on the doc page for "pair_style -granular"_pair_gran.html, versions of LAMMPS before 9Jan09 used a +gran/*"_pair_gran.html, versions of LAMMPS before 9Jan09 used a different equation for Hertzian interactions. This means Hertizian wall/particle interactions have also changed. They now include a sqrt(radius) term which was not present before. Also the previous @@ -188,6 +202,7 @@ Any dimension (xyz) that has a granular wall must be non-periodic. "fix move"_fix_move.html, "fix wall/gran/region"_fix_wall_gran_region.html, -"pair_style granular"_pair_gran.html +"pair_style gran/*"_pair_gran.html +"pair_style granular"_pair_granular.html [Default:] none diff --git a/doc/src/fix_wall_gran_region.txt b/doc/src/fix_wall_gran_region.txt index 50d744b305..6dcac2c180 100644 --- a/doc/src/fix_wall_gran_region.txt +++ b/doc/src/fix_wall_gran_region.txt @@ -10,24 +10,30 @@ fix wall/gran/region command :h3 [Syntax:] -fix ID group-ID wall/gran/region fstyle Kn Kt gamma_n gamma_t xmu dampflag wallstyle regionID :pre +fix ID group-ID wall/gran/region fstyle fstyle_params wallstyle regionID :pre ID, group-ID are documented in "fix"_fix.html command :ulb,l wall/region = style name of this fix command :l fstyle = style of force interactions between particles and wall :l - possible choices: hooke, hooke/history, hertz/history :pre -Kn = elastic constant for normal particle repulsion (force/distance units or pressure units - see discussion below) :l -Kt = elastic constant for tangential contact (force/distance units or pressure units - see discussion below) :l -gamma_n = damping coefficient for collisions in normal direction (1/time units or 1/time-distance units - see discussion below) :l -gamma_t = damping coefficient for collisions in tangential direction (1/time units or 1/time-distance units - see discussion below) :l -xmu = static yield criterion (unitless value between 0.0 and 1.0e4) :l -dampflag = 0 or 1 if tangential damping force is excluded or included :l + possible choices: hooke, hooke/history, hertz/history, granular :pre +fstyle_params = parameters associated with force interaction style :l + For {hooke}, {hooke/history}, and {hertz/history}, {fstyle_params} are: + Kn = elastic constant for normal particle repulsion (force/distance units or pressure units - see discussion below) + Kt = elastic constant for tangential contact (force/distance units or pressure units - see discussion below) + gamma_n = damping coefficient for collisions in normal direction (1/time units or 1/time-distance units - see discussion below) + gamma_t = damping coefficient for collisions in tangential direction (1/time units or 1/time-distance units - see discussion below) + xmu = static yield criterion (unitless value between 0.0 and 1.0e4) + dampflag = 0 or 1 if tangential damping force is excluded or included :pre + For {granular}, {fstyle_params} are set using the same syntax as for the {pair_coeff} command of "pair_style granular"_pair_granular.html :pre wallstyle = region (see "fix wall/gran"_fix_wall_gran.html for options for other kinds of walls) :l region-ID = region whose boundary will act as wall :l,ule [Examples:] -fix wall all wall/gran/region hooke/history 1000.0 200.0 200.0 100.0 0.5 1 region myCone :pre +fix wall all wall/gran/region hooke/history 1000.0 200.0 200.0 100.0 0.5 1 region myCone +fix 3 all wall/gran/region granular hooke 1000.0 50.0 tangential linear_nohistory 1.0 0.4 region myBox +fix 4 all wall/gran/region granular jkr 1000.0 50.0 tangential linear_history 800.0 1.0 0.5 rolling sds 500.0 200.0 0.5 twisting marshall region myCone +fix 5 all wall/gran/region granular dmt 1000.0 50.0 0.3 10.0 tangential linear_history 800.0 0.5 0.1 roll sds 500.0 200.0 0.1 twisting marshall region myCone :pre [Description:] @@ -122,11 +128,14 @@ to make the two faces differ by epsilon in their position. The nature of the wall/particle interactions are determined by the {fstyle} setting. It can be any of the styles defined by the -"pair_style granular"_pair_gran.html commands. Currently this is -{hooke}, {hooke/history}, or {hertz/history}. The equation for the +"pair_style gran/*"_pair_gran.html or the more general "pair_style granular"_pair_granular.html" +commands. Currently the options are {hooke}, {hooke/history}, or {hertz/history} for the former, +and {granular} with all the possible options of the associated {pair_coeff} command +for the latter. The equation for the force between the wall and particles touching it is the same as the -corresponding equation on the "pair_style granular"_pair_gran.html doc -page, but the effective radius is calculated using the radius of the +corresponding equation on the "pair_style gran/*"_pair_gran.html +and "pair_style_granular"_pair_granular.html doc +pages, but the effective radius is calculated using the radius of the particle and the radius of curvature of the wall at the contact point. Specifically, delta = radius - r = overlap of particle with wall, @@ -140,12 +149,18 @@ particle. The parameters {Kn}, {Kt}, {gamma_n}, {gamma_t}, {xmu} and {dampflag} have the same meaning and units as those specified with the -"pair_style granular"_pair_gran.html commands. This means a NULL can +"pair_style gran/*"_pair_gran.html commands. This means a NULL can be used for either {Kt} or {gamma_t} as described on that page. If a NULL is used for {Kt}, then a default value is used where {Kt} = 2/7 {Kn}. If a NULL is used for {gamma_t}, then a default value is used where {gamma_t} = 1/2 {gamma_n}. + +All the model choices for cohesion, tangential friction, rolling friction +and twisting friction supported by the "pair_style granular"_pair_granular.html +through its {pair_coeff} command are also supported for walls. These are discussed +in greater detail on the doc page for "pair_style granular"_pair_granular.html. + Note that you can choose a different force styles and/or different values for the 6 wall/particle coefficients than for particle/particle interactions. E.g. if you wish to model the wall as a different diff --git a/src/GRANULAR/fix_wall_gran.cpp b/src/GRANULAR/fix_wall_gran.cpp index 6e8cba7b4f..3b959e1a01 100644 --- a/src/GRANULAR/fix_wall_gran.cpp +++ b/src/GRANULAR/fix_wall_gran.cpp @@ -1021,9 +1021,8 @@ void FixWallGran::granular(double rsq, double dx, double dy, double dz, double radius, double meff, double *history, double *contact) { - int i,j,ii,jj,inum,jnum,itype,jtype; - double xtmp,ytmp,ztmp,delx,dely,delz,fx,fy,fz,nx,ny,nz; - double radi,radj,radsum,r,rinv,rsqinv; + double fx,fy,fz,nx,ny,nz; + double radsum,r,rinv; double Reff, delta, dR, dR2; double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3; @@ -1035,17 +1034,17 @@ void FixWallGran::granular(double rsq, double dx, double dy, double dz, double Fne, Ft, Fdamp, Fntot, Fncrit, Fscrit, Frcrit; double fs, fs1, fs2, fs3; - double mi,mj,damp,ccel,tor1,tor2,tor3; + double tor1,tor2,tor3; double relrot1,relrot2,relrot3,vrl1,vrl2,vrl3,vrlmag,vrlmaginv; //For JKR - double R2, coh, F_pulloff, delta_pulloff, dist_pulloff, a, a2, E; + double R2, coh, F_pulloff, a, a2, E; double t0, t1, t2, t3, t4, t5, t6; - double sqrt1, sqrt2, sqrt3, sqrt4; + double sqrt1, sqrt2, sqrt3; //Rolling double k_roll, damp_roll; - double roll1, roll2, roll3, torroll1, torroll2, torroll3; + double torroll1, torroll2, torroll3; double rollmag, rolldotn, scalefac; double fr, fr1, fr2, fr3; @@ -1055,9 +1054,6 @@ void FixWallGran::granular(double rsq, double dx, double dy, double dz, double tortwist1, tortwist2, tortwist3; double shrmag,rsht; - int *ilist,*jlist,*numneigh,**firstneigh; - int *touch,**firsttouch; - double *allhistory,**firsthistory; r = sqrt(rsq); radsum = rwall + radius; diff --git a/src/GRANULAR/pair_gran_hooke_history.cpp b/src/GRANULAR/pair_gran_hooke_history.cpp index 04df3b3d9b..344e72f8ef 100644 --- a/src/GRANULAR/pair_gran_hooke_history.cpp +++ b/src/GRANULAR/pair_gran_hooke_history.cpp @@ -349,10 +349,6 @@ void PairGranHookeHistory::settings(int narg, char **arg) { if (narg != 6) error->all(FLERR,"Illegal pair_style command"); - - - - kn = force->numeric(FLERR,arg[0]); if (strcmp(arg[1],"NULL") == 0) kt = kn * 2.0/7.0; else kt = force->numeric(FLERR,arg[1]); diff --git a/src/GRANULAR/pair_granular.cpp b/src/GRANULAR/pair_granular.cpp index ac0b668854..caef852ab0 100644 --- a/src/GRANULAR/pair_granular.cpp +++ b/src/GRANULAR/pair_granular.cpp @@ -130,7 +130,7 @@ void PairGranular::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,fx,fy,fz,nx,ny,nz; - double radi,radj,radsum,rsq,r,rinv,rsqinv; + double radi,radj,radsum,rsq,r,rinv; double Reff, delta, dR, dR2; double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3; @@ -140,19 +140,19 @@ void PairGranular::compute(int eflag, int vflag) double knfac, damp_normal, damp_normal_prefactor; double k_tangential, damp_tangential; double Fne, Ft, Fdamp, Fntot, Fncrit, Fscrit, Frcrit; - double fs, fs1, fs2, fs3; + double fs, fs1, fs2, fs3, tor1, tor2, tor3; - double mi,mj,meff,damp,ccel,tor1,tor2,tor3; - double relrot1,relrot2,relrot3,vrl1,vrl2,vrl3,vrlmag,vrlmaginv; + double mi,mj,meff; + double relrot1,relrot2,relrot3,vrl1,vrl2,vrl3; //For JKR double R2, coh, F_pulloff, delta_pulloff, dist_pulloff, a, a2, E; double t0, t1, t2, t3, t4, t5, t6; - double sqrt1, sqrt2, sqrt3, sqrt4; + double sqrt1, sqrt2, sqrt3; //Rolling double k_roll, damp_roll; - double roll1, roll2, roll3, torroll1, torroll2, torroll3; + double torroll1, torroll2, torroll3; double rollmag, rolldotn, scalefac; double fr, fr1, fr2, fr3; @@ -204,7 +204,6 @@ void PairGranular::compute(int eflag, int vflag) double *rmass = atom->rmass; int *mask = atom->mask; int nlocal = atom->nlocal; - int newton_pair = force->newton_pair; inum = list->inum; ilist = list->ilist; @@ -465,9 +464,6 @@ void PairGranular::compute(int eflag, int vflag) vrl1 = Reff*(relrot2*nz - relrot3*ny); //- 0.5*((radj-radi)/radsum)*vtr1; vrl2 = Reff*(relrot3*nx - relrot1*nz); //- 0.5*((radj-radi)/radsum)*vtr2; vrl3 = Reff*(relrot1*ny - relrot2*nx); //- 0.5*((radj-radi)/radsum)*vtr3; - vrlmag = sqrt(vrl1*vrl1+vrl2*vrl2+vrl3*vrl3); - if (vrlmag != 0.0) vrlmaginv = 1.0/vrlmag; - else vrlmaginv = 0.0; int rhist0 = roll_history_index; int rhist1 = rhist0 + 1; @@ -1192,12 +1188,12 @@ double PairGranular::single(int i, int j, int itype, int jtype, double rsq, double factor_coul, double factor_lj, double &fforce) { double radi,radj,radsum; - double r,rinv,rsqinv,delx,dely,delz, nx, ny, nz, Reff; + double r,rinv,delx,dely,delz, nx, ny, nz, Reff; double dR, dR2; double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3,wr1,wr2,wr3; double vtr1,vtr2,vtr3,vrel; - double mi,mj,meff,damp,ccel,tor1,tor2,tor3; - double relrot1,relrot2,relrot3,vrl1,vrl2,vrl3,vrlmag,vrlmaginv; + double mi,mj,meff; + double relrot1,relrot2,relrot3,vrl1,vrl2,vrl3; double knfac, damp_normal, damp_normal_prefactor; double k_tangential, damp_tangential; @@ -1207,25 +1203,22 @@ double PairGranular::single(int i, int j, int itype, int jtype, //For JKR double R2, coh, F_pulloff, delta_pulloff, dist_pulloff, a, a2, E; double delta, t0, t1, t2, t3, t4, t5, t6; - double sqrt1, sqrt2, sqrt3, sqrt4; + double sqrt1, sqrt2, sqrt3; //Rolling double k_roll, damp_roll; - double roll1, roll2, roll3, torroll1, torroll2, torroll3; - double rollmag, rolldotn, scalefac; + double rollmag; double fr, fr1, fr2, fr3; //Twisting double k_twist, damp_twist, mu_twist; double signtwist, magtwist, magtortwist, Mtcrit; - double tortwist1, tortwist2, tortwist3; - double shrmag,rsht; + double shrmag; int jnum; - int *ilist,*jlist,*numneigh,**firstneigh; - int *touch,**firsttouch; - double *history,*allhistory,**firsthistory; + int *jlist; + double *history,*allhistory; double *radius = atom->radius; radi = radius[i]; @@ -1312,8 +1305,6 @@ double PairGranular::single(int i, int j, int itype, int jtype, // if I or J part of rigid body, use body mass // if I or J is frozen, meff is other particle - int *type = atom->type; - mi = rmass[i]; mj = rmass[j]; if (fix_rigid) { @@ -1348,11 +1339,11 @@ double PairGranular::single(int i, int j, int itype, int jtype, else{ knfac = E; a = sqrt(dR); + Fne = knfac*delta; if (normal_model[itype][jtype] != HOOKE){ Fne *= a; knfac *= a; } - Fne = knfac*delta; if (normal_model[itype][jtype] == DMT) Fne -= 4*MY_PI*normal_coeffs[itype][jtype][3]*Reff; } @@ -1471,9 +1462,6 @@ double PairGranular::single(int i, int j, int itype, int jtype, vrl1 = Reff*(relrot2*nz - relrot3*ny); //- 0.5*((radj-radi)/radsum)*vtr1; vrl2 = Reff*(relrot3*nx - relrot1*nz); //- 0.5*((radj-radi)/radsum)*vtr2; vrl3 = Reff*(relrot1*ny - relrot2*nx); //- 0.5*((radj-radi)/radsum)*vtr3; - vrlmag = sqrt(vrl1*vrl1+vrl2*vrl2+vrl3*vrl3); - if (vrlmag != 0.0) vrlmaginv = 1.0/vrlmag; - else vrlmaginv = 0.0; int rhist0 = roll_history_index; int rhist1 = rhist0 + 1; @@ -1484,8 +1472,6 @@ double PairGranular::single(int i, int j, int itype, int jtype, history[rhist1]*history[rhist1] + history[rhist2]*history[rhist2]); - rolldotn = history[rhist0]*nx + history[rhist1]*ny + history[rhist2]*nz; - k_roll = roll_coeffs[itype][jtype][0]; damp_roll = roll_coeffs[itype][jtype][1]; fr1 = -k_roll*history[rhist0] - damp_roll*vrl1; @@ -1498,9 +1484,6 @@ double PairGranular::single(int i, int j, int itype, int jtype, fr = sqrt(fr1*fr1 + fr2*fr2 + fr3*fr3); if (fr > Frcrit) { if (rollmag != 0.0) { - history[rhist0] = -1.0/k_roll*(Frcrit*fr1/fr + damp_roll*vrl1); - history[rhist1] = -1.0/k_roll*(Frcrit*fr2/fr + damp_roll*vrl2); - history[rhist2] = -1.0/k_roll*(Frcrit*fr3/fr + damp_roll*vrl3); fr1 *= Frcrit/fr; fr2 *= Frcrit/fr; fr3 *= Frcrit/fr; @@ -1528,7 +1511,6 @@ double PairGranular::single(int i, int j, int itype, int jtype, signtwist = (magtwist > 0) - (magtwist < 0); Mtcrit = mu_twist*Fncrit;//critical torque (eq 44) if (fabs(magtortwist) > Mtcrit) { - history[twist_history_index] = 1.0/k_twist*(Mtcrit*signtwist - damp_twist*magtwist); magtortwist = -Mtcrit * signtwist; //eq 34 } } @@ -1621,7 +1603,7 @@ double PairGranular::mix_geom(double valii, double valjj) double PairGranular::pulloff_distance(double radi, double radj, int itype, int jtype) { - double E, coh, a, delta_pulloff, Reff; + double E, coh, a, Reff; Reff = radi*radj/(radi+radj); if (Reff <= 0) return 0; coh = normal_coeffs[itype][itype][3]; From 87a243203b52cd6755a0648b02030fd53948824d Mon Sep 17 00:00:00 2001 From: "Dan S. Bolintineanu" Date: Thu, 28 Feb 2019 16:46:21 -0700 Subject: [PATCH 23/44] Removed pair_granular.cpp/h from src directory --- src/pair_granular.cpp | 2337 ----------------------------------------- src/pair_granular.h | 120 --- 2 files changed, 2457 deletions(-) delete mode 100644 src/pair_granular.cpp delete mode 100644 src/pair_granular.h diff --git a/src/pair_granular.cpp b/src/pair_granular.cpp deleted file mode 100644 index 82a470f83b..0000000000 --- a/src/pair_granular.cpp +++ /dev/null @@ -1,2337 +0,0 @@ -/* ---------------------------------------------------------------------- -http://lammps.sandia.gov, Sandia National Laboratories -Steve Plimpton, sjplimp@sandia.gov - -Copyright (2003) Sandia Corporation. Under the terms of Contract -DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains -certain rights in this software. This software is distributed under -the GNU General Public License. - -See the README file in the top-level LAMMPS directory. -------------------------------------------------------------------------- */ - -/* ---------------------------------------------------------------------- -Contributing authors: Leo Silbert (SNL), Gary Grest (SNL), - Jeremy Lechman (SNL), Dan Bolintineanu (SNL), Ishan Srivastava (SNL) ------------------------------------------------------------------------ */ - -#include -#include -#include -#include -#include "pair_granular.h" -#include "atom.h" -#include "atom_vec.h" -#include "domain.h" -#include "force.h" -#include "update.h" -#include "modify.h" -#include "fix.h" -#include "fix_neigh_history.h" -#include "comm.h" -#include "neighbor.h" -#include "neigh_list.h" -#include "neigh_request.h" -#include "memory.h" -#include "error.h" -#include "math_const.h" - -using namespace LAMMPS_NS; -using namespace MathConst; - -#define PI27SQ 266.47931882941264802866 // 27*PI**2 -#define THREEROOT3 5.19615242270663202362 // 3*sqrt(3) -#define SIXROOT6 14.69693845669906728801 // 6*sqrt(6) -#define INVROOT6 0.40824829046386307274 // 1/sqrt(6) -#define FOURTHIRDS 1.333333333333333 // 4/3 -#define TWOPI 6.28318530717959 // 2*PI - -#define EPSILON 1e-10 - -enum {HOOKE, HERTZ, HERTZ_MATERIAL, DMT, JKR}; -enum {VELOCITY, VISCOELASTIC, TSUJI}; -enum {TANGENTIAL_NOHISTORY, TANGENTIAL_MINDLIN}; -enum {TWIST_NONE, TWIST_NOHISTORY, TWIST_SDS, TWIST_MARSHALL}; -enum {ROLL_NONE, ROLL_NOHISTORY, ROLL_SDS}; - -/* ---------------------------------------------------------------------- */ - -PairGranular::PairGranular(LAMMPS *lmp) : Pair(lmp) -{ - single_enable = 1; - no_virial_fdotr_compute = 1; - fix_history = NULL; - - single_extra = 9; - svector = new double[single_extra]; - - neighprev = 0; - - nmax = 0; - mass_rigid = NULL; - - onerad_dynamic = NULL; - onerad_frozen = NULL; - maxrad_dynamic = NULL; - maxrad_frozen = NULL; - - dt = update->dt; - - // set comm size needed by this Pair if used with fix rigid - - comm_forward = 1; - - use_history = 0; - beyond_contact = 0; - nondefault_history_transfer = 0; - tangential_history_index = 0; - roll_history_index = twist_history_index = 0; - -} - -/* ---------------------------------------------------------------------- */ -PairGranular::~PairGranular() -{ - delete [] svector; - if (fix_history) modify->delete_fix("NEIGH_HISTORY"); - - if (allocated) { - memory->destroy(setflag); - memory->destroy(cutsq); - memory->destroy(cut); - - memory->destroy(normal_coeffs); - memory->destroy(tangential_coeffs); - memory->destroy(roll_coeffs); - memory->destroy(twist_coeffs); - - delete [] onerad_dynamic; - delete [] onerad_frozen; - delete [] maxrad_dynamic; - delete [] maxrad_frozen; - } - memory->destroy(mass_rigid); -} - -void PairGranular::compute(int eflag, int vflag){ -#ifdef TEMPLATED_PAIR_GRANULAR - if (normal == HOOKE){ - if (damping == VELOCITY){ - if (tangential == TANGENTIAL_NOHISTORY){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<0,0,0,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<0,0,0,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<0,0,0,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<0,0,0,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<0,0,0,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<0,0,0,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<0,0,0,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<0,0,0,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<0,0,0,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<0,0,0,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<0,0,0,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<0,0,0,3,2>(eflag, vflag); - } - } - else if (tangential == TANGENTIAL_MINDLIN){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<0,0,1,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<0,0,1,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<0,0,1,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<0,0,1,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<0,0,1,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<0,0,1,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<0,0,1,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<0,0,1,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<0,0,1,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<0,0,1,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<0,0,1,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<0,0,1,3,2>(eflag, vflag); - } - } - } - else if (damping == VISCOELASTIC){ - if (tangential == TANGENTIAL_NOHISTORY){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<0,1,0,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<0,1,0,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<0,1,0,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<0,1,0,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<0,1,0,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<0,1,0,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<0,1,0,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<0,1,0,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<0,1,0,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<0,1,0,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<0,1,0,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<0,1,0,3,2>(eflag, vflag); - } - } - else if (tangential == TANGENTIAL_MINDLIN){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<0,1,1,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<0,1,1,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<0,1,1,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<0,1,1,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<0,1,1,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<0,1,1,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<0,1,1,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<0,1,1,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<0,1,1,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<0,1,1,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<0,1,1,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<0,1,1,3,2>(eflag, vflag); - } - } - } - else if (damping == TSUJI){ - if (tangential == TANGENTIAL_NOHISTORY){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<0,2,0,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<0,2,0,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<0,2,0,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<0,2,0,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<0,2,0,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<0,2,0,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<0,2,0,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<0,2,0,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<0,2,0,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<0,2,0,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<0,2,0,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<0,2,0,3,2>(eflag, vflag); - } - } - else if (tangential == TANGENTIAL_MINDLIN){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<0,2,1,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<0,2,1,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<0,2,1,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<0,2,1,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<0,2,1,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<0,2,1,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<0,2,1,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<0,2,1,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<0,2,1,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<0,2,1,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<0,2,1,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<0,2,1,3,2>(eflag, vflag); - } - } - } - } - else if (normal == HERTZ){ - if (damping == VELOCITY){ - if (tangential == TANGENTIAL_NOHISTORY){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<1,0,0,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<1,0,0,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<1,0,0,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<1,0,0,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<1,0,0,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<1,0,0,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<1,0,0,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<1,0,0,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<1,0,0,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<1,0,0,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<1,0,0,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<1,0,0,3,2>(eflag, vflag); - } - } - else if (tangential == TANGENTIAL_MINDLIN){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<1,0,1,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<1,0,1,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<1,0,1,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<1,0,1,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<1,0,1,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<1,0,1,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<1,0,1,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<1,0,1,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<1,0,1,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<1,0,1,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<1,0,1,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<1,0,1,3,2>(eflag, vflag); - } - } - } - else if (damping == VISCOELASTIC){ - if (tangential == TANGENTIAL_NOHISTORY){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<1,1,0,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<1,1,0,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<1,1,0,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<1,1,0,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<1,1,0,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<1,1,0,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<1,1,0,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<1,1,0,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<1,1,0,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<1,1,0,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<1,1,0,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<1,1,0,3,2>(eflag, vflag); - } - } - else if (tangential == TANGENTIAL_MINDLIN){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<1,1,1,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<1,1,1,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<1,1,1,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<1,1,1,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<1,1,1,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<1,1,1,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<1,1,1,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<1,1,1,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<1,1,1,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<1,1,1,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<1,1,1,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<1,1,1,3,2>(eflag, vflag); - } - } - } - else if (damping == TSUJI){ - if (tangential == TANGENTIAL_NOHISTORY){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<1,2,0,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<1,2,0,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<1,2,0,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<1,2,0,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<1,2,0,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<1,2,0,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<1,2,0,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<1,2,0,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<1,2,0,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<1,2,0,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<1,2,0,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<1,2,0,3,2>(eflag, vflag); - } - } - else if (tangential == TANGENTIAL_MINDLIN){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<1,2,1,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<1,2,1,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<1,2,1,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<1,2,1,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<1,2,1,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<1,2,1,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<1,2,1,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<1,2,1,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<1,2,1,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<1,2,1,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<1,2,1,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<1,2,1,3,2>(eflag, vflag); - } - } - } - } - else if (normal == HERTZ_MATERIAL){ - if (damping == VELOCITY){ - if (tangential == TANGENTIAL_NOHISTORY){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<2,0,0,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<2,0,0,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<2,0,0,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<2,0,0,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<2,0,0,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<2,0,0,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<2,0,0,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<2,0,0,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<2,0,0,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<2,0,0,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<2,0,0,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<2,0,0,3,2>(eflag, vflag); - } - } - else if (tangential == TANGENTIAL_MINDLIN){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<2,0,1,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<2,0,1,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<2,0,1,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<2,0,1,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<2,0,1,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<2,0,1,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<2,0,1,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<2,0,1,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<2,0,1,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<2,0,1,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<2,0,1,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<2,0,1,3,2>(eflag, vflag); - } - } - } - else if (damping == VISCOELASTIC){ - if (tangential == TANGENTIAL_NOHISTORY){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<2,1,0,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<2,1,0,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<2,1,0,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<2,1,0,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<2,1,0,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<2,1,0,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<2,1,0,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<2,1,0,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<2,1,0,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<2,1,0,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<2,1,0,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<2,1,0,3,2>(eflag, vflag); - } - } - else if (tangential == TANGENTIAL_MINDLIN){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<2,1,1,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<2,1,1,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<2,1,1,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<2,1,1,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<2,1,1,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<2,1,1,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<2,1,1,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<2,1,1,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<2,1,1,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<2,1,1,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<2,1,1,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<2,1,1,3,2>(eflag, vflag); - } - } - } - else if (damping == TSUJI){ - if (tangential == TANGENTIAL_NOHISTORY){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<2,2,0,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<2,2,0,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<2,2,0,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<2,2,0,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<2,2,0,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<2,2,0,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<2,2,0,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<2,2,0,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<2,2,0,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<2,2,0,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<2,2,0,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<2,2,0,3,2>(eflag, vflag); - } - } - else if (tangential == TANGENTIAL_MINDLIN){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<2,2,1,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<2,2,1,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<2,2,1,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<2,2,1,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<2,2,1,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<2,2,1,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<2,2,1,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<2,2,1,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<2,2,1,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<2,2,1,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<2,2,1,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<2,2,1,3,2>(eflag, vflag); - } - } - } - } - else if (normal == DMT){ - if (damping == VELOCITY){ - if (tangential == TANGENTIAL_NOHISTORY){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<3,0,0,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<3,0,0,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<3,0,0,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<3,0,0,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<3,0,0,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<3,0,0,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<3,0,0,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<3,0,0,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<3,0,0,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<3,0,0,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<3,0,0,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<3,0,0,3,2>(eflag, vflag); - } - } - else if (tangential == TANGENTIAL_MINDLIN){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<3,0,1,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<3,0,1,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<3,0,1,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<3,0,1,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<3,0,1,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<3,0,1,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<3,0,1,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<3,0,1,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<3,0,1,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<3,0,1,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<3,0,1,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<3,0,1,3,2>(eflag, vflag); - } - } - } - else if (damping == VISCOELASTIC){ - if (tangential == TANGENTIAL_NOHISTORY){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<3,1,0,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<3,1,0,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<3,1,0,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<3,1,0,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<3,1,0,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<3,1,0,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<3,1,0,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<3,1,0,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<3,1,0,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<3,1,0,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<3,1,0,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<3,1,0,3,2>(eflag, vflag); - } - } - else if (tangential == TANGENTIAL_MINDLIN){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<3,1,1,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<3,1,1,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<3,1,1,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<3,1,1,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<3,1,1,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<3,1,1,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<3,1,1,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<3,1,1,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<3,1,1,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<3,1,1,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<3,1,1,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<3,1,1,3,2>(eflag, vflag); - } - } - } - else if (damping == TSUJI){ - if (tangential == TANGENTIAL_NOHISTORY){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<3,2,0,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<3,2,0,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<3,2,0,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<3,2,0,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<3,2,0,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<3,2,0,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<3,2,0,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<3,2,0,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<3,2,0,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<3,2,0,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<3,2,0,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<3,2,0,3,2>(eflag, vflag); - } - } - else if (tangential == TANGENTIAL_MINDLIN){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<3,2,1,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<3,2,1,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<3,2,1,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<3,2,1,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<3,2,1,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<3,2,1,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<3,2,1,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<3,2,1,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<3,2,1,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<3,2,1,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<3,2,1,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<3,2,1,3,2>(eflag, vflag); - } - } - } - } - else if (normal == JKR){ - if (damping == VELOCITY){ - if (tangential == TANGENTIAL_NOHISTORY){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<4,0,0,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<4,0,0,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<4,0,0,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<4,0,0,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<4,0,0,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<4,0,0,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<4,0,0,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<4,0,0,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<4,0,0,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<4,0,0,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<4,0,0,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<4,0,0,3,2>(eflag, vflag); - } - } - else if (tangential == TANGENTIAL_MINDLIN){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<4,0,1,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<4,0,1,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<4,0,1,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<4,0,1,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<4,0,1,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<4,0,1,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<4,0,1,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<4,0,1,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<4,0,1,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<4,0,1,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<4,0,1,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<4,0,1,3,2>(eflag, vflag); - } - } - } - else if (damping == VISCOELASTIC){ - if (tangential == TANGENTIAL_NOHISTORY){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<4,1,0,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<4,1,0,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<4,1,0,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<4,1,0,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<4,1,0,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<4,1,0,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<4,1,0,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<4,1,0,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<4,1,0,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<4,1,0,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<4,1,0,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<4,1,0,3,2>(eflag, vflag); - } - } - else if (tangential == TANGENTIAL_MINDLIN){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<4,1,1,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<4,1,1,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<4,1,1,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<4,1,1,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<4,1,1,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<4,1,1,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<4,1,1,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<4,1,1,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<4,1,1,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<4,1,1,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<4,1,1,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<4,1,1,3,2>(eflag, vflag); - } - } - } - else if (damping == TSUJI){ - if (tangential == TANGENTIAL_NOHISTORY){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<4,2,0,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<4,2,0,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<4,2,0,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<4,2,0,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<4,2,0,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<4,2,0,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<4,2,0,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<4,2,0,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<4,2,0,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<4,2,0,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<4,2,0,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<4,2,0,3,2>(eflag, vflag); - } - } - else if (tangential == TANGENTIAL_MINDLIN){ - if (twist == TWIST_NONE){ - if (roll == ROLL_NONE) compute_templated<4,2,1,0,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<4,2,1,0,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<4,2,1,0,2>(eflag, vflag); - } - else if (twist == TWIST_NOHISTORY){ - if (roll == ROLL_NONE) compute_templated<4,2,1,1,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<4,2,1,1,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<4,2,1,1,2>(eflag, vflag); - } - else if (twist == TWIST_SDS){ - if (roll == ROLL_NONE) compute_templated<4,2,1,2,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<4,2,1,2,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<4,2,1,2,2>(eflag, vflag); - } - else if (twist == TWIST_MARSHALL){ - if (roll == ROLL_NONE) compute_templated<4,2,1,3,0>(eflag, vflag); - else if (roll == ROLL_NOHISTORY) compute_templated<4,2,1,3,1>(eflag, vflag); - else if (roll == ROLL_SDS) compute_templated<4,2,1,3,2>(eflag, vflag); - } - } - } - } - -#else - compute_untemplated(Tp_normal, Tp_damping, Tp_tangential, - Tp_roll, Tp_twist, - eflag, vflag); -#endif -} - -#ifdef TEMPLATED_PAIR_GRANULAR -template < int Tp_normal, int Tp_damping, int Tp_tangential, - int Tp_twist, int Tp_roll > -void PairGranular::compute_templated(int eflag, int vflag) -#else -void PairGranular::compute_untemplated - (int Tp_normal, int Tp_damping, int Tp_tangential, - int Tp_twist, int Tp_roll, int eflag, int vflag) -#endif -{ - int i,j,ii,jj,inum,jnum,itype,jtype; - double xtmp,ytmp,ztmp,delx,dely,delz,fx,fy,fz,nx,ny,nz; - double radi,radj,radsum,rsq,r,rinv,rsqinv; - double Reff, delta, dR, dR2; - - double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3; - double wr1,wr2,wr3; - double vtr1,vtr2,vtr3,vrel; - - double knfac, damp_normal; - double k_tangential, damp_tangential; - double Fne, Ft, Fdamp, Fntot, Fcrit, Fscrit, Frcrit; - double fs, fs1, fs2, fs3; - - //For JKR - double R2, coh, F_pulloff, delta_pulloff, dist_pulloff, a, a2, E; - double t0, t1, t2, t3, t4, t5, t6; - double sqrt1, sqrt2, sqrt3, sqrt4; - - double mi,mj,meff,damp,ccel,tor1,tor2,tor3; - double relrot1,relrot2,relrot3,vrl1,vrl2,vrl3,vrlmag,vrlmaginv; - - //Rolling - double k_roll, damp_roll; - double roll1, roll2, roll3, torroll1, torroll2, torroll3; - double rollmag, rolldotn, scalefac; - double fr, fr1, fr2, fr3; - - //Twisting - double k_twist, damp_twist, mu_twist; - double signtwist, magtwist, magtortwist, Mtcrit; - double tortwist1, tortwist2, tortwist3; - - double shrmag,rsht; - int *ilist,*jlist,*numneigh,**firstneigh; - int *touch,**firsttouch; - double *history,*allhistory,**firsthistory; - - bool touchflag; - - if (eflag || vflag) ev_setup(eflag,vflag); - else evflag = vflag_fdotr = 0; - - int historyupdate = 1; - if (update->setupflag) historyupdate = 0; - - // update rigid body info for owned & ghost atoms if using FixRigid masses - // body[i] = which body atom I is in, -1 if none - // mass_body = mass of each rigid body - - if (fix_rigid && neighbor->ago == 0){ - int tmp; - int *body = (int *) fix_rigid->extract("body",tmp); - double *mass_body = (double *) fix_rigid->extract("masstotal",tmp); - if (atom->nmax > nmax) { - memory->destroy(mass_rigid); - nmax = atom->nmax; - memory->create(mass_rigid,nmax,"pair:mass_rigid"); - } - int nlocal = atom->nlocal; - for (i = 0; i < nlocal; i++) - if (body[i] >= 0) mass_rigid[i] = mass_body[body[i]]; - else mass_rigid[i] = 0.0; - comm->forward_comm_pair(this); - } - - double **x = atom->x; - double **v = atom->v; - double **f = atom->f; - int *type = atom->type; - double **omega = atom->omega; - double **torque = atom->torque; - double *radius = atom->radius; - double *rmass = atom->rmass; - int *mask = atom->mask; - int nlocal = atom->nlocal; - int newton_pair = force->newton_pair; - - inum = list->inum; - ilist = list->ilist; - numneigh = list->numneigh; - firstneigh = list->firstneigh; - firsttouch = fix_history->firstflag; - firsthistory = fix_history->firstvalue; - - for (ii = 0; ii < inum; ii++) { - i = ilist[ii]; - itype = type[i]; - xtmp = x[i][0]; - ytmp = x[i][1]; - ztmp = x[i][2]; - itype = type[i]; - radi = radius[i]; - touch = firsttouch[i]; - allhistory = firsthistory[i]; - jlist = firstneigh[i]; - jnum = numneigh[i]; - - for (jj = 0; jj < jnum; jj++){ - j = jlist[jj]; - j &= NEIGHMASK; - - delx = xtmp - x[j][0]; - dely = ytmp - x[j][1]; - delz = ztmp - x[j][2]; - jtype = type[j]; - rsq = delx*delx + dely*dely + delz*delz; - radj = radius[j]; - radsum = radi + radj; - - E = normal_coeffs[itype][jtype][0]; - Reff = radi*radj/(radi+radj); - touchflag = false; - - if (Tp_normal == JKR){ - if (touch[jj]){ - R2 = Reff*Reff; - coh = normal_coeffs[itype][jtype][3]; - a = cbrt(9.0*M_PI*coh*R2/(4*E)); - delta_pulloff = a*a/Reff - 2*sqrt(M_PI*coh*a/E); - dist_pulloff = radsum-delta_pulloff; - touchflag = (rsq < dist_pulloff*dist_pulloff); - } - else{ - touchflag = (rsq < radsum*radsum); - } - } - else{ - touchflag = (rsq < radsum*radsum); - } - - if (!touchflag){ - // unset non-touching neighbors - touch[jj] = 0; - history = &allhistory[size_history*jj]; - for (int k = 0; k < size_history; k++) history[k] = 0.0; - } - else{ - r = sqrt(rsq); - rinv = 1.0/r; - - nx = delx*rinv; - ny = dely*rinv; - nz = delz*rinv; - - // relative translational velocity - - vr1 = v[i][0] - v[j][0]; - vr2 = v[i][1] - v[j][1]; - vr3 = v[i][2] - v[j][2]; - - // normal component - - vnnr = vr1*nx + vr2*ny + vr3*nz; //v_R . n - vn1 = nx*vnnr; - vn2 = ny*vnnr; - vn3 = nz*vnnr; - - // meff = effective mass of pair of particles - // if I or J part of rigid body, use body mass - // if I or J is frozen, meff is other particle - - mi = rmass[i]; - mj = rmass[j]; - if (fix_rigid) { - if (mass_rigid[i] > 0.0) mi = mass_rigid[i]; - if (mass_rigid[j] > 0.0) mj = mass_rigid[j]; - } - - meff = mi*mj / (mi+mj); - if (mask[i] & freeze_group_bit) meff = mj; - if (mask[j] & freeze_group_bit) meff = mi; - - delta = radsum - r; - dR = delta*Reff; - if (Tp_normal == JKR){ - touch[jj] = 1; - R2=Reff*Reff; - coh = normal_coeffs[itype][jtype][3]; - dR2 = dR*dR; - t0 = coh*coh*R2*R2*E; - t1 = PI27SQ*t0; - t2 = 8*dR*dR2*E*E*E; - t3 = 4*dR2*E; - sqrt1 = MAX(0, t0*(t1+2*t2)); //In case of sqrt(0) < 0 due to precision issues - t4 = cbrt(t1+t2+THREEROOT3*M_PI*sqrt(sqrt1)); - t5 = t3/t4 + t4/E; - sqrt2 = MAX(0, 2*dR + t5); - t6 = sqrt(sqrt2); - sqrt3 = MAX(0, 4*dR - t5 + SIXROOT6*coh*M_PI*R2/(E*t6)); - a = INVROOT6*(t6 + sqrt(sqrt3)); - a2 = a*a; - knfac = FOURTHIRDS*E*a; - Fne = knfac*a2/Reff - TWOPI*a2*sqrt(4*coh*E/(M_PI*a)); - } - else{ - knfac = E; //Hooke - Fne = knfac*delta; - if (Tp_normal != HOOKE) - a = sqrt(dR); - Fne *= a; - if (Tp_normal == DMT) - Fne -= 4*MY_PI*normal_coeffs[itype][jtype][3]*Reff; - } - - //Consider restricting Hooke to only have 'velocity' as an option for damping? - if (Tp_damping == VELOCITY){ - damp_normal = 1; - } - else if (Tp_damping == VISCOELASTIC){ - if (Tp_normal == HOOKE) a = sqrt(dR); - damp_normal = a*meff; - } - else if (Tp_damping == TSUJI){ - damp_normal = sqrt(meff*knfac); - } - - Fdamp = -normal_coeffs[itype][jtype][1]*damp_normal*vnnr; - - Fntot = Fne + Fdamp; - - //**************************************** - //Tangential force, including history effects - //**************************************** - - // tangential component - vt1 = vr1 - vn1; - vt2 = vr2 - vn2; - vt3 = vr3 - vn3; - - // relative rotational velocity - wr1 = (radi*omega[i][0] + radj*omega[j][0]); - wr2 = (radi*omega[i][1] + radj*omega[j][1]); - wr3 = (radi*omega[i][2] + radj*omega[j][2]); - - // relative tangential velocities - vtr1 = vt1 - (nz*wr2-ny*wr3); - vtr2 = vt2 - (nx*wr3-nz*wr1); - vtr3 = vt3 - (ny*wr1-nx*wr2); - vrel = vtr1*vtr1 + vtr2*vtr2 + vtr3*vtr3; - vrel = sqrt(vrel); - - // If any history is needed: - if (use_history){ - touch[jj] = 1; - history = &allhistory[size_history*jj]; - } - - - if (Tp_normal == JKR){ - F_pulloff = 3*M_PI*coh*Reff; - Fcrit = fabs(Fne + 2*F_pulloff); - } - else{ - Fcrit = fabs(Fne); - } - - //------------------------------ - //Tangential forces - //------------------------------ - k_tangential = tangential_coeffs[itype][jtype][0]; - damp_tangential = tangential_coeffs[itype][jtype][1]*damp_normal; - - if (Tp_tangential > 0){ - shrmag = sqrt(history[0]*history[0] + history[1]*history[1] + - history[2]*history[2]); - - // Rotate and update displacements. - // See e.g. eq. 17 of Luding, Gran. Matter 2008, v10,p235 - if (historyupdate) { - rsht = history[0]*nx + history[1]*ny + history[2]*nz; - if (fabs(rsht) < EPSILON) rsht = 0; - if (rsht > 0){ - scalefac = shrmag/(shrmag - rsht); //if rhst == shrmag, contacting pair has rotated 90 deg. in one step, in which case you deserve a crash! - history[0] -= rsht*nx; - history[1] -= rsht*ny; - history[2] -= rsht*nz; - //Also rescale to preserve magnitude - history[0] *= scalefac; - history[1] *= scalefac; - history[2] *= scalefac; - } - //Update history - history[0] += vtr1*dt; - history[1] += vtr2*dt; - history[2] += vtr3*dt; - } - - // tangential forces = history + tangential velocity damping - fs1 = -k_tangential*history[0] - damp_tangential*vtr1; - fs2 = -k_tangential*history[1] - damp_tangential*vtr2; - fs3 = -k_tangential*history[2] - damp_tangential*vtr3; - - // rescale frictional displacements and forces if needed - Fscrit = tangential_coeffs[itype][jtype][2] * Fcrit; - fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); - if (fs > Fscrit) { - if (shrmag != 0.0) { - history[0] = -1.0/k_tangential*(Fscrit*fs1/fs + damp_tangential*vtr1); - history[1] = -1.0/k_tangential*(Fscrit*fs2/fs + damp_tangential*vtr2); - history[2] = -1.0/k_tangential*(Fscrit*fs3/fs + damp_tangential*vtr3); - fs1 *= Fscrit/fs; - fs2 *= Fscrit/fs; - fs3 *= Fscrit/fs; - } else fs1 = fs2 = fs3 = 0.0; - } - } - else{ //Classic pair gran/hooke (no history) - fs = meff*damp_tangential*vrel; - if (vrel != 0.0) Ft = MIN(Fne,fs) / vrel; - else Ft = 0.0; - fs1 = -Ft*vtr1; - fs2 = -Ft*vtr2; - fs3 = -Ft*vtr3; - } - - //**************************************** - // Rolling resistance - //**************************************** - - if (Tp_roll != ROLL_NONE){ - relrot1 = omega[i][0] - omega[j][0]; - relrot2 = omega[i][1] - omega[j][1]; - relrot3 = omega[i][2] - omega[j][2]; - - // rolling velocity, see eq. 31 of Wang et al, Particuology v 23, p 49 (2015) - // This is different from the Marshall papers, which use the Bagi/Kuhn formulation - // for rolling velocity (see Wang et al for why the latter is wrong) - vrl1 = Reff*(relrot2*nz - relrot3*ny); //- 0.5*((radj-radi)/radsum)*vtr1; - vrl2 = Reff*(relrot3*nx - relrot1*nz); //- 0.5*((radj-radi)/radsum)*vtr2; - vrl3 = Reff*(relrot1*ny - relrot2*nx); //- 0.5*((radj-radi)/radsum)*vtr3; - vrlmag = sqrt(vrl1*vrl1+vrl2*vrl2+vrl3*vrl3); - if (vrlmag != 0.0) vrlmaginv = 1.0/vrlmag; - else vrlmaginv = 0.0; - - if (Tp_roll > 1){ - int rhist0 = roll_history_index; - int rhist1 = rhist0 + 1; - int rhist2 = rhist1 + 1; - - // Rolling displacement - rollmag = sqrt(history[rhist0]*history[rhist0] + - history[rhist1]*history[rhist1] + - history[rhist2]*history[rhist2]); - - rolldotn = history[rhist0]*nx + history[rhist1]*ny + history[rhist2]*nz; - - if (historyupdate){ - if (fabs(rolldotn) < EPSILON) rolldotn = 0; - if (rolldotn > 0){ //Rotate into tangential plane - scalefac = rollmag/(rollmag - rolldotn); - history[rhist0] -= rolldotn*nx; - history[rhist1] -= rolldotn*ny; - history[rhist2] -= rolldotn*nz; - //Also rescale to preserve magnitude - history[rhist0] *= scalefac; - history[rhist1] *= scalefac; - history[rhist2] *= scalefac; - } - history[rhist0] += vrl1*dt; - history[rhist1] += vrl2*dt; - history[rhist2] += vrl3*dt; - } - - k_roll = roll_coeffs[itype][jtype][0]; - damp_roll = roll_coeffs[itype][jtype][1]; - fr1 = -k_roll*history[rhist0] - damp_roll*vrl1; - fr2 = -k_roll*history[rhist1] - damp_roll*vrl2; - fr3 = -k_roll*history[rhist2] - damp_roll*vrl3; - - // rescale frictional displacements and forces if needed - Frcrit = roll_coeffs[itype][jtype][2] * Fcrit; - - fr = sqrt(fr1*fr1 + fr2*fr2 + fr3*fr3); - if (fr > Frcrit) { - if (rollmag != 0.0) { - history[rhist0] = -1.0/k_roll*(Frcrit*fr1/fr + damp_roll*vrl1); - history[rhist1] = -1.0/k_roll*(Frcrit*fr2/fr + damp_roll*vrl2); - history[rhist2] = -1.0/k_roll*(Frcrit*fr3/fr + damp_roll*vrl3); - fr1 *= Frcrit/fr; - fr2 *= Frcrit/fr; - fr3 *= Frcrit/fr; - } else fr1 = fr2 = fr3 = 0.0; - } - } - else{ // - fr = meff*roll_coeffs[itype][jtype][1]*vrlmag; - if (vrlmag != 0.0) fr = MIN(Fne, fr) / vrlmag; - else fr = 0.0; - fr1 = -fr*vrl1; - fr2 = -fr*vrl2; - fr3 = -fr*vrl3; - } - } - - //**************************************** - // Twisting torque, including history effects - //**************************************** - if (Tp_twist != TWIST_NONE){ - magtwist = relrot1*nx + relrot2*ny + relrot3*nz; //Omega_T (eq 29 of Marshall) - if (Tp_twist == TWIST_MARSHALL){ - k_twist = 0.5*k_tangential*a*a;; //eq 32 - damp_twist = 0.5*damp_tangential*a*a; - mu_twist = TWOTHIRDS*a; - } - else{ - k_twist = twist_coeffs[itype][jtype][0]; - damp_twist = twist_coeffs[itype][jtype][1]; - mu_twist = twist_coeffs[itype][jtype][2]; - } - if (Tp_twist > 1){ - if (historyupdate){ - history[twist_history_index] += magtwist*dt; - } - magtortwist = -k_twist*history[twist_history_index] - damp_twist*magtwist;//M_t torque (eq 30) - signtwist = (magtwist > 0) - (magtwist < 0); - Mtcrit = TWOTHIRDS*a*Fscrit;//critical torque (eq 44) - if (fabs(magtortwist) > Mtcrit) { - history[twist_history_index] = 1.0/k_twist*(Mtcrit*signtwist - damp_twist*magtwist); - magtortwist = -Mtcrit * signtwist; //eq 34 - } - } - else{ - if (magtwist > 0) magtortwist = -damp_twist*magtwist; - else magtortwist = 0; - } - } - // Apply forces & torques - - fx = nx*Fntot + fs1; - fy = ny*Fntot + fs2; - fz = nz*Fntot + fs3; - - f[i][0] += fx; - f[i][1] += fy; - f[i][2] += fz; - - tor1 = ny*fs3 - nz*fs2; - tor2 = nz*fs1 - nx*fs3; - tor3 = nx*fs2 - ny*fs1; - - torque[i][0] -= radi*tor1; - torque[i][1] -= radi*tor2; - torque[i][2] -= radi*tor3; - - if (Tp_twist != TWIST_NONE){ - tortwist1 = magtortwist * nx; - tortwist2 = magtortwist * ny; - tortwist3 = magtortwist * nz; - - torque[i][0] += tortwist1; - torque[i][1] += tortwist2; - torque[i][2] += tortwist3; - } - - if (Tp_roll != ROLL_NONE){ - torroll1 = Reff*(ny*fr3 - nz*fr2); //n cross fr - torroll2 = Reff*(nz*fr1 - nx*fr3); - torroll3 = Reff*(nx*fr2 - ny*fr1); - - torque[i][0] += torroll1; - torque[i][1] += torroll2; - torque[i][2] += torroll3; - } - - if (force->newton_pair || j < nlocal) { - f[j][0] -= fx; - f[j][1] -= fy; - f[j][2] -= fz; - - torque[j][0] -= radj*tor1; - torque[j][1] -= radj*tor2; - torque[j][2] -= radj*tor3; - - if (Tp_twist != TWIST_NONE){ - torque[j][0] -= tortwist1; - torque[j][1] -= tortwist2; - torque[j][2] -= tortwist3; - } - if (Tp_roll != ROLL_NONE){ - torque[j][0] -= torroll1; - torque[j][1] -= torroll2; - torque[j][2] -= torroll3; - } - } - if (evflag) ev_tally_xyz(i,j,nlocal,0, - 0.0,0.0,fx,fy,fz,delx,dely,delz); - } - } - } -} - - -/* ---------------------------------------------------------------------- -allocate all arrays -------------------------------------------------------------------------- */ - -void PairGranular::allocate() -{ - allocated = 1; - int n = atom->ntypes; - - memory->create(setflag,n+1,n+1,"pair:setflag"); - for (int i = 1; i <= n; i++) - for (int j = i; j <= n; j++) - setflag[i][j] = 0; - - memory->create(cutsq,n+1,n+1,"pair:cutsq"); - memory->create(cut,n+1,n+1,"pair:cut"); - memory->create(normal_coeffs,n+1,n+1,4,"pair:normal_coeffs"); - memory->create(tangential_coeffs,n+1,n+1,3,"pair:tangential_coeffs"); - memory->create(roll_coeffs,n+1,n+1,3,"pair:roll_coeffs"); - memory->create(twist_coeffs,n+1,n+1,3,"pair:twist_coeffs"); - - onerad_dynamic = new double[n+1]; - onerad_frozen = new double[n+1]; - maxrad_dynamic = new double[n+1]; - maxrad_frozen = new double[n+1]; -} - -/* ---------------------------------------------------------------------- - global settings -------------------------------------------------------------------------- */ - -void PairGranular::settings(int narg, char **arg) -{ - if (narg == 1){ - cutoff_global = force->numeric(FLERR,arg[0]); - } - else{ - cutoff_global = -1; //Will be set based on particle sizes, model choice - } - tangential_history = 0; - roll_history = twist_history = 0; - normal_set = tangential_set = damping_set = roll_set = twist_set = 0; -} - -/* ---------------------------------------------------------------------- - set coeffs for one or more type pairs -------------------------------------------------------------------------- */ - -void PairGranular::coeff(int narg, char **arg) -{ - double normal_coeffs_local[4]; - double tangential_coeffs_local[4]; - double roll_coeffs_local[4]; - double twist_coeffs_local[4]; - - if (narg < 2) - error->all(FLERR,"Incorrect args for pair coefficients"); - - if (!allocated) allocate(); - - int ilo,ihi,jlo,jhi; - force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); - force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); - - int iarg = 2; - while (iarg < narg){ - if (strcmp(arg[iarg], "hooke") == 0){ - if (iarg + 2 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hooke option"); - if (!normal_set) normal = HOOKE; - else if (normal != HOOKE) error->all(FLERR, "Illegal pair_coeff command, choice of normal contact model must be the same for all types"); - normal_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1]); //kn - normal_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //damping - normal_set = 1; - iarg += 3; - } - else if (strcmp(arg[iarg], "hertz") == 0){ - int num_coeffs = 2; - if (iarg + num_coeffs >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hertz option"); - if (!normal_set) normal = HERTZ; - else if (normal_set && normal != HERTZ) if (normal != HOOKE) error->all(FLERR, "Illegal pair_coeff command, choice of normal contact model must be the same for all types"); - normal_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1]); //kn - normal_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //damping - normal_set = 1; - iarg += num_coeffs+1; - } - else if (strcmp(arg[iarg], "hertz/material") == 0){ - int num_coeffs = 3; - if (iarg + num_coeffs >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hertz option"); - if (!normal_set) normal = HERTZ_MATERIAL; - else if (normal != HERTZ) if (normal != HOOKE) error->all(FLERR, "Illegal pair_coeff command, choice of normal contact model must be the same for all types"); - normal_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1])*FOURTHIRDS; //E - normal_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //damping - normal_coeffs_local[2] = force->numeric(FLERR,arg[iarg+3]); //G - normal_set = 1; - iarg += num_coeffs+1; - } - else if (strcmp(arg[iarg], "dmt") == 0){ - if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hertz option"); - if (!normal_set) normal = DMT; - else if (normal != DMT) error->all(FLERR, "Illegal pair_coeff command, choice of normal contact model must be the same for all types"); - normal_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1])*FOURTHIRDS; //E - normal_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //damping - normal_coeffs_local[2] = force->numeric(FLERR,arg[iarg+3]); //G - normal_coeffs_local[3] = force->numeric(FLERR,arg[iarg+3]); //cohesion - normal_set = 1; - iarg += 5; - } - else if (strcmp(arg[iarg], "jkr") == 0){ - if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for JKR option"); - beyond_contact = 1; - if (!normal_set) normal = JKR; - else if (normal != JKR) error->all(FLERR, "Illegal pair_coeff command, choice of normal contact model must be the same for all types"); - normal_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1]); //E - normal_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //damping - normal_coeffs_local[2] = force->numeric(FLERR,arg[iarg+3]); //G - normal_coeffs_local[3] = force->numeric(FLERR,arg[iarg+4]); //cohesion - normal_set = 1; - iarg += 5; - } - else if (strcmp(arg[iarg], "damp") == 0){ - if (iarg+1 >= narg) error->all(FLERR, "Illegal pair_coeff command, not enough parameters provided for damping model"); - if (strcmp(arg[iarg+1], "velocity") == 0){ - if (!damping_set) damping = VELOCITY; - else if (damping != VELOCITY) error->all(FLERR, "Illegal pair_coeff command, choice of damping contact model must be the same for all types"); - } - else if (strcmp(arg[iarg+1], "viscoelastic") == 0){ - if (!damping_set) damping = VISCOELASTIC; - else if (damping != VISCOELASTIC) error->all(FLERR, "Illegal pair_coeff command, choice of damping contact model must be the same for all types"); - } - else if (strcmp(arg[iarg+1], "tsuji") == 0){ - if (!damping_set) damping = TSUJI; - if (damping != TSUJI) error->all(FLERR, "Illegal pair_coeff command, choice of damping contact model must be the same for all types"); - } - damping_set = 1; - iarg += 2; - } - else if (strcmp(arg[iarg], "tangential") == 0){ - if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for tangential model"); - if (strcmp(arg[iarg+1], "nohistory") == 0){ - if (!tangential_set) tangential = TANGENTIAL_NOHISTORY; - else if (tangential != TANGENTIAL_NOHISTORY) error->all(FLERR, "Illegal pair_coeff command, choice of tangential contact model must be the same for all types"); - } - else if (strcmp(arg[iarg+1], "mindlin") == 0){ - if (!tangential_set) tangential = TANGENTIAL_MINDLIN; - else if (tangential != TANGENTIAL_MINDLIN) error->all(FLERR, "Illegal pair_coeff command, choice of tangential contact model must be the same for all types");; - tangential_history = 1; - } - else{ - error->all(FLERR, "Illegal pair_coeff command, tangential model not recognized"); - } - tangential_set = 1; - tangential_coeffs_local[0] = force->numeric(FLERR,arg[iarg+2]); //kt - tangential_coeffs_local[1] = force->numeric(FLERR,arg[iarg+3]); //gammat - tangential_coeffs_local[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. - iarg += 5; - } - else if (strcmp(arg[iarg], "rolling") == 0){ - if (iarg + 1 >= narg) error->all(FLERR, "Illegal pair_coeff command, not enough parameters"); - if (strcmp(arg[iarg+1], "none") == 0){ - if (!roll_set) roll = ROLL_NONE; - else if (roll != ROLL_NONE) error->all(FLERR, "Illegal pair_coeff command, choice of rolling friction model must be the same for all types"); - iarg += 2; - } - else{ - if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for rolling model"); - if (strcmp(arg[iarg+1], "nohistory") == 0){ - if (!roll_set) roll = ROLL_NOHISTORY; - else if (roll != ROLL_NOHISTORY) error->all(FLERR, "Illegal pair_coeff command, choice of rolling friction model must be the same for all types"); - } - else if (strcmp(arg[iarg+1], "sds") == 0){ - if (!roll_set) roll = ROLL_SDS; - else if (roll != ROLL_SDS) error->all(FLERR, "Illegal pair_coeff command, choice of rolling friction model must be the same for all types"); - roll_history = 1; - } - else{ - error->all(FLERR, "Illegal pair_coeff command, rolling friction model not recognized"); - } - roll_set =1 ; - roll_coeffs_local[0] = force->numeric(FLERR,arg[iarg+2]); //kR - roll_coeffs_local[1] = force->numeric(FLERR,arg[iarg+3]); //gammaR - roll_coeffs_local[2] = force->numeric(FLERR,arg[iarg+4]); //rolling friction coeff. - iarg += 5; - } - } - else if (strcmp(arg[iarg], "twisting") == 0){ - if (iarg + 1 >= narg) error->all(FLERR, "Illegal pair_coeff command, not enough parameters"); - if (strcmp(arg[iarg+1], "none") == 0){ - if (!twist_set) twist = TWIST_NONE; - else if (twist != TWIST_NONE) error->all(FLERR, "Illegal pair_coeff command, choice of twisting friction model must be the same for all types"); - iarg += 2; - } - else if (strcmp(arg[iarg+1], "marshall") == 0){ - if (!twist_set) twist = TWIST_MARSHALL; - else if (twist != TWIST_MARSHALL) error->all(FLERR, "Illegal pair_coeff command, choice of twisting friction model must be the same for all types"); - twist_history = 1; - twist_set = 1; - iarg += 2; - } - else{ - if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for twist model"); - else if (strcmp(arg[iarg+1], "nohistory") == 0){ - if (!twist_set) twist = TWIST_NOHISTORY; - if (twist != TWIST_NOHISTORY) error->all(FLERR, "Illegal pair_coeff command, choice of twisting friction model must be the same for all types"); - } - else if (strcmp(arg[iarg+1], "sds") == 0){ - if (!twist_set) twist = TWIST_SDS; - else if (twist != TWIST_SDS) error->all(FLERR, "Illegal pair_coeff command, choice of twisting friction model must be the same for all types"); - twist_history = 1; - } - else{ - error->all(FLERR, "Illegal pair_coeff command, twisting friction model not recognized"); - } - twist_set = 1; - twist_coeffs_local[0] = force->numeric(FLERR,arg[iarg+2]); //kt - twist_coeffs_local[1] = force->numeric(FLERR,arg[iarg+3]); //gammat - twist_coeffs_local[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. - iarg += 5; - } - } - else error->all(FLERR, "Illegal pair coeff command"); - } - - //It is an error not to specify normal or tangential model - if (!normal_set) error->all(FLERR, "Illegal pair coeff command, must specify normal contact model"); - if (!tangential_set) error->all(FLERR, "Illegal pair coeff command, must specify tangential contact model"); - - //If unspecified, set damping to VISCOELASTIC, twist/roll to NONE (cannot be changed by subsequent pair_coeff commands) - if (!damping_set) damping = VISCOELASTIC; - if (!roll_set) roll = ROLL_NONE; - if (!twist_set) twist = TWIST_NONE; - damping_set = roll_set = twist_set = 1; - - int count = 0; - double damp; - if (damping == TSUJI){ - double cor; - cor = normal_coeffs_local[1]; - damp = 1.2728-4.2783*cor+11.087*pow(cor,2)-22.348*pow(cor,3)+ - 27.467*pow(cor,4)-18.022*pow(cor,5)+ - 4.8218*pow(cor,6); - } - else damp = normal_coeffs_local[1]; - - for (int i = ilo; i <= ihi; i++) { - for (int j = MAX(jlo,i); j <= jhi; j++) { - normal_coeffs[i][j][0] = normal_coeffs[j][i][0] = normal_coeffs_local[0]; - normal_coeffs[i][j][1] = normal_coeffs[j][i][1] = damp; - if (normal != HERTZ && normal != HOOKE) normal_coeffs[i][j][2] = normal_coeffs_local[2]; - if ((normal == JKR) || (normal == DMT)) - normal_coeffs[i][j][3] = normal_coeffs[j][i][3] = normal_coeffs_local[3]; - - for (int k = 0; k < 3; k++) - tangential_coeffs[i][j][k] = tangential_coeffs[j][i][k] = tangential_coeffs_local[k]; - - if (roll != ROLL_NONE) - for (int k = 0; k < 3; k++) - roll_coeffs[i][j][k] = roll_coeffs[j][i][k] = roll_coeffs_local[k]; - - if (twist != TWIST_NONE && twist != TWIST_MARSHALL) - for (int k = 0; k < 3; k++) - twist_coeffs[i][j][k] = twist_coeffs[j][i][k] = twist_coeffs_local[k]; - - setflag[i][j] = 1; - count++; - } - } - - if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); -} - -/* ---------------------------------------------------------------------- - init specific to this pair style -------------------------------------------------------------------------- */ - -void PairGranular::init_style() -{ - int i; - - // error and warning checks - - if (!atom->radius_flag || !atom->rmass_flag) - error->all(FLERR,"Pair granular requires atom attributes radius, rmass"); - if (comm->ghost_velocity == 0) - error->all(FLERR,"Pair granular requires ghost atoms store velocity"); - - // Determine whether we need a granular neigh list, how large it needs to be - use_history = tangential_history || roll_history || twist_history; - - //For JKR, will need fix/neigh/history to keep track of touch arrays - if (normal == JKR) use_history = 1; - - size_history = 3*tangential_history + 3*roll_history + twist_history; - - //Determine location of tangential/roll/twist histories in array - if (roll_history){ - if (tangential_history) roll_history_index = 3; - else roll_history_index = 0; - } - if (twist_history){ - if (tangential_history){ - if (roll_history) twist_history_index = 6; - else twist_history_index = 3; - } - else{ - if (roll_history) twist_history_index = 3; - else twist_history_index = 0; - } - } - - int irequest = neighbor->request(this,instance_me); - neighbor->requests[irequest]->size = 1; - if (use_history) neighbor->requests[irequest]->history = 1; - - dt = update->dt; - - // if history is stored: - // if first init, create Fix needed for storing history - - if (use_history && fix_history == NULL) { - char dnumstr[16]; - sprintf(dnumstr,"%d",size_history); - char **fixarg = new char*[4]; - fixarg[0] = (char *) "NEIGH_HISTORY"; - fixarg[1] = (char *) "all"; - fixarg[2] = (char *) "NEIGH_HISTORY"; - fixarg[3] = dnumstr; - modify->add_fix(4,fixarg,1); - delete [] fixarg; - fix_history = (FixNeighHistory *) modify->fix[modify->nfix-1]; - fix_history->pair = this; - } - - // check for FixFreeze and set freeze_group_bit - - for (i = 0; i < modify->nfix; i++) - if (strcmp(modify->fix[i]->style,"freeze") == 0) break; - if (i < modify->nfix) freeze_group_bit = modify->fix[i]->groupbit; - else freeze_group_bit = 0; - - // check for FixRigid so can extract rigid body masses - - fix_rigid = NULL; - for (i = 0; i < modify->nfix; i++) - if (modify->fix[i]->rigid_flag) break; - if (i < modify->nfix) fix_rigid = modify->fix[i]; - - // check for FixPour and FixDeposit so can extract particle radii - - int ipour; - for (ipour = 0; ipour < modify->nfix; ipour++) - if (strcmp(modify->fix[ipour]->style,"pour") == 0) break; - if (ipour == modify->nfix) ipour = -1; - - int idep; - for (idep = 0; idep < modify->nfix; idep++) - if (strcmp(modify->fix[idep]->style,"deposit") == 0) break; - if (idep == modify->nfix) idep = -1; - - // set maxrad_dynamic and maxrad_frozen for each type - // include future FixPour and FixDeposit particles as dynamic - - int itype; - for (i = 1; i <= atom->ntypes; i++) { - onerad_dynamic[i] = onerad_frozen[i] = 0.0; - if (ipour >= 0) { - itype = i; - double radmax = *((double *) modify->fix[ipour]->extract("radius",itype)); - if (normal == JKR) radmax = radmax - 0.5*pulloff_distance(radmax, itype); - onerad_dynamic[i] = radmax; - } - if (idep >= 0) { - itype = i; - double radmax = *((double *) modify->fix[idep]->extract("radius",itype)); - if (normal == JKR) radmax = radmax - 0.5*pulloff_distance(radmax, itype); - onerad_dynamic[i] = radmax; - } - } - - double *radius = atom->radius; - int *mask = atom->mask; - int *type = atom->type; - int nlocal = atom->nlocal; - - for (i = 0; i < nlocal; i++){ - double radius_cut = radius[i]; - if (normal == JKR){ - radius_cut = radius[i] - 0.5*pulloff_distance(radius[i], type[i]); - } - if (mask[i] & freeze_group_bit){ - onerad_frozen[type[i]] = MAX(onerad_frozen[type[i]],radius_cut); - } - else{ - onerad_dynamic[type[i]] = MAX(onerad_dynamic[type[i]],radius_cut); - } - } - - MPI_Allreduce(&onerad_dynamic[1],&maxrad_dynamic[1],atom->ntypes, - MPI_DOUBLE,MPI_MAX,world); - MPI_Allreduce(&onerad_frozen[1],&maxrad_frozen[1],atom->ntypes, - MPI_DOUBLE,MPI_MAX,world); - - // set fix which stores history info - - if (size_history > 0){ - int ifix = modify->find_fix("NEIGH_HISTORY"); - if (ifix < 0) error->all(FLERR,"Could not find pair fix neigh history ID"); - fix_history = (FixNeighHistory *) modify->fix[ifix]; - } -} - -/* ---------------------------------------------------------------------- - init for one type pair i,j and corresponding j,i -------------------------------------------------------------------------- */ - -double PairGranular::init_one(int i, int j) -{ - double cutoff; - if (setflag[i][j] == 0) { - - if (normal != HOOKE && normal != HERTZ){ - normal_coeffs[i][j][0] = normal_coeffs[j][i][0] = mix_stiffnessE(normal_coeffs[i][i][0], normal_coeffs[j][j][0], - normal_coeffs[i][i][2], normal_coeffs[j][j][2]); - normal_coeffs[i][j][2] = normal_coeffs[j][i][2] = mix_stiffnessG(normal_coeffs[i][i][0], normal_coeffs[j][j][0], - normal_coeffs[i][i][2], normal_coeffs[j][j][2]); - } - else{ - normal_coeffs[i][j][0] = normal_coeffs[j][i][0] = mix_geom(normal_coeffs[i][i][0], normal_coeffs[j][j][0]); - } - - normal_coeffs[i][j][1] = normal_coeffs[j][i][1] = mix_geom(normal_coeffs[i][i][1], normal_coeffs[j][j][1]); - if ((normal == JKR) || (normal == DMT)) - normal_coeffs[i][j][3] = normal_coeffs[j][i][3] = mix_geom(normal_coeffs[i][i][3], normal_coeffs[j][j][3]); - - for (int k = 0; k < 3; k++) - tangential_coeffs[i][j][k] = tangential_coeffs[j][i][k] = mix_geom(tangential_coeffs[i][i][k], tangential_coeffs[j][j][k]); - - - if (roll != ROLL_NONE){ - for (int k = 0; k < 3; k++) - roll_coeffs[i][j][k] = roll_coeffs[j][i][k] = mix_geom(roll_coeffs[i][i][k], roll_coeffs[j][j][k]); - } - - if (twist != TWIST_NONE && twist != TWIST_MARSHALL){ - for (int k = 0; k < 3; k++) - twist_coeffs[i][j][k] = twist_coeffs[j][i][k] = mix_geom(twist_coeffs[i][i][k], twist_coeffs[j][j][k]); - } - } - - // It is possible that cut[i][j] at this point is still 0.0. This can happen when - // there is a future fix_pour after the current run. A cut[i][j] = 0.0 creates - // problems because neighbor.cpp uses min(cut[i][j]) to decide on the bin size - // To avoid this issue, for cases involving cut[i][j] = 0.0 (possible only - // if there is no current information about radius/cutoff of type i and j). - // we assign cutoff = max(cut[i][j]) for i,j such that cut[i][j] > 0.0. - - if (cutoff_global < 0){ - if (((maxrad_dynamic[i] > 0.0) && (maxrad_dynamic[j] > 0.0)) || - ((maxrad_dynamic[i] > 0.0) && (maxrad_frozen[j] > 0.0)) || - ((maxrad_frozen[i] > 0.0) && (maxrad_dynamic[j] > 0.0))) { // radius info about both i and j exist - cutoff = maxrad_dynamic[i]+maxrad_dynamic[j]; - cutoff = MAX(cutoff,maxrad_frozen[i]+maxrad_dynamic[j]); - cutoff = MAX(cutoff,maxrad_dynamic[i]+maxrad_frozen[j]); - } - else { // radius info about either i or j does not exist (i.e. not present and not about to get poured; set to largest value to not interfere with neighbor list) - double cutmax = 0.0; - for (int k = 1; k <= atom->ntypes; k++) { - cutmax = MAX(cutmax,2.0*maxrad_dynamic[k]); - cutmax = MAX(cutmax,2.0*maxrad_frozen[k]); - } - cutoff = cutmax; - } - } - else{ - cutoff = cutoff_global; - } - return cutoff; -} - - -/* ---------------------------------------------------------------------- - proc 0 writes to restart file - ------------------------------------------------------------------------- */ - -void PairGranular::write_restart(FILE *fp) -{ - int i,j; - fwrite(&normal,sizeof(int),1,fp); - fwrite(&damping,sizeof(int),1,fp); - fwrite(&tangential,sizeof(int),1,fp); - fwrite(&roll,sizeof(int),1,fp); - fwrite(&twist,sizeof(int),1,fp); - for (i = 1; i <= atom->ntypes; i++) { - for (j = i; j <= atom->ntypes; j++) { - fwrite(&setflag[i][j],sizeof(int),1,fp); - if (setflag[i][j]) { - fwrite(&normal_coeffs[i][j],sizeof(double),4,fp); - fwrite(&tangential_coeffs[i][j],sizeof(double),3,fp); - fwrite(&roll_coeffs[i][j],sizeof(double),3,fp); - fwrite(&twist_coeffs[i][j],sizeof(double),3,fp); - fwrite(&cut[i][j],sizeof(double),1,fp); - } - } - } -} - -/* ---------------------------------------------------------------------- - proc 0 reads from restart file, bcasts - ------------------------------------------------------------------------- */ - -void PairGranular::read_restart(FILE *fp) -{ - allocate(); - int i,j; - int me = comm->me; - if (me == 0){ - fread(&normal,sizeof(int),1,fp); - fread(&damping,sizeof(int),1,fp); - fread(&tangential,sizeof(int),1,fp); - fread(&roll,sizeof(int),1,fp); - fread(&twist,sizeof(int),1,fp); - } - MPI_Bcast(&normal,1,MPI_INT,0,world); - MPI_Bcast(&damping,1,MPI_INT,0,world); - MPI_Bcast(&tangential,1,MPI_INT,0,world); - MPI_Bcast(&roll,1,MPI_INT,0,world); - MPI_Bcast(&twist,1,MPI_INT,0,world); - for (i = 1; i <= atom->ntypes; i++) { - for (j = i; j <= atom->ntypes; j++) { - if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp); - MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world); - if (setflag[i][j]) { - if (me == 0) { - fread(&normal_coeffs[i][j],sizeof(double),4,fp); - fread(&tangential_coeffs[i][j],sizeof(double),3,fp); - fread(&roll_coeffs[i][j],sizeof(double),3,fp); - fread(&twist_coeffs[i][j],sizeof(double),3,fp); - fread(&cut[i][j],sizeof(double),1,fp); - } - MPI_Bcast(&normal_coeffs[i][j],4,MPI_DOUBLE,0,world); - MPI_Bcast(&tangential_coeffs[i][j],3,MPI_DOUBLE,0,world); - MPI_Bcast(&roll_coeffs[i][j],3,MPI_DOUBLE,0,world); - MPI_Bcast(&twist_coeffs[i][j],3,MPI_DOUBLE,0,world); - MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); - } - } - } -} - - -/* ---------------------------------------------------------------------- */ - -void PairGranular::reset_dt() -{ - dt = update->dt; -} - -/* ---------------------------------------------------------------------- */ - -double PairGranular::single(int i, int j, int itype, int jtype, - double rsq, double factor_coul, double factor_lj, double &fforce) -{ - double radi,radj,radsum; - double r,rinv,rsqinv,delx,dely,delz, nx, ny, nz, Reff; - double dR, dR2; - double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3,wr1,wr2,wr3; - double vtr1,vtr2,vtr3,vrel; - double mi,mj,meff,damp,ccel,tor1,tor2,tor3; - double relrot1,relrot2,relrot3,vrl1,vrl2,vrl3,vrlmag,vrlmaginv; - - double knfac, damp_normal; - double k_tangential, damp_tangential; - double Fne, Ft, Fdamp, Fntot, Fcrit, Fscrit, Frcrit; - double fs, fs1, fs2, fs3; - - //For JKR - double R2, coh, F_pulloff, delta_pulloff, dist_pulloff, a, a2, E; - double delta, t0, t1, t2, t3, t4, t5, t6; - double sqrt1, sqrt2, sqrt3, sqrt4; - - - //Rolling - double k_roll, damp_roll; - double roll1, roll2, roll3, torroll1, torroll2, torroll3; - double rollmag, rolldotn, scalefac; - double fr, fr1, fr2, fr3; - - //Twisting - double k_twist, damp_twist, mu_twist; - double signtwist, magtwist, magtortwist, Mtcrit; - double tortwist1, tortwist2, tortwist3; - - double shrmag,rsht; - int jnum; - int *ilist,*jlist,*numneigh,**firstneigh; - int *touch,**firsttouch; - double *history,*allhistory,**firsthistory; - - double *radius = atom->radius; - radi = radius[i]; - radj = radius[j]; - radsum = radi + radj; - Reff = radi*radj/(radi+radj); - - bool touchflag; - if (normal == JKR){ - R2 = Reff*Reff; - coh = normal_coeffs[itype][jtype][3]; - a = cbrt(9.0*M_PI*coh*R2/(4*E)); - delta_pulloff = a*a/Reff - 2*sqrt(M_PI*coh*a/E); - dist_pulloff = radsum+delta_pulloff; - touchflag = (rsq <= dist_pulloff*dist_pulloff); - } - else{ - touchflag = (rsq <= radsum*radsum); - } - - if (touchflag){ - fforce = 0.0; - for (int m = 0; m < single_extra; m++) svector[m] = 0.0; - return 0.0; - } - - double **x = atom->x; - delx = x[i][0] - x[j][0]; - dely = x[i][1] - x[j][1]; - delz = x[i][2] - x[j][2]; - r = sqrt(rsq); - rinv = 1.0/r; - - nx = delx*rinv; - ny = dely*rinv; - nz = delz*rinv; - - // relative translational velocity - - double **v = atom->v; - vr1 = v[i][0] - v[j][0]; - vr2 = v[i][1] - v[j][1]; - vr3 = v[i][2] - v[j][2]; - - // normal component - - vnnr = vr1*nx + vr2*ny + vr3*nz; - vn1 = nx*vnnr; - vn2 = ny*vnnr; - vn3 = nz*vnnr; - - double *rmass = atom->rmass; - int *mask = atom->mask; - mi = rmass[i]; - mj = rmass[j]; - if (fix_rigid) { - if (mass_rigid[i] > 0.0) mi = mass_rigid[i]; - if (mass_rigid[j] > 0.0) mj = mass_rigid[j]; - } - - meff = mi*mj / (mi+mj); - if (mask[i] & freeze_group_bit) meff = mj; - if (mask[j] & freeze_group_bit) meff = mi; - - delta = radsum - r; - dR = delta*Reff; - - // tangential component - - vt1 = vr1 - vn1; - vt2 = vr2 - vn2; - vt3 = vr3 - vn3; - - // relative rotational velocity - - double **omega = atom->omega; - wr1 = (radi*omega[i][0] + radj*omega[j][0]); - wr2 = (radi*omega[i][1] + radj*omega[j][1]); - wr3 = (radi*omega[i][2] + radj*omega[j][2]); - - // meff = effective mass of pair of particles - // if I or J part of rigid body, use body mass - // if I or J is frozen, meff is other particle - - int *type = atom->type; - - mi = rmass[i]; - mj = rmass[j]; - if (fix_rigid) { - // NOTE: ensure mass_rigid is current for owned+ghost atoms? - if (mass_rigid[i] > 0.0) mi = mass_rigid[i]; - if (mass_rigid[j] > 0.0) mj = mass_rigid[j]; - } - - meff = mi*mj / (mi+mj); - if (mask[i] & freeze_group_bit) meff = mj; - if (mask[j] & freeze_group_bit) meff = mi; - - delta = radsum - r; - dR = delta*Reff; - if (normal == JKR){ - dR2 = dR*dR; - t0 = coh*coh*R2*R2*E; - t1 = PI27SQ*t0; - t2 = 8*dR*dR2*E*E*E; - t3 = 4*dR2*E; - sqrt1 = MAX(0, t0*(t1+2*t2)); //In case of sqrt(0) < 0 due to precision issues - t4 = cbrt(t1+t2+THREEROOT3*M_PI*sqrt(sqrt1)); - t5 = t3/t4 + t4/E; - sqrt2 = MAX(0, 2*dR + t5); - t6 = sqrt(sqrt2); - sqrt3 = MAX(0, 4*dR - t5 + SIXROOT6*coh*M_PI*R2/(E*t6)); - a = INVROOT6*(t6 + sqrt(sqrt3)); - a2 = a*a; - knfac = FOURTHIRDS*E*a; - Fne = knfac*a2/Reff - TWOPI*a2*sqrt(4*coh*E/(M_PI*a)); - } - else{ - knfac = E; - Fne = knfac*delta; - if (normal != HOOKE) - a = sqrt(dR); - Fne *= a; - if (normal == DMT) - Fne -= 4*MY_PI*normal_coeffs[itype][jtype][3]*Reff; - } - - //Consider restricting Hooke to only have 'velocity' as an option for damping? - if (damping == VELOCITY){ - damp_normal = normal_coeffs[itype][jtype][1]; - } - else if (damping == VISCOELASTIC){ - if (normal == HOOKE) a = sqrt(dR); - damp_normal = normal_coeffs[itype][jtype][1]*a*meff; - } - else if (damping == TSUJI){ - damp_normal = normal_coeffs[itype][jtype][1]*sqrt(meff*knfac); - } - - Fdamp = -damp_normal*vnnr; - - Fntot = Fne + Fdamp; - - jnum = list->numneigh[i]; - jlist = list->firstneigh[i]; - - if (use_history){ - allhistory = fix_history->firstvalue[i]; - for (int jj = 0; jj < jnum; jj++) { - neighprev++; - if (neighprev >= jnum) neighprev = 0; - if (jlist[neighprev] == j) break; - } - history = &allhistory[size_history*neighprev]; - } - - //**************************************** - //Tangential force, including history effects - //**************************************** - - // tangential component - vt1 = vr1 - vn1; - vt2 = vr2 - vn2; - vt3 = vr3 - vn3; - - // relative rotational velocity - wr1 = (radi*omega[i][0] + radj*omega[j][0]); - wr2 = (radi*omega[i][1] + radj*omega[j][1]); - wr3 = (radi*omega[i][2] + radj*omega[j][2]); - - // relative tangential velocities - vtr1 = vt1 - (nz*wr2-ny*wr3); - vtr2 = vt2 - (nx*wr3-nz*wr1); - vtr3 = vt3 - (ny*wr1-nx*wr2); - vrel = vtr1*vtr1 + vtr2*vtr2 + vtr3*vtr3; - vrel = sqrt(vrel); - - Fcrit = fabs(Fne); - if (normal == JKR){ - F_pulloff = 3*M_PI*coh*Reff; - Fcrit = fabs(Fne + 2*F_pulloff); - } - - //------------------------------ - //Tangential forces - //------------------------------ - k_tangential = tangential_coeffs[itype][jtype][0]; - if (normal != HOOKE){ - k_tangential *= a; - } - damp_tangential = tangential_coeffs[itype][jtype][1]*damp_normal; - - if (tangential_history){ - shrmag = sqrt(history[0]*history[0] + history[1]*history[1] + - history[2]*history[2]); - - // tangential forces = history + tangential velocity damping - fs1 = -k_tangential*history[0] - damp_tangential*vtr1; - fs2 = -k_tangential*history[1] - damp_tangential*vtr2; - fs3 = -k_tangential*history[2] - damp_tangential*vtr3; - - // rescale frictional displacements and forces if needed - Fscrit = tangential_coeffs[itype][jtype][2] * Fcrit; - fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); - if (fs > Fscrit) { - if (shrmag != 0.0) { - history[0] = -1.0/k_tangential*(Fscrit*fs1/fs + damp_tangential*vtr1); - history[1] = -1.0/k_tangential*(Fscrit*fs2/fs + damp_tangential*vtr2); - history[2] = -1.0/k_tangential*(Fscrit*fs3/fs + damp_tangential*vtr3); - fs1 *= Fscrit/fs; - fs2 *= Fscrit/fs; - fs3 *= Fscrit/fs; - } else fs1 = fs2 = fs3 = 0.0; - } - } - else{ //Classic pair gran/hooke (no history) - fs = meff*damp_tangential*vrel; - if (vrel != 0.0) Ft = MIN(Fne,fs) / vrel; - else Ft = 0.0; - fs1 = -Ft*vtr1; - fs2 = -Ft*vtr2; - fs3 = -Ft*vtr3; - } - - //**************************************** - // Rolling resistance - //**************************************** - - if (roll != ROLL_NONE){ - relrot1 = omega[i][0] - omega[j][0]; - relrot2 = omega[i][1] - omega[j][1]; - relrot3 = omega[i][2] - omega[j][2]; - - // rolling velocity, see eq. 31 of Wang et al, Particuology v 23, p 49 (2015) - // This is different from the Marshall papers, which use the Bagi/Kuhn formulation - // for rolling velocity (see Wang et al for why the latter is wrong) - vrl1 = Reff*(relrot2*nz - relrot3*ny); //- 0.5*((radj-radi)/radsum)*vtr1; - vrl2 = Reff*(relrot3*nx - relrot1*nz); //- 0.5*((radj-radi)/radsum)*vtr2; - vrl3 = Reff*(relrot1*ny - relrot2*nx); //- 0.5*((radj-radi)/radsum)*vtr3; - vrlmag = sqrt(vrl1*vrl1+vrl2*vrl2+vrl3*vrl3); - if (vrlmag != 0.0) vrlmaginv = 1.0/vrlmag; - else vrlmaginv = 0.0; - - if (roll_history){ - int rhist0 = roll_history_index; - int rhist1 = rhist0 + 1; - int rhist2 = rhist1 + 1; - - // Rolling displacement - rollmag = sqrt(history[rhist0]*history[rhist0] + - history[rhist1]*history[rhist1] + - history[rhist2]*history[rhist2]); - - rolldotn = history[rhist0]*nx + history[rhist1]*ny + history[rhist2]*nz; - - k_roll = roll_coeffs[itype][jtype][0]; - damp_roll = roll_coeffs[itype][jtype][1]; - fr1 = -k_roll*history[rhist0] - damp_roll*vrl1; - fr2 = -k_roll*history[rhist1] - damp_roll*vrl2; - fr3 = -k_roll*history[rhist2] - damp_roll*vrl3; - - // rescale frictional displacements and forces if needed - Frcrit = roll_coeffs[itype][jtype][2] * Fcrit; - - fr = sqrt(fr1*fr1 + fr2*fr2 + fr3*fr3); - if (fr > Frcrit) { - if (rollmag != 0.0) { - history[rhist0] = -1.0/k_roll*(Frcrit*fr1/fr + damp_roll*vrl1); - history[rhist1] = -1.0/k_roll*(Frcrit*fr2/fr + damp_roll*vrl2); - history[rhist2] = -1.0/k_roll*(Frcrit*fr3/fr + damp_roll*vrl3); - fr1 *= Frcrit/fr; - fr2 *= Frcrit/fr; - fr3 *= Frcrit/fr; - } else fr1 = fr2 = fr3 = 0.0; - } - } - else{ // - fr = meff*roll_coeffs[itype][jtype][1]*vrlmag; - if (vrlmag != 0.0) fr = MIN(Fne, fr) / vrlmag; - else fr = 0.0; - fr1 = -fr*vrl1; - fr2 = -fr*vrl2; - fr3 = -fr*vrl3; - } - } - - //**************************************** - // Twisting torque, including history effects - //**************************************** - if (twist != TWIST_NONE){ - magtwist = relrot1*nx + relrot2*ny + relrot3*nz; //Omega_T (eq 29 of Marshall) - if (twist == TWIST_MARSHALL){ - k_twist = 0.5*k_tangential*a*a;; //eq 32 - damp_twist = 0.5*damp_tangential*a*a; - mu_twist = TWOTHIRDS*a; - } - else{ - k_twist = twist_coeffs[itype][jtype][0]; - damp_twist = twist_coeffs[itype][jtype][1]; - mu_twist = twist_coeffs[itype][jtype][2]; - } - if (twist_history){ - magtortwist = -k_twist*history[twist_history_index] - damp_twist*magtwist;//M_t torque (eq 30) - signtwist = (magtwist > 0) - (magtwist < 0); - Mtcrit = TWOTHIRDS*a*Fscrit;//critical torque (eq 44) - if (fabs(magtortwist) > Mtcrit) { - history[twist_history_index] = 1.0/k_twist*(Mtcrit*signtwist - damp_twist*magtwist); - magtortwist = -Mtcrit * signtwist; //eq 34 - } - } - else{ - if (magtwist > 0) magtortwist = -damp_twist*magtwist; - else magtortwist = 0; - } - } - - // set single_extra quantities - - svector[0] = fs1; - svector[1] = fs2; - svector[2] = fs3; - svector[3] = fs; - svector[4] = fr1; - svector[5] = fr2; - svector[6] = fr3; - svector[7] = fr; - svector[8] = magtortwist; - return 0.0; -} - -/* ---------------------------------------------------------------------- */ - -int PairGranular::pack_forward_comm(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = mass_rigid[j]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void PairGranular::unpack_forward_comm(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) - mass_rigid[i] = buf[m++]; -} - -/* ---------------------------------------------------------------------- - memory usage of local atom-based arrays - ------------------------------------------------------------------------- */ - -double PairGranular::memory_usage() -{ - double bytes = nmax * sizeof(double); - return bytes; -} - -/* ---------------------------------------------------------------------- - mixing of Young's modulus (E) -------------------------------------------------------------------------- */ - -double PairGranular::mix_stiffnessE(double Eii, double Ejj, double Gii, double Gjj) -{ - double poisii = Eii/(2.0*Gii) - 1.0; - double poisjj = Ejj/(2.0*Gjj) - 1.0; - return 1/((1-poisii*poisjj)/Eii+(1-poisjj*poisjj)/Ejj); -} - -/* ---------------------------------------------------------------------- - mixing of shear modulus (G) - ------------------------------------------------------------------------- */ - -double PairGranular::mix_stiffnessG(double Eii, double Ejj, double Gii, double Gjj) -{ - double poisii = Eii/(2.0*Gii) - 1.0; - double poisjj = Ejj/(2.0*Gjj) - 1.0; - return 1/((2.0 -poisjj)/Gii+(2.0-poisjj)/Gjj); -} - -/* ---------------------------------------------------------------------- - mixing of everything else -------------------------------------------------------------------------- */ - -double PairGranular::mix_geom(double valii, double valjj) -{ - return sqrt(valii*valjj); -} - - -/* ---------------------------------------------------------------------- - Compute pull-off distance (beyond contact) for a given radius and atom type -------------------------------------------------------------------------- */ - -double PairGranular::pulloff_distance(double radius, int itype) -{ - double E, coh, a, delta_pulloff; - coh = normal_coeffs[itype][itype][3]; - E = mix_stiffnessE(normal_coeffs[itype][itype][0], normal_coeffs[itype][itype][0], - normal_coeffs[itype][itype][2], normal_coeffs[itype][itype][2]); - a = cbrt(9*M_PI*coh*radius*radius/(4*E)); - return a*a/radius - 2*sqrt(M_PI*coh*a/E); -} - diff --git a/src/pair_granular.h b/src/pair_granular.h deleted file mode 100644 index f39f31e4cb..0000000000 --- a/src/pair_granular.h +++ /dev/null @@ -1,120 +0,0 @@ -/* ---------------------------------------------------------- - LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator - http://lammps.sandia.gov, Sandia National Laboratories - Steve Plimpton, sjplimp@sandia.gov - - Copyright (2003) Sandia Corporation. Under the terms of Contract - DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains - certain 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(granular,PairGranular) - -#else - -#ifndef LMP_PAIR_GRANULAR_H -#define LMP_PAIR_GRANULAR_H - -#include "pair.h" - -namespace LAMMPS_NS { - -class PairGranular : public Pair { -public: - PairGranular(class LAMMPS *); - virtual ~PairGranular(); - - void compute(int, int); - // comment next line to turn off templating -#define TEMPLATED_PAIR_GRANULAR -#ifdef TEMPLATED_PAIR_GRANULAR - template < int Tp_normal, int Tp_damping, int Tp_tangential, - int Tp_roll, int Tp_twist> - void compute_templated(int, int); -#else - void compute_untemplated(int, int, int, int, int, - int, int); -#endif - - virtual void settings(int, char **); - virtual void coeff(int, char **); - void init_style(); - double init_one(int, int); - void write_restart(FILE *); - void read_restart(FILE *); - void reset_dt(); - virtual double single(int, int, int, int, double, double, double, double &); - int pack_forward_comm(int, int *, double *, int, int *); - void unpack_forward_comm(int, int, double *); - double memory_usage(); - - protected: - double cut_global; - double dt; - int freeze_group_bit; - int use_history; - - int neighprev; - double *onerad_dynamic,*onerad_frozen; - double *maxrad_dynamic,*maxrad_frozen; - double **cut; - - class FixNeighHistory *fix_history; - - // storage of rigid body masses for use in granular interactions - - class Fix *fix_rigid; // ptr to rigid body fix, NULL if none - double *mass_rigid; // rigid mass for owned+ghost atoms - int nmax; // allocated size of mass_rigid - - virtual void allocate(); - -private: - int size_history; - - //Models - int normal, damping, tangential, roll, twist; - - //History flags - int tangential_history, roll_history, twist_history; - - //Indices of history entries - int tangential_history_index, roll_history_index, twist_history_index; - - //Flags for whether model choices have been set - int normal_set, tangential_set, damping_set, roll_set, twist_set; - - //Per-type coefficients, set in pair coeff command - double ***normal_coeffs; - double ***tangential_coeffs; - double ***roll_coeffs; - double ***twist_coeffs; - - //Optional user-specified global cutoff - double cutoff_global; - - double mix_stiffnessE(double Eii, double Ejj, double Gii, double Gjj); - double mix_stiffnessG(double Eii, double Ejj, double Gii, double Gjj); - double mix_geom(double valii, double valjj); - double pulloff_distance(double radius, int itype); -}; - -} - -#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. - - */ From 9a6dc2ff11dd846f4e2cf7b4cada63af21dcb110 Mon Sep 17 00:00:00 2001 From: "Dan S. Bolintineanu" Date: Wed, 6 Mar 2019 13:54:32 -0700 Subject: [PATCH 24/44] Removed several files that should not have been included --- src/GRANULAR/pair_gran_dmt_rolling.cpp | 721 -------- src/GRANULAR/pair_gran_dmt_rolling.h | 55 - src/GRANULAR/pair_gran_dmt_rolling2.cpp | 719 -------- .../pair_gran_hooke_history_multi.cpp | 915 ---------- src/GRANULAR/pair_gran_hooke_history_multi.h | 109 -- src/GRANULAR/pair_gran_jkr_rolling.cpp | 763 -------- src/GRANULAR/pair_gran_jkr_rolling.h | 56 - src/GRANULAR/pair_gran_jkr_rolling_multi.cpp | 1181 ------------ src/GRANULAR/pair_gran_jkr_rolling_multi.h | 87 - src/GRANULAR/pair_granular_multi.cpp | 1624 ----------------- src/GRANULAR/pair_granular_multi.h | 107 -- 11 files changed, 6337 deletions(-) delete mode 100644 src/GRANULAR/pair_gran_dmt_rolling.cpp delete mode 100644 src/GRANULAR/pair_gran_dmt_rolling.h delete mode 100644 src/GRANULAR/pair_gran_dmt_rolling2.cpp delete mode 100644 src/GRANULAR/pair_gran_hooke_history_multi.cpp delete mode 100644 src/GRANULAR/pair_gran_hooke_history_multi.h delete mode 100644 src/GRANULAR/pair_gran_jkr_rolling.cpp delete mode 100644 src/GRANULAR/pair_gran_jkr_rolling.h delete mode 100644 src/GRANULAR/pair_gran_jkr_rolling_multi.cpp delete mode 100644 src/GRANULAR/pair_gran_jkr_rolling_multi.h delete mode 100644 src/GRANULAR/pair_granular_multi.cpp delete mode 100644 src/GRANULAR/pair_granular_multi.h diff --git a/src/GRANULAR/pair_gran_dmt_rolling.cpp b/src/GRANULAR/pair_gran_dmt_rolling.cpp deleted file mode 100644 index f293998e92..0000000000 --- a/src/GRANULAR/pair_gran_dmt_rolling.cpp +++ /dev/null @@ -1,721 +0,0 @@ -/* ---------------------------------------------------------------------- - LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator - http://lammps.sandia.gov, Sandia National Laboratories - Steve Plimpton, sjplimp@sandia.gov - - Copyright (2003) Sandia Corporation. Under the terms of Contract - DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains - certain rights in this software. This software is distributed under - the GNU General Public License. - - See the README file in the top-level LAMMPS directory. - ------------------------------------------------------------------------- */ - -/* ---------------------------------------------------------------------- - Contributing authors: Leo Silbert (SNL), Gary Grest (SNL) - ------------------------------------------------------------------------- */ - -#include -#include -#include -#include -#include "pair_gran_dmt_rolling.h" -#include "atom.h" -#include "update.h" -#include "force.h" -#include "fix.h" -#include "fix_neigh_history.h" -#include "neighbor.h" -#include "neigh_list.h" -#include "comm.h" -#include "memory.h" -#include "error.h" -#include "math_const.h" - -using namespace LAMMPS_NS; -using namespace MathConst; - -#define TWOTHIRDS 0.6666666666666666 -#define EPSILON 1e-10 - -enum {TSUJI, BRILLIANTOV}; -enum {INDEP, BRILLROLL}; - -/* ---------------------------------------------------------------------- */ - -PairGranDMTRolling::PairGranDMTRolling(LAMMPS *lmp) : - PairGranHookeHistory(lmp, 7), - E_one(0), G_one(0), pois(0), muS_one(0), cor(0), alpha_one(0), - Ecoh_one(0), kR_one(0), muR_one(0), etaR_one(0) -{ - int ntypes = atom->ntypes; - memory->create(E,ntypes+1,ntypes+1,"pair:E"); - memory->create(G,ntypes+1,ntypes+1,"pair:G"); - memory->create(alpha,ntypes+1,ntypes+1,"pair:alpha"); - memory->create(gamman,ntypes+1,ntypes+1,"pair:gamman"); - memory->create(muS,ntypes+1,ntypes+1,"pair:muS"); - memory->create(Ecoh,ntypes+1,ntypes+1,"pair:Ecoh"); - memory->create(kR,ntypes+1,ntypes+1,"pair:kR"); - memory->create(muR,ntypes+1,ntypes+1,"pair:muR"); - memory->create(etaR,ntypes+1,ntypes+1,"pair:etaR"); -} - -/* ---------------------------------------------------------------------- */ -PairGranDMTRolling::~PairGranDMTRolling() -{ - delete [] E_one; - delete [] G_one; - delete [] pois; - delete [] muS_one; - delete [] cor; - delete [] alpha_one; - delete [] Ecoh_one; - delete [] kR_one; - delete [] muR_one; - delete [] etaR_one; - //TODO: Make all this work with standard pair coeff type commands. - //Also these should not be in the destructor. - memory->destroy(E); - memory->destroy(G); - memory->destroy(alpha); - memory->destroy(gamman); - memory->destroy(muS); - memory->destroy(Ecoh); - memory->destroy(kR); - memory->destroy(muR); - memory->destroy(etaR); -} -/* ---------------------------------------------------------------------- */ - -void PairGranDMTRolling::compute(int eflag, int vflag) -{ - int i,j,ii,jj,inum,jnum; - int itype,jtype; - double xtmp,ytmp,ztmp,delx,dely,delz,fx,fy,fz,nx,ny,nz; - double radi,radj,radsum,rsq,r,rinv,rsqinv,R,a; - double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3; - double wr1,wr2,wr3; - double vtr1,vtr2,vtr3,vrel; - double kn, kt, k_Q, k_R, eta_N, eta_T, eta_Q, eta_R; - double Fhz, Fdamp, Fdmt, Fne, Fntot, Fscrit, Frcrit; - double overlap; - double mi,mj,meff,damp,ccel,tor1,tor2,tor3; - double relrot1,relrot2,relrot3,vrl1,vrl2,vrl3,vrlmag,vrlmaginv; - double rollmag, rolldotn, scalefac; - double fr, fr1, fr2, fr3; - double signtwist, magtwist, magtortwist, Mtcrit; - double fs,fs1,fs2,fs3,roll1,roll2,roll3,torroll1,torroll2,torroll3; - double tortwist1, tortwist2, tortwist3; - double shrmag,rsht; - int *ilist,*jlist,*numneigh,**firstneigh; - int *touch,**firsttouch; - double *shear,*allshear,**firstshear; - - if (eflag || vflag) ev_setup(eflag,vflag); - else evflag = vflag_fdotr = 0; - - int shearupdate = 1; - if (update->setupflag) shearupdate = 0; - - // update rigid body info for owned & ghost atoms if using FixRigid masses - // body[i] = which body atom I is in, -1 if none - // mass_body = mass of each rigid body - - if (fix_rigid && neighbor->ago == 0){ - int tmp; - int *body = (int *) fix_rigid->extract("body",tmp); - double *mass_body = (double *) fix_rigid->extract("masstotal",tmp); - if (atom->nmax > nmax) { - memory->destroy(mass_rigid); - nmax = atom->nmax; - memory->create(mass_rigid,nmax,"pair:mass_rigid"); - } - int nlocal = atom->nlocal; - for (i = 0; i < nlocal; i++) - if (body[i] >= 0) mass_rigid[i] = mass_body[body[i]]; - else mass_rigid[i] = 0.0; - comm->forward_comm_pair(this); - } - - double **x = atom->x; - double **v = atom->v; - double **f = atom->f; - double **omega = atom->omega; - double **torque = atom->torque; - double *radius = atom->radius; - double *rmass = atom->rmass; - int *type = atom->type; - int *mask = atom->mask; - int nlocal = atom->nlocal; - - inum = list->inum; - ilist = list->ilist; - numneigh = list->numneigh; - firstneigh = list->firstneigh; - firsttouch = fix_history->firstflag; - firstshear = fix_history->firstvalue; - - // loop over neighbors of my atoms - - for (ii = 0; ii < inum; ii++) { - i = ilist[ii]; - itype = type[i]; - xtmp = x[i][0]; - ytmp = x[i][1]; - ztmp = x[i][2]; - radi = radius[i]; - touch = firsttouch[i]; - allshear = firstshear[i]; - jlist = firstneigh[i]; - jnum = numneigh[i]; - - for (jj = 0; jj < jnum; jj++) { - j = jlist[jj]; - jtype = type[j]; - j &= NEIGHMASK; - - delx = xtmp - x[j][0]; - dely = ytmp - x[j][1]; - delz = ztmp - x[j][2]; - rsq = delx*delx + dely*dely + delz*delz; - radj = radius[j]; - radsum = radi + radj; - - if (rsq >= radsum*radsum){ - // unset non-touching neighbors - touch[jj] = 0; - shear = &allshear[size_history*jj]; - for (int k = 0; k < size_history; k++) - shear[k] = 0.0; - } else { - r = sqrt(rsq); - rinv = 1.0/r; - rsqinv = 1.0/rsq; - R = radi*radj/(radi+radj); - nx = delx*rinv; - ny = dely*rinv; - nz = delz*rinv; - - // relative translational velocity - - vr1 = v[i][0] - v[j][0]; - vr2 = v[i][1] - v[j][1]; - vr3 = v[i][2] - v[j][2]; - - // normal component - - vnnr = vr1*nx + vr2*ny + vr3*nz; //v_R . n - vn1 = nx*vnnr; - vn2 = ny*vnnr; - vn3 = nz*vnnr; - - // meff = effective mass of pair of particles - // if I or J part of rigid body, use body mass - // if I or J is frozen, meff is other particle - - mi = rmass[i]; - mj = rmass[j]; - if (fix_rigid) { - if (mass_rigid[i] > 0.0) mi = mass_rigid[i]; - if (mass_rigid[j] > 0.0) mj = mass_rigid[j]; - } - - meff = mi*mj / (mi+mj); - if (mask[i] & freeze_group_bit) meff = mj; - if (mask[j] & freeze_group_bit) meff = mi; - - //**************************************** - //Normal force = Hertzian contact + DMT + damping - //**************************************** - overlap = radsum - r; - a = sqrt(R*overlap); - kn = 4.0/3.0*E[itype][jtype]*a; - Fhz = kn*overlap; - - //Damping (based on Tsuji et al) - if (normaldamp == BRILLIANTOV) eta_N = a*meff*gamman[itype][jtype]; - else if (normaldamp == TSUJI) eta_N=alpha[itype][jtype]*sqrt(meff*kn); - - Fdamp = -eta_N*vnnr; //F_nd eq 23 and Zhao eq 19 - - //DMT - Fdmt = -4*MY_PI*Ecoh[itype][jtype]*R; - - Fne = Fhz + Fdmt; - Fntot = Fne + Fdamp; - - //**************************************** - //Tangential force, including shear history effects - //**************************************** - - // tangential component - vt1 = vr1 - vn1; - vt2 = vr2 - vn2; - vt3 = vr3 - vn3; - - // relative rotational velocity - //Luding Gran Matt 2008, v10,p235 suggests correcting radi and radj by subtracting - //delta/2, i.e. instead of radi, use distance to center of contact point? - wr1 = (radi*omega[i][0] + radj*omega[j][0]); - wr2 = (radi*omega[i][1] + radj*omega[j][1]); - wr3 = (radi*omega[i][2] + radj*omega[j][2]); - - // relative tangential velocities - vtr1 = vt1 - (nz*wr2-ny*wr3); - vtr2 = vt2 - (nx*wr3-nz*wr1); - vtr3 = vt3 - (ny*wr1-nx*wr2); - vrel = vtr1*vtr1 + vtr2*vtr2 + vtr3*vtr3; - vrel = sqrt(vrel); - - // shear history effects - touch[jj] = 1; - shear = &allshear[size_history*jj]; - shrmag = sqrt(shear[0]*shear[0] + shear[1]*shear[1] + - shear[2]*shear[2]); - - // Rotate and update shear displacements. - // See e.g. eq. 17 of Luding, Gran. Matter 2008, v10,p235 - if (shearupdate) { - rsht = shear[0]*nx + shear[1]*ny + shear[2]*nz; - if (fabs(rsht) < EPSILON) rsht = 0; - if (rsht > 0){ - scalefac = shrmag/(shrmag - rsht); //if rhst == shrmag, contacting pair has rotated 90 deg. in one step, in which case you deserve a crash! - shear[0] -= rsht*nx; - shear[1] -= rsht*ny; - shear[2] -= rsht*nz; - //Also rescale to preserve magnitude - shear[0] *= scalefac; - shear[1] *= scalefac; - shear[2] *= scalefac; - } - //Update shear history - shear[0] += vtr1*dt; - shear[1] += vtr2*dt; - shear[2] += vtr3*dt; - } - - // tangential forces = shear + tangential velocity damping - // following Zhao and Marshall Phys Fluids v20, p043302 (2008) - kt=8.0*G[itype][jtype]*a; - - eta_T = eta_N; //Based on discussion in Marshall; eta_T can also be an independent parameter - fs1 = -kt*shear[0] - eta_T*vtr1; //eq 26 - fs2 = -kt*shear[1] - eta_T*vtr2; - fs3 = -kt*shear[2] - eta_T*vtr3; - - // rescale frictional displacements and forces if needed - Fscrit = muS[itype][jtype] * fabs(Fne); - // For JKR, use eq 43 of Marshall. For DMT, use Fne instead - shrmag = sqrt(shear[0]*shear[0] + shear[1]*shear[1] + - shear[2]*shear[2]); - fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); - if (fs > Fscrit) { - if (shrmag != 0.0) { - //shear[0] = (Fcrit/fs) * (shear[0] + eta_T*vtr1/kt) - eta_T*vtr1/kt; - //shear[1] = (Fcrit/fs) * (shear[1] + eta_T*vtr1/kt) - eta_T*vtr1/kt; - //shear[2] = (Fcrit/fs) * (shear[2] + eta_T*vtr1/kt) - eta_T*vtr1/kt; - shear[0] = -1.0/kt*(Fscrit*fs1/fs + eta_T*vtr1); //Same as above, but simpler (check!) - shear[1] = -1.0/kt*(Fscrit*fs2/fs + eta_T*vtr2); - shear[2] = -1.0/kt*(Fscrit*fs3/fs + eta_T*vtr3); - fs1 *= Fscrit/fs; - fs2 *= Fscrit/fs; - fs3 *= Fscrit/fs; - } else fs1 = fs2 = fs3 = 0.0; - } - - //**************************************** - // Rolling force, including shear history effects - //**************************************** - - relrot1 = omega[i][0] - omega[j][0]; - relrot2 = omega[i][1] - omega[j][1]; - relrot3 = omega[i][2] - omega[j][2]; - - // rolling velocity, see eq. 31 of Wang et al, Particuology v 23, p 49 (2015) - // This is different from the Marshall papers, which use the Bagi/Kuhn formulation - // for rolling velocity (see Wang et al for why the latter is wrong) - vrl1 = R*(relrot2*nz - relrot3*ny); //- 0.5*((radj-radi)/radsum)*vtr1; - vrl2 = R*(relrot3*nx - relrot1*nz); //- 0.5*((radj-radi)/radsum)*vtr2; - vrl3 = R*(relrot1*ny - relrot2*nx); //- 0.5*((radj-radi)/radsum)*vtr3; - vrlmag = sqrt(vrl1*vrl1+vrl2*vrl2+vrl3*vrl3); - if (vrlmag != 0.0) vrlmaginv = 1.0/vrlmag; - else vrlmaginv = 0.0; - - // Rolling displacement - rollmag = sqrt(shear[3]*shear[3] + shear[4]*shear[4] + shear[5]*shear[5]); - rolldotn = shear[3]*nx + shear[4]*ny + shear[5]*nz; - - if (shearupdate) { - if (fabs(rolldotn) < EPSILON) rolldotn = 0; - if (rolldotn > 0){ //Rotate into tangential plane - scalefac = rollmag/(rollmag - rolldotn); - shear[3] -= rolldotn*nx; - shear[4] -= rolldotn*ny; - shear[5] -= rolldotn*nz; - //Also rescale to preserve magnitude - shear[3] *= scalefac; - shear[4] *= scalefac; - shear[5] *= scalefac; - } - shear[3] += vrl1*dt; - shear[4] += vrl2*dt; - shear[5] += vrl3*dt; - } - - k_R = kR[itype][jtype]; - if (rollingdamp == INDEP) eta_R = etaR[itype][jtype]; - else if (rollingdamp == BRILLROLL) eta_R = muR[itype][jtype]*fabs(Fne); - fr1 = -k_R*shear[3] - eta_R*vrl1; - fr2 = -k_R*shear[4] - eta_R*vrl2; - fr3 = -k_R*shear[5] - eta_R*vrl3; - - // rescale frictional displacements and forces if needed - Frcrit = muR[itype][jtype] * fabs(Fne); - - rollmag = sqrt(shear[3]*shear[3] + shear[4]*shear[4] + shear[5]*shear[5]); - fr = sqrt(fr1*fr1 + fr2*fr2 + fr3*fr3); - if (fr > Frcrit) { - if (rollmag != 0.0) { - shear[3] = -1.0/k_R*(Frcrit*fr1/fr + eta_R*vrl1); - shear[4] = -1.0/k_R*(Frcrit*fr2/fr + eta_R*vrl2); - shear[5] = -1.0/k_R*(Frcrit*fr3/fr + eta_R*vrl3); - fr1 *= Frcrit/fr; - fr2 *= Frcrit/fr; - fr3 *= Frcrit/fr; - } else fr1 = fr2 = fr3 = 0.0; - } - - - //**************************************** - // Twisting torque, including shear history effects - //**************************************** - magtwist = relrot1*nx + relrot2*ny + relrot3*nz; //Omega_T (eq 29 of Marshall) - shear[6] += magtwist*dt; - k_Q = 0.5*kt*a*a;; //eq 32 - eta_Q = 0.5*eta_T*a*a; - magtortwist = -k_Q*shear[6] - eta_Q*magtwist;//M_t torque (eq 30) - - signtwist = (magtwist > 0) - (magtwist < 0); - Mtcrit=TWOTHIRDS*a*Fscrit;//critical torque (eq 44) - if (fabs(magtortwist) > Mtcrit){ - shear[6] = 1.0/k_Q*(Mtcrit*signtwist - eta_Q*magtwist); - magtortwist = -Mtcrit * signtwist; //eq 34 - } - - // Apply forces & torques - - fx = nx*Fntot + fs1; - fy = ny*Fntot + fs2; - fz = nz*Fntot + fs3; - - f[i][0] += fx; - f[i][1] += fy; - f[i][2] += fz; - - tor1 = ny*fs3 - nz*fs2; - tor2 = nz*fs1 - nx*fs3; - tor3 = nx*fs2 - ny*fs1; - - torque[i][0] -= radi*tor1; - torque[i][1] -= radi*tor2; - torque[i][2] -= radi*tor3; - - tortwist1 = magtortwist * nx; - tortwist2 = magtortwist * ny; - tortwist3 = magtortwist * nz; - - torque[i][0] += tortwist1; - torque[i][1] += tortwist2; - torque[i][2] += tortwist3; - - torroll1 = R*(ny*fr3 - nz*fr2); //n cross fr - torroll2 = R*(nz*fr1 - nx*fr3); - torroll3 = R*(nx*fr2 - ny*fr1); - - torque[i][0] += torroll1; - torque[i][1] += torroll2; - torque[i][2] += torroll3; - - if (force->newton_pair || j < nlocal) { - f[j][0] -= fx; - f[j][1] -= fy; - f[j][2] -= fz; - - torque[j][0] -= radj*tor1; - torque[j][1] -= radj*tor2; - torque[j][2] -= radj*tor3; - - torque[j][0] -= tortwist1; - torque[j][1] -= tortwist2; - torque[j][2] -= tortwist3; - - torque[j][0] -= torroll1; - torque[j][1] -= torroll2; - torque[j][2] -= torroll3; - } - if (evflag) ev_tally_xyz(i,j,nlocal,0, - 0.0,0.0,fx,fy,fz,delx,dely,delz); - } - } - } -} - -/* ---------------------------------------------------------------------- - global settings - ------------------------------------------------------------------------- */ - -void PairGranDMTRolling::settings(int narg, char **arg) -{ - if (narg < 6) error->all(FLERR,"Illegal pair_style command"); - - int ntypes = atom->ntypes; - - if (narg < 8*ntypes) error->all(FLERR,"Illegal pair_style command"); - - E_one = new double[ntypes+1]; - G_one = new double[ntypes+1]; - pois = new double[ntypes+1]; - muS_one = new double[ntypes+1]; - cor = new double[ntypes+1]; - alpha_one = new double[ntypes+1]; - Ecoh_one = new double[ntypes+1]; - kR_one = new double[ntypes+1]; - muR_one = new double[ntypes+1]; - etaR_one = new double[ntypes+1]; - - for (int i=0; i < ntypes;i++){ - E_one[i+1] = force->numeric(FLERR, arg[i]); - G_one[i+1] = force->numeric(FLERR, arg[ntypes+i]); - muS_one[i+1] = force->numeric(FLERR, arg[2*ntypes+i]); - cor[i+1] = force->numeric(FLERR, arg[3*ntypes+i]); - Ecoh_one[i+1] = force->numeric(FLERR, arg[4*ntypes+i]); - kR_one[i+1] = force->numeric(FLERR, arg[5*ntypes+i]); - muR_one[i+1] = force->numeric(FLERR, arg[6*ntypes+i]); - etaR_one[i+1] = force->numeric(FLERR, arg[7*ntypes+i]); - } - - //Defaults - normaldamp = TSUJI; - rollingdamp = INDEP; - - int iarg = 8*ntypes; - while (iarg < narg){ - if (strcmp(arg[iarg],"normaldamp") == 0){ - if (iarg+2 > narg) error->all(FLERR, "Invalid pair/gran/dmt/rolling entry"); - if (strcmp(arg[iarg+1],"tsuji") == 0) normaldamp = TSUJI; - else if (strcmp(arg[iarg+1],"brilliantov") == 0) normaldamp = BRILLIANTOV; - else error->all(FLERR, "Invalid normal damping model for pair/gran/dmt/rolling"); - iarg += 2; - } - else if (strcmp(arg[iarg],"rollingdamp") == 0){ - if (iarg+2 > narg) error->all(FLERR, "Invalid pair/gran/dmt/rolling entry"); - if (strcmp(arg[iarg+1],"independent") == 0) rollingdamp = INDEP; - else if (strcmp(arg[iarg+1],"brilliantov") == 0) rollingdamp = BRILLROLL; - else error->all(FLERR, "Invalid rolling damping model for pair/gran/dmt/rolling"); - iarg += 2; - } - else{ - iarg +=1; - } - } - - //Derived from inputs - for (int i=1; i <= ntypes; i++){ - pois[i] = E_one[i]/(2.0*G_one[i]) - 1.0; - alpha_one[i] = 1.2728-4.2783*cor[i]+11.087*cor[i]*cor[i]-22.348*cor[i]*cor[i]*cor[i]+27.467*cor[i]*cor[i]*cor[i]*cor[i]-18.022*cor[i]*cor[i]*cor[i]*cor[i]*cor[i]+4.8218*cor[i]*cor[i]*cor[i]*cor[i]*cor[i]*cor[i]; - for (int j=i; j <= ntypes; j++){ - E[i][j] = E[j][i] = 1/((1-pois[i]*pois[i])/E_one[i]+(1-pois[j]*pois[j])/E_one[j]); - G[i][j] = G[j][i] = 1/((2-pois[i])/G_one[i]+(2-pois[j])/G_one[j]); - if (normaldamp == TSUJI){ - alpha[i][j] = alpha[j][i] = sqrt(alpha_one[i]*alpha_one[j]); - } - else if (normaldamp == BRILLIANTOV){ - gamman[i][j] = gamman[j][i] = sqrt(cor[i]*cor[j]); - } - muS[i][j] = muS[j][i] = sqrt(muS_one[i]*muS_one[j]); - Ecoh[i][j] = Ecoh[j][i] = sqrt(Ecoh_one[i]*Ecoh_one[j]); - kR[i][j] = kR[j][i] = sqrt(kR_one[i]*kR_one[j]); - etaR[i][j] = etaR[j][i] = sqrt(etaR_one[i]*etaR_one[j]); - muR[i][j] = muR[j][i] = sqrt(muR_one[i]*muR_one[j]); - } - } -} - -/* ---------------------------------------------------------------------- */ - -double PairGranDMTRolling::single(int i, int j, int itype, int jtype, - double rsq, - double factor_coul, double factor_lj, - double &fforce) -{ - double radi,radj,radsum; - double r,rinv,rsqinv,delx,dely,delz, nx, ny, nz, R; - double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3,wr1,wr2,wr3; - double overlap, a; - double mi,mj,meff,damp,kn,kt; - double Fhz,Fdamp,Fdmt,Fne,Fntot,Fscrit; - double eta_N,eta_T; - double vtr1,vtr2,vtr3,vrel; - double fs1,fs2,fs3,fs; - double shrmag; - - - double *radius = atom->radius; - radi = radius[i]; - radj = radius[j]; - radsum = radi + radj; - - if (rsq >= radsum*radsum) { - fforce = 0.0; - svector[0] = svector[1] = svector[2] = svector[3] = 0.0; - return 0.0; - } - - r = sqrt(rsq); - rinv = 1.0/r; - rsqinv = 1.0/rsq; - R = radi*radj/radsum; - - // relative translational velocity - - double **v = atom->v; - vr1 = v[i][0] - v[j][0]; - vr2 = v[i][1] - v[j][1]; - vr3 = v[i][2] - v[j][2]; - - // normal component - - double **x = atom->x; - delx = x[i][0] - x[j][0]; - dely = x[i][1] - x[j][1]; - delz = x[i][2] - x[j][2]; - - nx = delx*rinv; - ny = dely*rinv; - nz = delz*rinv; - - - vnnr = vr1*nx + vr2*ny + vr3*nz; - vn1 = nx*vnnr; - vn2 = ny*vnnr; - vn3 = nz*vnnr; - - // tangential component - - vt1 = vr1 - vn1; - vt2 = vr2 - vn2; - vt3 = vr3 - vn3; - - // relative rotational velocity - - double **omega = atom->omega; - wr1 = (radi*omega[i][0] + radj*omega[j][0]); - wr2 = (radi*omega[i][1] + radj*omega[j][1]); - wr3 = (radi*omega[i][2] + radj*omega[j][2]); - - // meff = effective mass of pair of particles - // if I or J part of rigid body, use body mass - // if I or J is frozen, meff is other particle - - double *rmass = atom->rmass; - int *type = atom->type; - int *mask = atom->mask; - - mi = rmass[i]; - mj = rmass[j]; - if (fix_rigid) { - // NOTE: ensure mass_rigid is current for owned+ghost atoms? - if (mass_rigid[i] > 0.0) mi = mass_rigid[i]; - if (mass_rigid[j] > 0.0) mj = mass_rigid[j]; - } - - meff = mi*mj / (mi+mj); - if (mask[i] & freeze_group_bit) meff = mj; - if (mask[j] & freeze_group_bit) meff = mi; - - - // normal force = Hertzian contact + normal velocity damping - overlap = radsum - r; - a = sqrt(R*overlap); - kn = 4.0/3.0*E[itype][jtype]*a; - Fhz = kn*overlap; - - //Damping (based on Tsuji et al) - - eta_N=alpha[itype][jtype]*sqrt(meff*kn); - Fdamp = -eta_N*vnnr; //F_nd eq 23 and Zhao eq 19 - - //DMT - Fdmt = -4*MY_PI*Ecoh[itype][jtype]*R; - - Fne = Fhz + Fdmt; - Fntot = Fne + Fdamp; - - // relative velocities - - vtr1 = vt1 - (nz*wr2-ny*wr3); - vtr2 = vt2 - (nx*wr3-nz*wr1); - vtr3 = vt3 - (ny*wr1-nx*wr2); - vrel = vtr1*vtr1 + vtr2*vtr2 + vtr3*vtr3; - vrel = sqrt(vrel); - - // shear history effects - // neighprev = index of found neigh on previous call - // search entire jnum list of neighbors of I for neighbor J - // start from neighprev, since will typically be next neighbor - // reset neighprev to 0 as necessary - - int jnum = list->numneigh[i]; - int *jlist = list->firstneigh[i]; - double *allshear = fix_history->firstvalue[i]; - - for (int jj = 0; jj < jnum; jj++) { - neighprev++; - if (neighprev >= jnum) neighprev = 0; - if (jlist[neighprev] == j) break; - } - - double *shear = &allshear[size_history*neighprev]; - shrmag = sqrt(shear[0]*shear[0] + shear[1]*shear[1] + - shear[2]*shear[2]); - - // tangential forces = shear + tangential velocity damping - kt=8.0*G[itype][jtype]*a; - - eta_T = eta_N; - fs1 = -kt*shear[0] - eta_T*vtr1; - fs2 = -kt*shear[1] - eta_T*vtr2; - fs3 = -kt*shear[2] - eta_T*vtr3; - - // rescale frictional displacements and forces if needed - - fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); - Fscrit= muS[itype][jtype] * fabs(Fne); - - if (fs > Fscrit) { - if (shrmag != 0.0) { - fs1 *= Fscrit/fs; - fs2 *= Fscrit/fs; - fs3 *= Fscrit/fs; - fs *= Fscrit/fs; - } else fs1 = fs2 = fs3 = fs = 0.0; - } - - // set all forces and return no energy - - fforce = Fntot; - - // set single_extra quantities - - svector[0] = fs1; - svector[1] = fs2; - svector[2] = fs3; - svector[3] = fs; - svector[4] = vn1; - svector[5] = vn2; - svector[6] = vn3; - svector[7] = vt1; - svector[8] = vt2; - svector[9] = vt3; - return 0.0; -} diff --git a/src/GRANULAR/pair_gran_dmt_rolling.h b/src/GRANULAR/pair_gran_dmt_rolling.h deleted file mode 100644 index 8f4ae2005e..0000000000 --- a/src/GRANULAR/pair_gran_dmt_rolling.h +++ /dev/null @@ -1,55 +0,0 @@ -/* -*- 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. -------------------------------------------------------------------------- */ - -#ifdef PAIR_CLASS - -PairStyle(gran/dmt/rolling,PairGranDMTRolling) - -#else - -#ifndef LMP_PAIR_GRAN_DMT_ROLLING_H -#define LMP_PAIR_GRAN_DMT_ROLLING_H - -#include "pair_gran_hooke_history.h" - -namespace LAMMPS_NS { - -class PairGranDMTRolling : public PairGranHookeHistory { -public: - PairGranDMTRolling(class LAMMPS *); - virtual ~PairGranDMTRolling(); - virtual void compute(int, int); - void settings(int, char **); //Eventually set this through coeff method so that user can specify a particular i-j set of coefficients - double single(int, int, int, int, double, double, double, double &); - double *E_one, *G_one, *pois, *muS_one, *cor, *alpha_one, *Ecoh_one, *kR_one, *muR_one, *etaR_one; //Public so as to be accessible to fix/wall/gran -private: - double **E, **G, **alpha, **muS, **Ecoh, **kR, **muR, **etaR, **gamman; - int normaldamp, rollingdamp; - - -}; - -} - -#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. - - */ diff --git a/src/GRANULAR/pair_gran_dmt_rolling2.cpp b/src/GRANULAR/pair_gran_dmt_rolling2.cpp deleted file mode 100644 index 5c1211cbc5..0000000000 --- a/src/GRANULAR/pair_gran_dmt_rolling2.cpp +++ /dev/null @@ -1,719 +0,0 @@ -/* ---------------------------------------------------------------------- - LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator - http://lammps.sandia.gov, Sandia National Laboratories - Steve Plimpton, sjplimp@sandia.gov - - Copyright (2003) Sandia Corporation. Under the terms of Contract - DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains - certain rights in this software. This software is distributed under - the GNU General Public License. - - See the README file in the top-level LAMMPS directory. - ------------------------------------------------------------------------- */ - -/* ---------------------------------------------------------------------- - Contributing authors: Leo Silbert (SNL), Gary Grest (SNL) - ------------------------------------------------------------------------- */ - -#include -#include -#include -#include -#include "pair_gran_dmt_rolling.h" -#include "atom.h" -#include "update.h" -#include "force.h" -#include "fix.h" -#include "neighbor.h" -#include "neigh_list.h" -#include "comm.h" -#include "memory.h" -#include "error.h" -#include "math_const.h" - -using namespace LAMMPS_NS; -using namespace MathConst; - -#define TWOTHIRDS 0.6666666666666666 -#define EPSILON 1e-10 - -enum {TSUJI, BRILLIANTOV}; -enum {INDEP, BRILLROLL}; - -/* ---------------------------------------------------------------------- */ - -PairGranDMTRolling::PairGranDMTRolling(LAMMPS *lmp) : - PairGranHookeHistory(lmp, 7), - E_one(0), G_one(0), pois(0), muS_one(0), cor(0), alpha_one(0), - Ecoh_one(0), kR_one(0), muR_one(0), etaR_one(0) -{ - int ntypes = atom->ntypes; - memory->create(E,ntypes+1,ntypes+1,"pair:E"); - memory->create(G,ntypes+1,ntypes+1,"pair:G"); - memory->create(alpha,ntypes+1,ntypes+1,"pair:alpha"); - memory->create(gamman,ntypes+1,ntypes+1,"pair:gamman"); - memory->create(muS,ntypes+1,ntypes+1,"pair:muS"); - memory->create(Ecoh,ntypes+1,ntypes+1,"pair:Ecoh"); - memory->create(kR,ntypes+1,ntypes+1,"pair:kR"); - memory->create(muR,ntypes+1,ntypes+1,"pair:muR"); - memory->create(etaR,ntypes+1,ntypes+1,"pair:etaR"); -} - -/* ---------------------------------------------------------------------- */ -PairGranDMTRolling::~PairGranDMTRolling() -{ - delete [] E_one; - delete [] G_one; - delete [] pois; - delete [] muS_one; - delete [] cor; - delete [] alpha_one; - delete [] Ecoh_one; - delete [] kR_one; - delete [] muR_one; - delete [] etaR_one; - //TODO: Make all this work with standard pair coeff type commands. - //Also these should not be in the destructor. - memory->destroy(E); - memory->destroy(G); - memory->destroy(alpha); - memory->destroy(gamman); - memory->destroy(muS); - memory->destroy(Ecoh); - memory->destroy(kR); - memory->destroy(muR); - memory->destroy(etaR); -} -/* ---------------------------------------------------------------------- */ - -void PairGranDMTRolling::compute(int eflag, int vflag) -{ - int i,j,ii,jj,inum,jnum; - int itype,jtype; - double xtmp,ytmp,ztmp,delx,dely,delz,fx,fy,fz,nx,ny,nz; - double radi,radj,radsum,rsq,r,rinv,rsqinv,R,a; - double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3; - double wr1,wr2,wr3; - double vtr1,vtr2,vtr3,vrel; - double kn, kt, k_Q, k_R, eta_N, eta_T, eta_Q, eta_R; - double Fhz, Fdamp, Fdmt, Fne, Fntot, Fscrit, Frcrit; - double overlap; - double mi,mj,meff,damp,ccel,tor1,tor2,tor3; - double relrot1,relrot2,relrot3,vrl1,vrl2,vrl3,vrlmag,vrlmaginv; - double rollmag, rolldotn, scalefac; - double fr, fr1, fr2, fr3; - double signtwist, magtwist, magtortwist, Mtcrit; - double fs,fs1,fs2,fs3,roll1,roll2,roll3,torroll1,torroll2,torroll3; - double tortwist1, tortwist2, tortwist3; - double shrmag,rsht; - int *ilist,*jlist,*numneigh,**firstneigh; - int *touch,**firsttouch; - double *shear,*allshear,**firstshear; - - if (eflag || vflag) ev_setup(eflag,vflag); - else evflag = vflag_fdotr = 0; - - int shearupdate = 1; - if (update->setupflag) shearupdate = 0; - - // update rigid body info for owned & ghost atoms if using FixRigid masses - // body[i] = which body atom I is in, -1 if none - // mass_body = mass of each rigid body - - if (fix_rigid && neighbor->ago == 0){ - int tmp; - int *body = (int *) fix_rigid->extract("body",tmp); - double *mass_body = (double *) fix_rigid->extract("masstotal",tmp); - if (atom->nmax > nmax) { - memory->destroy(mass_rigid); - nmax = atom->nmax; - memory->create(mass_rigid,nmax,"pair:mass_rigid"); - } - int nlocal = atom->nlocal; - for (i = 0; i < nlocal; i++) - if (body[i] >= 0) mass_rigid[i] = mass_body[body[i]]; - else mass_rigid[i] = 0.0; - comm->forward_comm_pair(this); - } - - double **x = atom->x; - double **v = atom->v; - double **f = atom->f; - double **omega = atom->omega; - double **torque = atom->torque; - double *radius = atom->radius; - double *rmass = atom->rmass; - int *type = atom->type; - int *mask = atom->mask; - int nlocal = atom->nlocal; - - inum = list->inum; - ilist = list->ilist; - numneigh = list->numneigh; - firstneigh = list->firstneigh; - firsttouch = list->listhistory->firstneigh; - firstshear = list->listhistory->firstdouble; - - // loop over neighbors of my atoms - - for (ii = 0; ii < inum; ii++) { - i = ilist[ii]; - itype = type[i]; - xtmp = x[i][0]; - ytmp = x[i][1]; - ztmp = x[i][2]; - radi = radius[i]; - touch = firsttouch[i]; - allshear = firstshear[i]; - jlist = firstneigh[i]; - jnum = numneigh[i]; - - for (jj = 0; jj < jnum; jj++) { - j = jlist[jj]; - jtype = type[j]; - j &= NEIGHMASK; - - delx = xtmp - x[j][0]; - dely = ytmp - x[j][1]; - delz = ztmp - x[j][2]; - rsq = delx*delx + dely*dely + delz*delz; - radj = radius[j]; - radsum = radi + radj; - - if (rsq >= radsum*radsum){ - // unset non-touching neighbors - touch[jj] = 0; - shear = &allshear[nsheardim*jj]; - for (int k = 0; k < nsheardim; k++) - shear[k] = 0.0; - } else { - r = sqrt(rsq); - rinv = 1.0/r; - rsqinv = 1.0/rsq; - R = radi*radj/(radi+radj); - nx = delx*rinv; - ny = dely*rinv; - nz = delz*rinv; - - // relative translational velocity - - vr1 = v[i][0] - v[j][0]; - vr2 = v[i][1] - v[j][1]; - vr3 = v[i][2] - v[j][2]; - - // normal component - - vnnr = vr1*nx + vr2*ny + vr3*nz; //v_R . n - vn1 = nx*vnnr; - vn2 = ny*vnnr; - vn3 = nz*vnnr; - - // meff = effective mass of pair of particles - // if I or J part of rigid body, use body mass - // if I or J is frozen, meff is other particle - - mi = rmass[i]; - mj = rmass[j]; - if (fix_rigid) { - if (mass_rigid[i] > 0.0) mi = mass_rigid[i]; - if (mass_rigid[j] > 0.0) mj = mass_rigid[j]; - } - - meff = mi*mj / (mi+mj); - if (mask[i] & freeze_group_bit) meff = mj; - if (mask[j] & freeze_group_bit) meff = mi; - - //**************************************** - //Normal force = Hertzian contact + DMT + damping - //**************************************** - overlap = radsum - r; - a = sqrt(R*overlap); - kn = 4.0/3.0*E[itype][jtype]*a; - Fhz = kn*overlap; - - //Damping (based on Tsuji et al) - if (normaldamp == BRILLIANTOV) eta_N = a*meff*gamman[itype][jtype]; - else if (normaldamp == TSUJI) eta_N=alpha[itype][jtype]*sqrt(meff*kn); - - Fdamp = -eta_N*vnnr; //F_nd eq 23 and Zhao eq 19 - - //DMT - Fdmt = -4*MY_PI*Ecoh[itype][jtype]*R; - - Fne = Fhz + Fdmt; - Fntot = Fne + Fdamp; - - //**************************************** - //Tangential force, including shear history effects - //**************************************** - - // tangential component - vt1 = vr1 - vn1; - vt2 = vr2 - vn2; - vt3 = vr3 - vn3; - - // relative rotational velocity - //Luding Gran Matt 2008, v10,p235 suggests correcting radi and radj by subtracting - //delta/2, i.e. instead of radi, use distance to center of contact point? - wr1 = (radi*omega[i][0] + radj*omega[j][0]); - wr2 = (radi*omega[i][1] + radj*omega[j][1]); - wr3 = (radi*omega[i][2] + radj*omega[j][2]); - - // relative tangential velocities - vtr1 = vt1 - (nz*wr2-ny*wr3); - vtr2 = vt2 - (nx*wr3-nz*wr1); - vtr3 = vt3 - (ny*wr1-nx*wr2); - vrel = vtr1*vtr1 + vtr2*vtr2 + vtr3*vtr3; - vrel = sqrt(vrel); - - // shear history effects - touch[jj] = 1; - shear = &allshear[nsheardim*jj]; - shrmag = sqrt(shear[0]*shear[0] + shear[1]*shear[1] + - shear[2]*shear[2]); - - // Rotate and update shear displacements. - // See e.g. eq. 17 of Luding, Gran. Matter 2008, v10,p235 - if (shearupdate) { - rsht = shear[0]*nx + shear[1]*ny + shear[2]*nz; - if (fabs(rsht) < EPSILON) rsht = 0; - if (rsht > 0){ - scalefac = shrmag/(shrmag - rsht); //if rhst == shrmag, contacting pair has rotated 90 deg. in one step, in which case you deserve a crash! - shear[0] -= rsht*nx; - shear[1] -= rsht*ny; - shear[2] -= rsht*nz; - //Also rescale to preserve magnitude - shear[0] *= scalefac; - shear[1] *= scalefac; - shear[2] *= scalefac; - } - //Update shear history - shear[0] += vtr1*dt; - shear[1] += vtr2*dt; - shear[2] += vtr3*dt; - } - - // tangential forces = shear + tangential velocity damping - // following Zhao and Marshall Phys Fluids v20, p043302 (2008) - kt=8.0*G[itype][jtype]*a; - - eta_T = eta_N; //Based on discussion in Marshall; eta_T can also be an independent parameter - fs1 = -kt*shear[0] - eta_T*vtr1; //eq 26 - fs2 = -kt*shear[1] - eta_T*vtr2; - fs3 = -kt*shear[2] - eta_T*vtr3; - - // rescale frictional displacements and forces if needed - Fscrit = muS[itype][jtype] * fabs(Fne); - // For JKR, use eq 43 of Marshall. For DMT, use Fne instead - shrmag = sqrt(shear[0]*shear[0] + shear[1]*shear[1] + - shear[2]*shear[2]); - fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); - if (fs > Fscrit) { - if (shrmag != 0.0) { - //shear[0] = (Fcrit/fs) * (shear[0] + eta_T*vtr1/kt) - eta_T*vtr1/kt; - //shear[1] = (Fcrit/fs) * (shear[1] + eta_T*vtr1/kt) - eta_T*vtr1/kt; - //shear[2] = (Fcrit/fs) * (shear[2] + eta_T*vtr1/kt) - eta_T*vtr1/kt; - shear[0] = -1.0/kt*(Fscrit*fs1/fs + eta_T*vtr1); //Same as above, but simpler (check!) - shear[1] = -1.0/kt*(Fscrit*fs2/fs + eta_T*vtr2); - shear[2] = -1.0/kt*(Fscrit*fs3/fs + eta_T*vtr3); - fs1 *= Fscrit/fs; - fs2 *= Fscrit/fs; - fs3 *= Fscrit/fs; - } else fs1 = fs2 = fs3 = 0.0; - } - - //**************************************** - // Rolling force, including shear history effects - //**************************************** - - relrot1 = omega[i][0] - omega[j][0]; - relrot2 = omega[i][1] - omega[j][1]; - relrot3 = omega[i][2] - omega[j][2]; - - // rolling velocity, see eq. 31 of Wang et al, Particuology v 23, p 49 (2015) - // This is different from the Marshall papers, which use the Bagi/Kuhn formulation - // for rolling velocity (see Wang et al for why the latter is wrong) - vrl1 = R*(relrot2*nz - relrot3*ny); //- 0.5*((radj-radi)/radsum)*vtr1; - vrl2 = R*(relrot3*nx - relrot1*nz); //- 0.5*((radj-radi)/radsum)*vtr2; - vrl3 = R*(relrot1*ny - relrot2*nx); //- 0.5*((radj-radi)/radsum)*vtr3; - vrlmag = sqrt(vrl1*vrl1+vrl2*vrl2+vrl3*vrl3); - if (vrlmag != 0.0) vrlmaginv = 1.0/vrlmag; - else vrlmaginv = 0.0; - - // Rolling displacement - rollmag = sqrt(shear[3]*shear[3] + shear[4]*shear[4] + shear[5]*shear[5]); - rolldotn = shear[3]*nx + shear[4]*ny + shear[5]*nz; - - if (shearupdate) { - if (fabs(rolldotn) < EPSILON) rolldotn = 0; - if (rolldotn > 0){ //Rotate into tangential plane - scalefac = rollmag/(rollmag - rolldotn); - shear[3] -= rolldotn*nx; - shear[4] -= rolldotn*ny; - shear[5] -= rolldotn*nz; - //Also rescale to preserve magnitude - shear[3] *= scalefac; - shear[4] *= scalefac; - shear[5] *= scalefac; - } - shear[3] += vrl1*dt; - shear[4] += vrl2*dt; - shear[5] += vrl3*dt; - } - - k_R = kR[itype][jtype]; - if (rollingdamp == INDEP) eta_R = etaR[itype][jtype]; - else if (rollingdamp == BRILLROLL) eta_R = muR[itype][jtype]*fabs(Fne); - fr1 = -k_R*shear[3] - eta_R*vrl1; - fr2 = -k_R*shear[4] - eta_R*vrl2; - fr3 = -k_R*shear[5] - eta_R*vrl3; - - // rescale frictional displacements and forces if needed - Frcrit = muR[itype][jtype] * fabs(Fne); - - fr = sqrt(fr1*fr1 + fr2*fr2 + fr3*fr3); - if (fr > Frcrit) { - if (rollmag != 0.0) { - shear[3] = -1.0/k_R*(Frcrit*fr1/fr + eta_R*vrl1); - shear[4] = -1.0/k_R*(Frcrit*fr2/fr + eta_R*vrl2); - shear[5] = -1.0/k_R*(Frcrit*fr3/fr + eta_R*vrl3); - fr1 *= Frcrit/fr; - fr2 *= Frcrit/fr; - fr3 *= Frcrit/fr; - } else fr1 = fr2 = fr3 = 0.0; - } - - - //**************************************** - // Twisting torque, including shear history effects - //**************************************** - magtwist = relrot1*nx + relrot2*ny + relrot3*nz; //Omega_T (eq 29 of Marshall) - shear[6] += magtwist*dt; - k_Q = 0.5*kt*a*a;; //eq 32 - eta_Q = 0.5*eta_T*a*a; - magtortwist = -k_Q*shear[6] - eta_Q*magtwist;//M_t torque (eq 30) - - signtwist = (magtwist > 0) - (magtwist < 0); - Mtcrit=TWOTHIRDS*a*Fscrit;//critical torque (eq 44) - if (fabs(magtortwist) > Mtcrit){ - shear[6] = 1.0/k_Q*(Mtcrit*signtwist - eta_Q*magtwist); - magtortwist = -Mtcrit * signtwist; //eq 34 - } - - // Apply forces & torques - - fx = nx*Fntot + fs1; - fy = ny*Fntot + fs2; - fz = nz*Fntot + fs3; - - f[i][0] += fx; - f[i][1] += fy; - f[i][2] += fz; - - tor1 = ny*fs3 - nz*fs2; - tor2 = nz*fs1 - nx*fs3; - tor3 = nx*fs2 - ny*fs1; - - torque[i][0] -= radi*tor1; - torque[i][1] -= radi*tor2; - torque[i][2] -= radi*tor3; - - tortwist1 = magtortwist * nx; - tortwist2 = magtortwist * ny; - tortwist3 = magtortwist * nz; - - torque[i][0] += tortwist1; - torque[i][1] += tortwist2; - torque[i][2] += tortwist3; - - torroll1 = R*(ny*fr3 - nz*fr2); //n cross fr - torroll2 = R*(nz*fr1 - nx*fr3); - torroll3 = R*(nx*fr2 - ny*fr1); - - torque[i][0] += torroll1; - torque[i][1] += torroll2; - torque[i][2] += torroll3; - - if (force->newton_pair || j < nlocal) { - f[j][0] -= fx; - f[j][1] -= fy; - f[j][2] -= fz; - - torque[j][0] -= radj*tor1; - torque[j][1] -= radj*tor2; - torque[j][2] -= radj*tor3; - - torque[j][0] -= tortwist1; - torque[j][1] -= tortwist2; - torque[j][2] -= tortwist3; - - torque[j][0] -= torroll1; - torque[j][1] -= torroll2; - torque[j][2] -= torroll3; - } - if (evflag) ev_tally_xyz(i,j,nlocal,0, - 0.0,0.0,fx,fy,fz,delx,dely,delz); - } - } - } -} - -/* ---------------------------------------------------------------------- - global settings - ------------------------------------------------------------------------- */ - -void PairGranDMTRolling::settings(int narg, char **arg) -{ - if (narg < 6) error->all(FLERR,"Illegal pair_style command"); - - int ntypes = atom->ntypes; - - if (narg < 8*ntypes) error->all(FLERR,"Illegal pair_style command"); - - E_one = new double[ntypes+1]; - G_one = new double[ntypes+1]; - pois = new double[ntypes+1]; - muS_one = new double[ntypes+1]; - cor = new double[ntypes+1]; - alpha_one = new double[ntypes+1]; - Ecoh_one = new double[ntypes+1]; - kR_one = new double[ntypes+1]; - muR_one = new double[ntypes+1]; - etaR_one = new double[ntypes+1]; - - for (int i=0; i < ntypes;i++){ - E_one[i+1] = force->numeric(FLERR, arg[i]); - G_one[i+1] = force->numeric(FLERR, arg[ntypes+i]); - muS_one[i+1] = force->numeric(FLERR, arg[2*ntypes+i]); - cor[i+1] = force->numeric(FLERR, arg[3*ntypes+i]); - Ecoh_one[i+1] = force->numeric(FLERR, arg[4*ntypes+i]); - kR_one[i+1] = force->numeric(FLERR, arg[5*ntypes+i]); - muR_one[i+1] = force->numeric(FLERR, arg[6*ntypes+i]); - etaR_one[i+1] = force->numeric(FLERR, arg[7*ntypes+i]); - } - - //Defaults - normaldamp = TSUJI; - rollingdamp = INDEP; - - int iarg = 8*ntypes; - while (iarg < narg){ - if (strcmp(arg[iarg],"normaldamp") == 0){ - if (iarg+2 > narg) error->all(FLERR, "Invalid pair/gran/dmt/rolling entry"); - if (strcmp(arg[iarg+1],"tsuji") == 0) normaldamp = TSUJI; - else if (strcmp(arg[iarg+1],"brilliantov") == 0) normaldamp = BRILLIANTOV; - else error->all(FLERR, "Invalid normal damping model for pair/gran/dmt/rolling"); - iarg += 2; - } - else if (strcmp(arg[iarg],"rollingdamp") == 0){ - if (iarg+2 > narg) error->all(FLERR, "Invalid pair/gran/dmt/rolling entry"); - if (strcmp(arg[iarg+1],"independent") == 0) rollingdamp = INDEP; - else if (strcmp(arg[iarg+1],"brilliantov") == 0) rollingdamp = BRILLROLL; - else error->all(FLERR, "Invalid rolling damping model for pair/gran/dmt/rolling"); - iarg += 2; - } - else{ - iarg +=1; - } - } - - //Derived from inputs - for (int i=1; i <= ntypes; i++){ - pois[i] = E_one[i]/(2.0*G_one[i]) - 1.0; - alpha_one[i] = 1.2728-4.2783*cor[i]+11.087*cor[i]*cor[i]-22.348*cor[i]*cor[i]*cor[i]+27.467*cor[i]*cor[i]*cor[i]*cor[i]-18.022*cor[i]*cor[i]*cor[i]*cor[i]*cor[i]+4.8218*cor[i]*cor[i]*cor[i]*cor[i]*cor[i]*cor[i]; - for (int j=i; j <= ntypes; j++){ - E[i][j] = E[j][i] = 1/((1-pois[i]*pois[i])/E_one[i]+(1-pois[j]*pois[j])/E_one[j]); - G[i][j] = G[j][i] = 1/((2-pois[i])/G_one[i]+(2-pois[j])/G_one[j]); - if (normaldamp == TSUJI){ - alpha[i][j] = alpha[j][i] = sqrt(alpha_one[i]*alpha_one[j]); - } - else if (normaldamp == BRILLIANTOV){ - gamman[i][j] = gamman[j][i] = sqrt(cor[i]*cor[j]); - } - muS[i][j] = muS[j][i] = sqrt(muS_one[i]*muS_one[j]); - Ecoh[i][j] = Ecoh[j][i] = sqrt(Ecoh_one[i]*Ecoh_one[j]); - kR[i][j] = kR[j][i] = sqrt(kR_one[i]*kR_one[j]); - etaR[i][j] = etaR[j][i] = sqrt(etaR_one[i]*etaR_one[j]); - muR[i][j] = muR[j][i] = sqrt(muR_one[i]*muR_one[j]); - } - } -} - -/* ---------------------------------------------------------------------- */ - -double PairGranDMTRolling::single(int i, int j, int itype, int jtype, - double rsq, - double factor_coul, double factor_lj, - double &fforce) -{ - double radi,radj,radsum; - double r,rinv,rsqinv,delx,dely,delz, nx, ny, nz, R; - double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3,wr1,wr2,wr3; - double overlap, a; - double mi,mj,meff,damp,kn,kt; - double Fhz,Fdamp,Fdmt,Fne,Fntot,Fscrit; - double eta_N,eta_T; - double vtr1,vtr2,vtr3,vrel; - double fs1,fs2,fs3,fs; - double shrmag; - - - double *radius = atom->radius; - radi = radius[i]; - radj = radius[j]; - radsum = radi + radj; - - if (rsq >= radsum*radsum) { - fforce = 0.0; - svector[0] = svector[1] = svector[2] = svector[3] = 0.0; - return 0.0; - } - - r = sqrt(rsq); - rinv = 1.0/r; - rsqinv = 1.0/rsq; - R = radi*radj/radsum; - - // relative translational velocity - - double **v = atom->v; - vr1 = v[i][0] - v[j][0]; - vr2 = v[i][1] - v[j][1]; - vr3 = v[i][2] - v[j][2]; - - // normal component - - double **x = atom->x; - delx = x[i][0] - x[j][0]; - dely = x[i][1] - x[j][1]; - delz = x[i][2] - x[j][2]; - - nx = delx*rinv; - ny = dely*rinv; - nz = delz*rinv; - - - vnnr = vr1*nx + vr2*ny + vr3*nz; - vn1 = nx*vnnr; - vn2 = ny*vnnr; - vn3 = nz*vnnr; - - // tangential component - - vt1 = vr1 - vn1; - vt2 = vr2 - vn2; - vt3 = vr3 - vn3; - - // relative rotational velocity - - double **omega = atom->omega; - wr1 = (radi*omega[i][0] + radj*omega[j][0]); - wr2 = (radi*omega[i][1] + radj*omega[j][1]); - wr3 = (radi*omega[i][2] + radj*omega[j][2]); - - // meff = effective mass of pair of particles - // if I or J part of rigid body, use body mass - // if I or J is frozen, meff is other particle - - double *rmass = atom->rmass; - int *type = atom->type; - int *mask = atom->mask; - - mi = rmass[i]; - mj = rmass[j]; - if (fix_rigid) { - // NOTE: ensure mass_rigid is current for owned+ghost atoms? - if (mass_rigid[i] > 0.0) mi = mass_rigid[i]; - if (mass_rigid[j] > 0.0) mj = mass_rigid[j]; - } - - meff = mi*mj / (mi+mj); - if (mask[i] & freeze_group_bit) meff = mj; - if (mask[j] & freeze_group_bit) meff = mi; - - - // normal force = Hertzian contact + normal velocity damping - overlap = radsum - r; - a = sqrt(R*overlap); - kn = 4.0/3.0*E[itype][jtype]*a; - Fhz = kn*overlap; - - //Damping (based on Tsuji et al) - - eta_N=alpha[itype][jtype]*sqrt(meff*kn); - Fdamp = -eta_N*vnnr; //F_nd eq 23 and Zhao eq 19 - - //DMT - Fdmt = -4*MY_PI*Ecoh[itype][jtype]*R; - - Fne = Fhz + Fdmt; - Fntot = Fne + Fdamp; - - // relative velocities - - vtr1 = vt1 - (nz*wr2-ny*wr3); - vtr2 = vt2 - (nx*wr3-nz*wr1); - vtr3 = vt3 - (ny*wr1-nx*wr2); - vrel = vtr1*vtr1 + vtr2*vtr2 + vtr3*vtr3; - vrel = sqrt(vrel); - - // shear history effects - // neighprev = index of found neigh on previous call - // search entire jnum list of neighbors of I for neighbor J - // start from neighprev, since will typically be next neighbor - // reset neighprev to 0 as necessary - - int jnum = list->numneigh[i]; - int *jlist = list->firstneigh[i]; - double *allshear = list->listhistory->firstdouble[i]; - - for (int jj = 0; jj < jnum; jj++) { - neighprev++; - if (neighprev >= jnum) neighprev = 0; - if (jlist[neighprev] == j) break; - } - - double *shear = &allshear[nsheardim*neighprev]; - shrmag = sqrt(shear[0]*shear[0] + shear[1]*shear[1] + - shear[2]*shear[2]); - - // tangential forces = shear + tangential velocity damping - kt=8.0*G[itype][jtype]*a; - - eta_T = eta_N; - fs1 = -kt*shear[0] - eta_T*vtr1; - fs2 = -kt*shear[1] - eta_T*vtr2; - fs3 = -kt*shear[2] - eta_T*vtr3; - - // rescale frictional displacements and forces if needed - - fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); - Fscrit= muS[itype][jtype] * fabs(Fne); - - if (fs > Fscrit) { - if (shrmag != 0.0) { - fs1 *= Fscrit/fs; - fs2 *= Fscrit/fs; - fs3 *= Fscrit/fs; - fs *= Fscrit/fs; - } else fs1 = fs2 = fs3 = fs = 0.0; - } - - // set all forces and return no energy - - fforce = Fntot; - - // set single_extra quantities - - svector[0] = fs1; - svector[1] = fs2; - svector[2] = fs3; - svector[3] = fs; - svector[4] = vn1; - svector[5] = vn2; - svector[6] = vn3; - svector[7] = vt1; - svector[8] = vt2; - svector[9] = vt3; - return 0.0; -} diff --git a/src/GRANULAR/pair_gran_hooke_history_multi.cpp b/src/GRANULAR/pair_gran_hooke_history_multi.cpp deleted file mode 100644 index 48e793bbb3..0000000000 --- a/src/GRANULAR/pair_gran_hooke_history_multi.cpp +++ /dev/null @@ -1,915 +0,0 @@ -/* ---------------------------------------------------------------------- - LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator - http://lammps.sandia.gov, Sandia National Laboratories - Steve Plimpton, sjplimp@sandia.gov - - Copyright (2003) Sandia Corporation. Under the terms of Contract - DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains - certain rights in this software. This software is distributed under - the GNU General Public License. - - See the README file in the top-level LAMMPS directory. -------------------------------------------------------------------------- */ - -/* ---------------------------------------------------------------------- - Contributing authors: Leo Silbert (SNL), Gary Grest (SNL) -------------------------------------------------------------------------- */ - -#include -#include -#include -#include -#include "pair_gran_hooke_history_multi.h" -#include "atom.h" -#include "atom_vec.h" -#include "domain.h" -#include "force.h" -#include "update.h" -#include "modify.h" -#include "fix.h" -#include "fix_neigh_history.h" -#include "comm.h" -#include "neighbor.h" -#include "neigh_list.h" -#include "neigh_request.h" -#include "memory.h" -#include "error.h" - -using namespace LAMMPS_NS; - -#define BIG 1.0e20 - -/* ---------------------------------------------------------------------- */ - -PairGranHookeHistoryMulti::PairGranHookeHistoryMulti(LAMMPS *lmp) : Pair(lmp) -{ - single_enable = 1; - no_virial_fdotr_compute = 1; - history = 1; - fix_history = NULL; - - single_extra = 10; - svector = new double[10]; - - neighprev = 0; - - nmax = 0; - mass_rigid = NULL; - - // set comm size needed by this Pair if used with fix rigid - - comm_forward = 1; -} - -/* ---------------------------------------------------------------------- */ - -PairGranHookeHistoryMulti::~PairGranHookeHistoryMulti() -{ - delete [] svector; - if (fix_history) modify->delete_fix("NEIGH_HISTORY"); - - if (allocated) { - memory->destroy(setflag); - memory->destroy(cutsq); - - memory->destroy(cut); - memory->destroy(kn); - memory->destroy(kt); - memory->destroy(gamman); - memory->destroy(gammat); - memory->destroy(xmu); - memory->destroy(dampflag); - - delete [] onerad_dynamic; - delete [] onerad_frozen; - delete [] maxrad_dynamic; - delete [] maxrad_frozen; - } - memory->destroy(mass_rigid); -} - -/* ---------------------------------------------------------------------- */ - -void PairGranHookeHistoryMulti::compute(int eflag, int vflag) -{ - int i,j,ii,jj,inum,jnum,itype,jtype; - double xtmp,ytmp,ztmp,delx,dely,delz,fx,fy,fz; - double radi,radj,radsum,rsq,r,rinv,rsqinv; - double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3; - double wr1,wr2,wr3; - double vtr1,vtr2,vtr3,vrel; - double mi,mj,meff,damp,ccel,tor1,tor2,tor3; - double fn,fs,fs1,fs2,fs3; - double shrmag,rsht; - int *ilist,*jlist,*numneigh,**firstneigh; - int *touch,**firsttouch; - double *shear,*allshear,**firstshear; - - if (eflag || vflag) ev_setup(eflag,vflag); - else evflag = vflag_fdotr = 0; - - int shearupdate = 1; - if (update->setupflag) shearupdate = 0; - - // update rigid body info for owned & ghost atoms if using FixRigid masses - // body[i] = which body atom I is in, -1 if none - // mass_body = mass of each rigid body - - if (fix_rigid && neighbor->ago == 0) { - int tmp; - int *body = (int *) fix_rigid->extract("body",tmp); - double *mass_body = (double *) fix_rigid->extract("masstotal",tmp); - if (atom->nmax > nmax) { - memory->destroy(mass_rigid); - nmax = atom->nmax; - memory->create(mass_rigid,nmax,"pair:mass_rigid"); - } - int nlocal = atom->nlocal; - for (i = 0; i < nlocal; i++) - if (body[i] >= 0) mass_rigid[i] = mass_body[body[i]]; - else mass_rigid[i] = 0.0; - comm->forward_comm_pair(this); - } - - double **x = atom->x; - double **v = atom->v; - double **f = atom->f; - int *type = atom->type; - double **omega = atom->omega; - double **torque = atom->torque; - double *radius = atom->radius; - double *rmass = atom->rmass; - int *mask = atom->mask; - int nlocal = atom->nlocal; - int newton_pair = force->newton_pair; - - inum = list->inum; - ilist = list->ilist; - numneigh = list->numneigh; - firstneigh = list->firstneigh; - firsttouch = fix_history->firstflag; - firstshear = fix_history->firstvalue; - - // loop over neighbors of my atoms - - for (ii = 0; ii < inum; ii++) { - i = ilist[ii]; - xtmp = x[i][0]; - ytmp = x[i][1]; - ztmp = x[i][2]; - itype = type[i]; - radi = radius[i]; - touch = firsttouch[i]; - allshear = firstshear[i]; - jlist = firstneigh[i]; - jnum = numneigh[i]; - - for (jj = 0; jj < jnum; jj++) { - j = jlist[jj]; - j &= NEIGHMASK; - - delx = xtmp - x[j][0]; - dely = ytmp - x[j][1]; - delz = ztmp - x[j][2]; - rsq = delx*delx + dely*dely + delz*delz; - jtype = type[j]; - radj = radius[j]; - radsum = radi + radj; - - if (rsq >= radsum*radsum) { - - // unset non-touching neighbors - - touch[jj] = 0; - shear = &allshear[3*jj]; - shear[0] = 0.0; - shear[1] = 0.0; - shear[2] = 0.0; - - } else { - r = sqrt(rsq); - rinv = 1.0/r; - rsqinv = 1.0/rsq; - - // relative translational velocity - - vr1 = v[i][0] - v[j][0]; - vr2 = v[i][1] - v[j][1]; - vr3 = v[i][2] - v[j][2]; - - // normal component - - vnnr = vr1*delx + vr2*dely + vr3*delz; - vn1 = delx*vnnr * rsqinv; - vn2 = dely*vnnr * rsqinv; - vn3 = delz*vnnr * rsqinv; - - // tangential component - - vt1 = vr1 - vn1; - vt2 = vr2 - vn2; - vt3 = vr3 - vn3; - - // relative rotational velocity - - wr1 = (radi*omega[i][0] + radj*omega[j][0]) * rinv; - wr2 = (radi*omega[i][1] + radj*omega[j][1]) * rinv; - wr3 = (radi*omega[i][2] + radj*omega[j][2]) * rinv; - - // meff = effective mass of pair of particles - // if I or J part of rigid body, use body mass - // if I or J is frozen, meff is other particle - - mi = rmass[i]; - mj = rmass[j]; - if (fix_rigid) { - if (mass_rigid[i] > 0.0) mi = mass_rigid[i]; - if (mass_rigid[j] > 0.0) mj = mass_rigid[j]; - } - - meff = mi*mj / (mi+mj); - if (mask[i] & freeze_group_bit) meff = mj; - if (mask[j] & freeze_group_bit) meff = mi; - - // normal forces = Hookian contact + normal velocity damping - - damp = meff*gamman[itype][jtype]*vnnr*rsqinv; - ccel = kn[itype][jtype]*(radsum-r)*rinv - damp; - - // relative velocities - - vtr1 = vt1 - (delz*wr2-dely*wr3); - vtr2 = vt2 - (delx*wr3-delz*wr1); - vtr3 = vt3 - (dely*wr1-delx*wr2); - vrel = vtr1*vtr1 + vtr2*vtr2 + vtr3*vtr3; - vrel = sqrt(vrel); - - // shear history effects - - touch[jj] = 1; - shear = &allshear[3*jj]; - - if (shearupdate) { - shear[0] += vtr1*dt; - shear[1] += vtr2*dt; - shear[2] += vtr3*dt; - } - shrmag = sqrt(shear[0]*shear[0] + shear[1]*shear[1] + - shear[2]*shear[2]); - - // rotate shear displacements - - rsht = shear[0]*delx + shear[1]*dely + shear[2]*delz; - rsht *= rsqinv; - if (shearupdate) { - shear[0] -= rsht*delx; - shear[1] -= rsht*dely; - shear[2] -= rsht*delz; - } - - // tangential forces = shear + tangential velocity damping - - fs1 = - (kt[itype][jtype]*shear[0] + meff*gammat[itype][jtype]*vtr1); - fs2 = - (kt[itype][jtype]*shear[1] + meff*gammat[itype][jtype]*vtr2); - fs3 = - (kt[itype][jtype]*shear[2] + meff*gammat[itype][jtype]*vtr3); - - // rescale frictional displacements and forces if needed - - fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); - fn = xmu[itype][jtype] * fabs(ccel*r); - - if (fs > fn) { - if (shrmag != 0.0) { - shear[0] = (fn/fs) * (shear[0] + - meff*gammat[itype][jtype]*vtr1/kt[itype][jtype]) - - meff*gammat[itype][jtype]*vtr1/kt[itype][jtype]; - shear[1] = (fn/fs) * (shear[1] + - meff*gammat[itype][jtype]*vtr2/kt[itype][jtype]) - - meff*gammat[itype][jtype]*vtr2/kt[itype][jtype]; - shear[2] = (fn/fs) * (shear[2] + - meff*gammat[itype][jtype]*vtr3/kt[itype][jtype]) - - meff*gammat[itype][jtype]*vtr3/kt[itype][jtype]; - fs1 *= fn/fs; - fs2 *= fn/fs; - fs3 *= fn/fs; - } else fs1 = fs2 = fs3 = 0.0; - } - - // forces & torques - - fx = delx*ccel + fs1; - fy = dely*ccel + fs2; - fz = delz*ccel + fs3; - f[i][0] += fx; - f[i][1] += fy; - f[i][2] += fz; - - tor1 = rinv * (dely*fs3 - delz*fs2); - tor2 = rinv * (delz*fs1 - delx*fs3); - tor3 = rinv * (delx*fs2 - dely*fs1); - torque[i][0] -= radi*tor1; - torque[i][1] -= radi*tor2; - torque[i][2] -= radi*tor3; - - if (newton_pair || j < nlocal) { - f[j][0] -= fx; - f[j][1] -= fy; - f[j][2] -= fz; - torque[j][0] -= radj*tor1; - torque[j][1] -= radj*tor2; - torque[j][2] -= radj*tor3; - } - - if (evflag) ev_tally_xyz(i,j,nlocal,newton_pair, - 0.0,0.0,fx,fy,fz,delx,dely,delz); - } - } - } - - if (vflag_fdotr) virial_fdotr_compute(); -} - -/* ---------------------------------------------------------------------- - allocate all arrays -------------------------------------------------------------------------- */ - -void PairGranHookeHistoryMulti::allocate() -{ - allocated = 1; - int n = atom->ntypes; - - memory->create(setflag,n+1,n+1,"pair:setflag"); - for (int i = 1; i <= n; i++) - for (int j = i; j <= n; j++) - setflag[i][j] = 0; - - memory->create(cutsq,n+1,n+1,"pair:cutsq"); - memory->create(cut,n+1,n+1,"pair:cut"); - memory->create(kn,n+1,n+1,"pair:kn"); - memory->create(kt,n+1,n+1,"pair:kt"); - memory->create(gamman,n+1,n+1,"pair:gamman"); - memory->create(gammat,n+1,n+1,"pair:gammat"); - memory->create(xmu,n+1,n+1,"pair:xmu"); - memory->create(dampflag,n+1,n+1,"pair:dampflag"); - - onerad_dynamic = new double[n+1]; - onerad_frozen = new double[n+1]; - maxrad_dynamic = new double[n+1]; - maxrad_frozen = new double[n+1]; -} - -/* ---------------------------------------------------------------------- - global settings -------------------------------------------------------------------------- */ - -void PairGranHookeHistoryMulti::settings(int narg, char **arg) -{ - if (narg != 1) error->all(FLERR,"Illegal pair_style command"); - - if (strcmp(arg[0],"NULL") == 0 ) cut_global = -1.0; - else cut_global = force->numeric(FLERR,arg[0]); - - // reset cutoffs that have been explicitly set - if (allocated) { - int i,j; - for (i = 1; i <= atom->ntypes; i++) - for (j = i; j <= atom->ntypes; j++) - if (setflag[i][j]) cut[i][j] = cut_global; - } -} - -/* ---------------------------------------------------------------------- - set coeffs for one or more type pairs -------------------------------------------------------------------------- */ - -void PairGranHookeHistoryMulti::coeff(int narg, char **arg) -{ - if (narg < 8 || narg > 9) - error->all(FLERR,"Incorrect args for pair coefficients"); - - if (!allocated) allocate(); - - int ilo,ihi,jlo,jhi; - force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); - force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); - - double kn_one = force->numeric(FLERR,arg[2]); - double kt_one; - if (strcmp(arg[3],"NULL") == 0) kt_one = kn_one * 2.0/7.0; - else kt_one = force->numeric(FLERR,arg[3]); - - double gamman_one = force->numeric(FLERR,arg[4]); - double gammat_one; - if (strcmp(arg[5],"NULL") == 0) gammat_one = 0.5 * gamman_one; - else gammat_one = force->numeric(FLERR,arg[5]); - - double xmu_one = force->numeric(FLERR,arg[6]); - int dampflag_one = force->inumeric(FLERR,arg[7]); - if (dampflag_one == 0) gammat_one = 0.0; - - if (kn_one < 0.0 || kt_one < 0.0 || gamman_one < 0.0 || gammat_one < 0.0 || - xmu_one < 0.0 || xmu_one > 10000.0 || dampflag_one < 0 || dampflag_one > 1) - error->all(FLERR,"Illegal pair_style command"); - - // convert Kn and Kt from pressure units to force/distance^2 - kn_one /= force->nktv2p; - kt_one /= force->nktv2p; - - double cut_one = cut_global; - if (narg==9) { - if (strcmp(arg[8],"NULL") == 0) cut_one = -1.0; - else cut_one = force->numeric(FLERR,arg[8]); - } - - int count = 0; - for (int i = ilo; i <= ihi; i++) { - for (int j = MAX(jlo,i); j <= jhi; j++) { - kn[i][j] = kn_one; - kt[i][j] = kt_one; - gamman[i][j] = gamman_one; - gammat[i][j] = gammat_one; - xmu[i][j] = xmu_one; - dampflag[i][j] = dampflag_one; - cut[i][j] = cut_one; - setflag[i][j] = 1; - count++; - } - } - - if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); -} - -/* ---------------------------------------------------------------------- - init specific to this pair style -------------------------------------------------------------------------- */ - -void PairGranHookeHistoryMulti::init_style() -{ - int i; - - // error and warning checks - - if (!atom->radius_flag || !atom->rmass_flag) - error->all(FLERR,"Pair granular requires atom attributes radius, rmass"); - if (comm->ghost_velocity == 0) - error->all(FLERR,"Pair granular requires ghost atoms store velocity"); - - // need a granular neigh list - - int irequest = neighbor->request(this,instance_me); - neighbor->requests[irequest]->size = 1; - if (history) neighbor->requests[irequest]->history = 1; - - dt = update->dt; - - // if shear history is stored: - // if first init, create Fix needed for storing shear history - - if (history && fix_history == NULL) { - char dnumstr[16]; - sprintf(dnumstr,"%d",3); - char **fixarg = new char*[4]; - fixarg[0] = (char *) "NEIGH_HISTORY"; - fixarg[1] = (char *) "all"; - fixarg[2] = (char *) "NEIGH_HISTORY"; - fixarg[3] = dnumstr; - modify->add_fix(4,fixarg,1); - delete [] fixarg; - fix_history = (FixNeighHistory *) modify->fix[modify->nfix-1]; - fix_history->pair = this; - } - - // check for FixFreeze and set freeze_group_bit - - for (i = 0; i < modify->nfix; i++) - if (strcmp(modify->fix[i]->style,"freeze") == 0) break; - if (i < modify->nfix) freeze_group_bit = modify->fix[i]->groupbit; - else freeze_group_bit = 0; - - // check for FixRigid so can extract rigid body masses - - fix_rigid = NULL; - for (i = 0; i < modify->nfix; i++) - if (modify->fix[i]->rigid_flag) break; - if (i < modify->nfix) fix_rigid = modify->fix[i]; - - // check for FixPour and FixDeposit so can extract particle radii - - int ipour; - for (ipour = 0; ipour < modify->nfix; ipour++) - if (strcmp(modify->fix[ipour]->style,"pour") == 0) break; - if (ipour == modify->nfix) ipour = -1; - - int idep; - for (idep = 0; idep < modify->nfix; idep++) - if (strcmp(modify->fix[idep]->style,"deposit") == 0) break; - if (idep == modify->nfix) idep = -1; - - // set maxrad_dynamic and maxrad_frozen for each type - // include future FixPour and FixDeposit particles as dynamic - - int itype; - for (i = 1; i <= atom->ntypes; i++) { - onerad_dynamic[i] = onerad_frozen[i] = 0.0; - if (ipour >= 0) { - itype = i; - onerad_dynamic[i] = - *((double *) modify->fix[ipour]->extract("radius",itype)); - } - if (idep >= 0) { - itype = i; - onerad_dynamic[i] = - *((double *) modify->fix[idep]->extract("radius",itype)); - } - } - - double *radius = atom->radius; - int *mask = atom->mask; - int *type = atom->type; - int nlocal = atom->nlocal; - - for (i = 0; i < nlocal; i++) - if (mask[i] & freeze_group_bit) - onerad_frozen[type[i]] = MAX(onerad_frozen[type[i]],radius[i]); - else - onerad_dynamic[type[i]] = MAX(onerad_dynamic[type[i]],radius[i]); - - MPI_Allreduce(&onerad_dynamic[1],&maxrad_dynamic[1],atom->ntypes, - MPI_DOUBLE,MPI_MAX,world); - MPI_Allreduce(&onerad_frozen[1],&maxrad_frozen[1],atom->ntypes, - MPI_DOUBLE,MPI_MAX,world); - - // set fix which stores history info - - if (history) { - int ifix = modify->find_fix("NEIGH_HISTORY"); - if (ifix < 0) error->all(FLERR,"Could not find pair fix neigh history ID"); - fix_history = (FixNeighHistory *) modify->fix[ifix]; - } -} - -/* ---------------------------------------------------------------------- - init for one type pair i,j and corresponding j,i -------------------------------------------------------------------------- */ - -double PairGranHookeHistoryMulti::init_one(int i, int j) -{ - if (setflag[i][j] == 0) { - kn[i][j] = mix_stiffness(kn[i][i],kn[j][j]); - kt[i][j] = mix_stiffness(kt[i][i],kt[j][j]); - gamman[i][j] = mix_damping(gamman[i][i],gamman[j][j]); - gammat[i][j] = mix_damping(gammat[i][i],gammat[j][j]); - xmu[i][j] = mix_friction(xmu[i][i],xmu[j][j]); - - dampflag[i][j] = 0; - if (dampflag[i][i] || dampflag[j][j]) dampflag[i][j] = 1; - - } - - kn[j][i] = kn[i][j]; - kt[j][i] = kt[i][j]; - gamman[j][i] = gamman[i][j]; - gammat[j][i] = gammat[i][j]; - xmu[j][i] = xmu[i][j]; - dampflag[j][i] = dampflag[i][j]; - - double cutoff = cut[i][j]; - - // It is likely that cut[i][j] at this point is still 0.0. This can happen when - // there is a future fix_pour after the current run. A cut[i][j] = 0.0 creates - // problems because neighbor.cpp uses min(cut[i][j]) to decide on the bin size - // To avoid this issue,for cases involving cut[i][j] = 0.0 (possible only - // if there is no current information about radius/cutoff of type i and j). - // we assign cutoff = min(cut[i][j]) for i,j such that cut[i][j] > 0.0. - - if (cut[i][j] < 0.0) { - if (((maxrad_dynamic[i] > 0.0) && (maxrad_dynamic[j] > 0.0)) || ((maxrad_dynamic[i] > 0.0) && (maxrad_frozen[j] > 0.0)) || - ((maxrad_frozen[i] > 0.0) && (maxrad_dynamic[j] > 0.0))) { // radius info about both i and j exist - cutoff = maxrad_dynamic[i]+maxrad_dynamic[j]; - cutoff = MAX(cutoff,maxrad_frozen[i]+maxrad_dynamic[j]); - cutoff = MAX(cutoff,maxrad_dynamic[i]+maxrad_frozen[j]); - } - else { // radius info about either i or j does not exist (i.e. not present and not about to get poured; set to largest value to not interfere with neighbor list) - double cutmax = 0.0; - for (int k = 1; k <= atom->ntypes; k++) { - cutmax = MAX(cutmax,2.0*maxrad_dynamic[k]); - cutmax = MAX(cutmax,2.0*maxrad_frozen[k]); - } - cutoff = cutmax; - } - } - return cutoff; -} - -/* ---------------------------------------------------------------------- - proc 0 writes to restart file -------------------------------------------------------------------------- */ - -void PairGranHookeHistoryMulti::write_restart(FILE *fp) -{ - write_restart_settings(fp); - - int i,j; - for (i = 1; i <= atom->ntypes; i++) { - for (j = i; j <= atom->ntypes; j++) { - fwrite(&setflag[i][j],sizeof(int),1,fp); - if (setflag[i][j]) { - fwrite(&kn[i][j],sizeof(double),1,fp); - fwrite(&kt[i][j],sizeof(double),1,fp); - fwrite(&gamman[i][j],sizeof(double),1,fp); - fwrite(&gammat[i][j],sizeof(double),1,fp); - fwrite(&xmu[i][j],sizeof(double),1,fp); - fwrite(&dampflag[i][j],sizeof(int),1,fp); - fwrite(&cut[i][j],sizeof(double),1,fp); - } - } - } -} - -/* ---------------------------------------------------------------------- - proc 0 reads from restart file, bcasts -------------------------------------------------------------------------- */ - -void PairGranHookeHistoryMulti::read_restart(FILE *fp) -{ - read_restart_settings(fp); - allocate(); - - int i,j; - int me = comm->me; - for (i = 1; i <= atom->ntypes; i++) { - for (j = i; j <= atom->ntypes; j++) { - if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp); - MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world); - if (setflag[i][j]) { - if (me == 0) { - fread(&kn[i][j],sizeof(double),1,fp); - fread(&kt[i][j],sizeof(double),1,fp); - fread(&gamman[i][j],sizeof(double),1,fp); - fread(&gammat[i][j],sizeof(double),1,fp); - fread(&xmu[i][j],sizeof(double),1,fp); - fread(&dampflag[i][j],sizeof(int),1,fp); - fread(&cut[i][j],sizeof(double),1,fp); - } - MPI_Bcast(&kn[i][j],1,MPI_DOUBLE,0,world); - MPI_Bcast(&kt[i][j],1,MPI_DOUBLE,0,world); - MPI_Bcast(&gamman[i][j],1,MPI_DOUBLE,0,world); - MPI_Bcast(&gammat[i][j],1,MPI_DOUBLE,0,world); - MPI_Bcast(&xmu[i][j],1,MPI_DOUBLE,0,world); - MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); - MPI_Bcast(&dampflag[i][j],1,MPI_INT,0,world); - } - } - } -} - -/* ---------------------------------------------------------------------- - proc 0 writes to restart file -------------------------------------------------------------------------- */ - -void PairGranHookeHistoryMulti::write_restart_settings(FILE *fp) -{ - fwrite(&cut_global,sizeof(double),1,fp); -} - -/* ---------------------------------------------------------------------- - proc 0 reads from restart file, bcasts -------------------------------------------------------------------------- */ - -void PairGranHookeHistoryMulti::read_restart_settings(FILE *fp) -{ - if (comm->me == 0) { - fread(&cut_global,sizeof(double),1,fp); - } - MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world); -} - -/* ---------------------------------------------------------------------- */ - -void PairGranHookeHistoryMulti::reset_dt() -{ - dt = update->dt; -} - -/* ---------------------------------------------------------------------- */ - -double PairGranHookeHistoryMulti::single(int i, int j, int itype, int jtype, - double rsq, - double factor_coul, double factor_lj, - double &fforce) -{ - double radi,radj,radsum; - double r,rinv,rsqinv,delx,dely,delz; - double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3,wr1,wr2,wr3; - double mi,mj,meff,damp,ccel; - double vtr1,vtr2,vtr3,vrel,shrmag,rsht; - double fs1,fs2,fs3,fs,fn; - - double *radius = atom->radius; - radi = radius[i]; - radj = radius[j]; - radsum = radi + radj; - - if (rsq >= radsum*radsum) { - fforce = 0.0; - for (int m = 0; m < single_extra; m++) svector[m] = 0.0; - return 0.0; - } - - r = sqrt(rsq); - rinv = 1.0/r; - rsqinv = 1.0/rsq; - - // relative translational velocity - - double **v = atom->v; - vr1 = v[i][0] - v[j][0]; - vr2 = v[i][1] - v[j][1]; - vr3 = v[i][2] - v[j][2]; - - // normal component - - double **x = atom->x; - delx = x[i][0] - x[j][0]; - dely = x[i][1] - x[j][1]; - delz = x[i][2] - x[j][2]; - - vnnr = vr1*delx + vr2*dely + vr3*delz; - vn1 = delx*vnnr * rsqinv; - vn2 = dely*vnnr * rsqinv; - vn3 = delz*vnnr * rsqinv; - - // tangential component - - vt1 = vr1 - vn1; - vt2 = vr2 - vn2; - vt3 = vr3 - vn3; - - // relative rotational velocity - - double **omega = atom->omega; - wr1 = (radi*omega[i][0] + radj*omega[j][0]) * rinv; - wr2 = (radi*omega[i][1] + radj*omega[j][1]) * rinv; - wr3 = (radi*omega[i][2] + radj*omega[j][2]) * rinv; - - // meff = effective mass of pair of particles - // if I or J part of rigid body, use body mass - // if I or J is frozen, meff is other particle - - double *rmass = atom->rmass; - int *mask = atom->mask; - - mi = rmass[i]; - mj = rmass[j]; - if (fix_rigid) { - // NOTE: insure mass_rigid is current for owned+ghost atoms? - if (mass_rigid[i] > 0.0) mi = mass_rigid[i]; - if (mass_rigid[j] > 0.0) mj = mass_rigid[j]; - } - - meff = mi*mj / (mi+mj); - if (mask[i] & freeze_group_bit) meff = mj; - if (mask[j] & freeze_group_bit) meff = mi; - - // normal forces = Hookian contact + normal velocity damping - - damp = meff*gamman[itype][jtype]*vnnr*rsqinv; - ccel = kn[itype][jtype]*(radsum-r)*rinv - damp; - - // relative velocities - - vtr1 = vt1 - (delz*wr2-dely*wr3); - vtr2 = vt2 - (delx*wr3-delz*wr1); - vtr3 = vt3 - (dely*wr1-delx*wr2); - vrel = vtr1*vtr1 + vtr2*vtr2 + vtr3*vtr3; - vrel = sqrt(vrel); - - // shear history effects - // neighprev = index of found neigh on previous call - // search entire jnum list of neighbors of I for neighbor J - // start from neighprev, since will typically be next neighbor - // reset neighprev to 0 as necessary - - int jnum = list->numneigh[i]; - int *jlist = list->firstneigh[i]; - double *allshear = fix_history->firstvalue[i]; - - for (int jj = 0; jj < jnum; jj++) { - neighprev++; - if (neighprev >= jnum) neighprev = 0; - if (jlist[neighprev] == j) break; - } - - double *shear = &allshear[3*neighprev]; - shrmag = sqrt(shear[0]*shear[0] + shear[1]*shear[1] + - shear[2]*shear[2]); - - // rotate shear displacements - - rsht = shear[0]*delx + shear[1]*dely + shear[2]*delz; - rsht *= rsqinv; - - // tangential forces = shear + tangential velocity damping - - fs1 = - (kt[itype][jtype]*shear[0] + meff*gammat[itype][jtype]*vtr1); - fs2 = - (kt[itype][jtype]*shear[1] + meff*gammat[itype][jtype]*vtr2); - fs3 = - (kt[itype][jtype]*shear[2] + meff*gammat[itype][jtype]*vtr3); - - // rescale frictional displacements and forces if needed - - fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); - fn = xmu[itype][jtype] * fabs(ccel*r); - - if (fs > fn) { - if (shrmag != 0.0) { - fs1 *= fn/fs; - fs2 *= fn/fs; - fs3 *= fn/fs; - fs *= fn/fs; - } else fs1 = fs2 = fs3 = fs = 0.0; - } - - // set force and return no energy - - fforce = ccel; - - // set single_extra quantities - - svector[0] = fs1; - svector[1] = fs2; - svector[2] = fs3; - svector[3] = fs; - svector[4] = vn1; - svector[5] = vn2; - svector[6] = vn3; - svector[7] = vt1; - svector[8] = vt2; - svector[9] = vt3; - - return 0.0; -} - -/* ---------------------------------------------------------------------- */ - -int PairGranHookeHistoryMulti::pack_forward_comm(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = mass_rigid[j]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void PairGranHookeHistoryMulti::unpack_forward_comm(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) - mass_rigid[i] = buf[m++]; -} - -/* ---------------------------------------------------------------------- - memory usage of local atom-based arrays -------------------------------------------------------------------------- */ - -double PairGranHookeHistoryMulti::memory_usage() -{ - double bytes = nmax * sizeof(double); - return bytes; -} - -/* ---------------------------------------------------------------------- - mixing of stiffness -------------------------------------------------------------------------- */ - -double PairGranHookeHistoryMulti::mix_stiffness(double kii, double kjj) -{ - return kii*kjj/(kii + kjj); -} - -/* ---------------------------------------------------------------------- - mixing of damping -------------------------------------------------------------------------- */ - -double PairGranHookeHistoryMulti::mix_damping(double gammaii, double gammajj) -{ - return sqrt(gammaii*gammajj); -} - -/* ---------------------------------------------------------------------- - mixing of friction -------------------------------------------------------------------------- */ - -double PairGranHookeHistoryMulti::mix_friction(double xmuii, double xmujj) -{ - return MAX(xmuii,xmujj); -} - diff --git a/src/GRANULAR/pair_gran_hooke_history_multi.h b/src/GRANULAR/pair_gran_hooke_history_multi.h deleted file mode 100644 index f302ede96c..0000000000 --- a/src/GRANULAR/pair_gran_hooke_history_multi.h +++ /dev/null @@ -1,109 +0,0 @@ -/* -*- 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. -------------------------------------------------------------------------- */ - -#ifdef PAIR_CLASS - -PairStyle(gran/hooke/history/multi,PairGranHookeHistoryMulti) - -#else - -#ifndef LMP_PAIR_GRAN_HOOKE_HISTORY_MULTI_H -#define LMP_PAIR_GRAN_HOOKE_HISTORY_MULTI_H - -#include "pair.h" - -namespace LAMMPS_NS { - -class PairGranHookeHistoryMulti : public Pair { - public: - PairGranHookeHistoryMulti(class LAMMPS *); - virtual ~PairGranHookeHistoryMulti(); - virtual void compute(int, int); - virtual void settings(int, char **); - virtual void coeff(int, char **); // Made Virtual by IS Oct 7 2017 - void init_style(); - double init_one(int, int); - void write_restart(FILE *); - void read_restart(FILE *); - void write_restart_settings(FILE *); - void read_restart_settings(FILE *); - void reset_dt(); - virtual double single(int, int, int, int, double, double, double, double &); - int pack_forward_comm(int, int *, double *, int, int *); - void unpack_forward_comm(int, int, double *); - double memory_usage(); - - protected: - double cut_global; - double **kn,**kt,**gamman,**gammat,**xmu,**cut; - int **dampflag; - double dt; - int freeze_group_bit; - int history; - - int neighprev; - double *onerad_dynamic,*onerad_frozen; - double *maxrad_dynamic,*maxrad_frozen; - - class FixNeighHistory *fix_history; - - // storage of rigid body masses for use in granular interactions - - class Fix *fix_rigid; // ptr to rigid body fix, NULL if none - double *mass_rigid; // rigid mass for owned+ghost atoms - int nmax; // allocated size of mass_rigid - - virtual void allocate(); // Made Virtual by IS Oct 7 2017 - -private: - double mix_stiffness(double kii, double kjj); - double mix_damping(double gammaii, double gammajj); - double mix_friction(double xmuii, double xmujj); -}; - -} - -#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 granular requires atom attributes radius, rmass - -The atom style defined does not have these attributes. - -E: Pair granular requires ghost atoms store velocity - -Use the comm_modify vel yes command to enable this. - -E: Pair granular with shear history requires newton pair off - -This is a current restriction of the implementation of pair -granular styles with history. - -E: Could not find pair fix ID - -A fix is created internally by the pair style to store shear -history information. You cannot delete it. - -*/ diff --git a/src/GRANULAR/pair_gran_jkr_rolling.cpp b/src/GRANULAR/pair_gran_jkr_rolling.cpp deleted file mode 100644 index ce109cccbc..0000000000 --- a/src/GRANULAR/pair_gran_jkr_rolling.cpp +++ /dev/null @@ -1,763 +0,0 @@ -/* ---------------------------------------------------------------------- - http://lammps.sandia.gov, Sandia National Laboratories - Steve Plimpton, sjplimp@sandia.gov - - Copyright (2003) Sandia Corporation. Under the terms of Contract - DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains - certain rights in this software. This software is distributed under - the GNU General Public License. - - See the README file in the top-level LAMMPS directory. - ------------------------------------------------------------------------- */ - -/* ---------------------------------------------------------------------- - Contributing authors: Leo Silbert (SNL), Gary Grest (SNL) - ------------------------------------------------------------------------- */ - -#include -#include -#include -#include -#include "pair_gran_jkr_rolling.h" -#include "atom.h" -#include "update.h" -#include "force.h" -#include "fix.h" -#include "fix_neigh_history.h" -#include "neighbor.h" -#include "neigh_list.h" -#include "comm.h" -#include "memory.h" -#include "error.h" -#include "math_const.h" - -using namespace LAMMPS_NS; -using namespace MathConst; - -#define ONETHIRD 0.33333333333333333 -#define TWOTHIRDS 0.66666666666666666 -#define POW6ONE 0.550321208149104 //6^(-1/3) -#define POW6TWO 0.30285343213869 //6^(-2/3) - -#define EPSILON 1e-10 - -enum {TSUJI, BRILLIANTOV}; -enum {INDEP, BRILLROLL}; - -/* ---------------------------------------------------------------------- */ - -PairGranJKRRolling::PairGranJKRRolling(LAMMPS *lmp) : - PairGranHookeHistory(lmp, 7) -{ - E_one = NULL; - G_one = NULL; - pois = NULL; - muS_one = NULL; - cor = NULL; - alpha_one = NULL; - Ecoh_one = NULL; - kR_one = NULL; - muR_one = NULL; - etaR_one = NULL; - int ntypes = atom->ntypes; - memory->create(E,ntypes+1,ntypes+1,"pair:E"); - memory->create(G,ntypes+1,ntypes+1,"pair:G"); - memory->create(alpha,ntypes+1,ntypes+1,"pair:alpha"); - memory->create(gamman,ntypes+1,ntypes+1,"pair:gamman"); - memory->create(muS,ntypes+1,ntypes+1,"pair:muS"); - memory->create(Ecoh,ntypes+1,ntypes+1,"pair:Ecoh"); - memory->create(kR,ntypes+1,ntypes+1,"pair:kR"); - memory->create(muR,ntypes+1,ntypes+1,"pair:muR"); - memory->create(etaR,ntypes+1,ntypes+1,"pair:etaR"); -} - -/* ---------------------------------------------------------------------- */ -PairGranJKRRolling::~PairGranJKRRolling() -{ - delete [] E_one; - delete [] G_one; - delete [] pois; - delete [] muS_one; - delete [] cor; - delete [] alpha_one; - delete [] Ecoh_one; - delete [] kR_one; - delete [] muR_one; - delete [] etaR_one; - //TODO: Make all this work with standard pair coeff type commands. - //Also these should not be in the destructor. - memory->destroy(E); - memory->destroy(G); - memory->destroy(alpha); - memory->destroy(gamman); - memory->destroy(muS); - memory->destroy(Ecoh); - memory->destroy(kR); - memory->destroy(muR); - memory->destroy(etaR); -} -/* ---------------------------------------------------------------------- */ - -void PairGranJKRRolling::compute(int eflag, int vflag) -{ - int i,j,ii,jj,inum,jnum; - int itype,jtype; - double xtmp,ytmp,ztmp,delx,dely,delz,fx,fy,fz,nx,ny,nz; - double radi,radj,radsum,rsq,r,rinv,rsqinv,R,a; - double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3; - double wr1,wr2,wr3; - double vtr1,vtr2,vtr3,vrel; - double kn, kt, k_Q, k_R, eta_N, eta_T, eta_Q, eta_R; - double Fne, Fdamp, Fntot, Fscrit, Frcrit, F_C, delta_C, delta_Cinv; - double overlap, olapsq, olapcubed, sqrtterm, tmp, a0; - double keyterm, keyterm2, keyterm3, aovera0, foverFc; - double mi,mj,meff,damp,ccel,tor1,tor2,tor3; - double relrot1,relrot2,relrot3,vrl1,vrl2,vrl3,vrlmag,vrlmaginv; - double rollmag, rolldotn, scalefac; - double fr, fr1, fr2, fr3; - double signtwist, magtwist, magtortwist, Mtcrit; - double fs,fs1,fs2,fs3,roll1,roll2,roll3,torroll1,torroll2,torroll3; - double tortwist1, tortwist2, tortwist3; - double shrmag,rsht; - int *ilist,*jlist,*numneigh,**firstneigh; - int *touch,**firsttouch; - double *shear,*allshear,**firstshear; - - if (eflag || vflag) ev_setup(eflag,vflag); - else evflag = vflag_fdotr = 0; - - int shearupdate = 1; - if (update->setupflag) shearupdate = 0; - - // update rigid body info for owned & ghost atoms if using FixRigid masses - // body[i] = which body atom I is in, -1 if none - // mass_body = mass of each rigid body - - if (fix_rigid && neighbor->ago == 0){ - int tmp; - int *body = (int *) fix_rigid->extract("body",tmp); - double *mass_body = (double *) fix_rigid->extract("masstotal",tmp); - if (atom->nmax > nmax) { - memory->destroy(mass_rigid); - nmax = atom->nmax; - memory->create(mass_rigid,nmax,"pair:mass_rigid"); - } - int nlocal = atom->nlocal; - for (i = 0; i < nlocal; i++) - if (body[i] >= 0) mass_rigid[i] = mass_body[body[i]]; - else mass_rigid[i] = 0.0; - comm->forward_comm_pair(this); - } - - double **x = atom->x; - double **v = atom->v; - double **f = atom->f; - double **omega = atom->omega; - double **torque = atom->torque; - double *radius = atom->radius; - double *rmass = atom->rmass; - int *type = atom->type; - int *mask = atom->mask; - int nlocal = atom->nlocal; - - inum = list->inum; - ilist = list->ilist; - numneigh = list->numneigh; - firstneigh = list->firstneigh; - firsttouch = fix_history->firstflag; - firstshear = fix_history->firstvalue; - - // loop over neighbors of my atoms - - for (ii = 0; ii < inum; ii++) { - i = ilist[ii]; - itype = type[i]; - xtmp = x[i][0]; - ytmp = x[i][1]; - ztmp = x[i][2]; - radi = radius[i]; - touch = firsttouch[i]; - allshear = firstshear[i]; - jlist = firstneigh[i]; - jnum = numneigh[i]; - - for (jj = 0; jj < jnum; jj++) { - j = jlist[jj]; - jtype = type[j]; - j &= NEIGHMASK; - - delx = xtmp - x[j][0]; - dely = ytmp - x[j][1]; - delz = ztmp - x[j][2]; - rsq = delx*delx + dely*dely + delz*delz; - radj = radius[j]; - radsum = radi + radj; - R = radi*radj/(radi+radj); - a0 = pow(9.0*M_PI*Ecoh[itype][jtype]*R*R/E[itype][jtype],ONETHIRD); - delta_C = 0.5*a0*a0*POW6ONE/R; - - if ((rsq >= radsum*radsum && touch[jj] == 0) || - (rsq >= (radsum+delta_C)*(radsum+delta_C))){ - // unset non-touching neighbors - touch[jj] = 0; - shear = &allshear[size_history*jj]; - for (int k = 0; k < size_history; k++) - shear[k] = 0.0; - } else { - F_C = 3.0*R*M_PI*Ecoh[itype][jtype]; - r = sqrt(rsq); - rinv = 1.0/r; - rsqinv = 1.0/rsq; - - nx = delx*rinv; - ny = dely*rinv; - nz = delz*rinv; - - // relative translational velocity - - vr1 = v[i][0] - v[j][0]; - vr2 = v[i][1] - v[j][1]; - vr3 = v[i][2] - v[j][2]; - - // normal component - - vnnr = vr1*nx + vr2*ny + vr3*nz; //v_R . n - vn1 = nx*vnnr; - vn2 = ny*vnnr; - vn3 = nz*vnnr; - - // meff = effective mass of pair of particles - // if I or J part of rigid body, use body mass - // if I or J is frozen, meff is other particle - - mi = rmass[i]; - mj = rmass[j]; - if (fix_rigid) { - if (mass_rigid[i] > 0.0) mi = mass_rigid[i]; - if (mass_rigid[j] > 0.0) mj = mass_rigid[j]; - } - - meff = mi*mj / (mi+mj); - if (mask[i] & freeze_group_bit) meff = mj; - if (mask[j] & freeze_group_bit) meff = mi; - - //**************************************** - //Normal force = JKR-adjusted Hertzian contact + damping - //**************************************** - if (Ecoh[itype][jtype] != 0.0) delta_Cinv = 1.0/delta_C; - else delta_Cinv = 1.0; - overlap = (radsum - r)*delta_Cinv; - olapsq = overlap*overlap; - olapcubed = olapsq*overlap; - sqrtterm = sqrt(1.0 + olapcubed); - tmp = 2.0 + olapcubed + 2.0*sqrtterm; - keyterm = pow(tmp,ONETHIRD); - keyterm2 = olapsq/keyterm; - keyterm3 = sqrt(overlap + keyterm2 + keyterm); - aovera0 = POW6TWO * (keyterm3 + - sqrt(2.0*overlap - keyterm2 - keyterm + 4.0/keyterm3));// eq 41 - a = aovera0*a0; - foverFc = 4.0*((aovera0*aovera0*aovera0) - pow(aovera0,1.5));//F_ne/F_C (eq 40) - - Fne = F_C*foverFc; - - //Damping - kn = 4.0/3.0*E[itype][jtype]*a; - if (normaldamp == BRILLIANTOV) eta_N = a*meff*gamman[itype][jtype]; - else if (normaldamp == TSUJI) eta_N=alpha[itype][jtype]*sqrt(meff*kn); - - Fdamp = -eta_N*vnnr; //F_nd eq 23 and Zhao eq 19 - - Fntot = Fne + Fdamp; - - //**************************************** - //Tangential force, including shear history effects - //**************************************** - - // tangential component - vt1 = vr1 - vn1; - vt2 = vr2 - vn2; - vt3 = vr3 - vn3; - - // relative rotational velocity - //Luding Gran Matt 2008, v10,p235 suggests correcting radi and radj by subtracting - //delta/2, i.e. instead of radi, use distance to center of contact point? - wr1 = (radi*omega[i][0] + radj*omega[j][0]); - wr2 = (radi*omega[i][1] + radj*omega[j][1]); - wr3 = (radi*omega[i][2] + radj*omega[j][2]); - - // relative tangential velocities - vtr1 = vt1 - (nz*wr2-ny*wr3); - vtr2 = vt2 - (nx*wr3-nz*wr1); - vtr3 = vt3 - (ny*wr1-nx*wr2); - vrel = vtr1*vtr1 + vtr2*vtr2 + vtr3*vtr3; - vrel = sqrt(vrel); - - // shear history effects - touch[jj] = 1; - shear = &allshear[size_history*jj]; - shrmag = sqrt(shear[0]*shear[0] + shear[1]*shear[1] + - shear[2]*shear[2]); - - // Rotate and update shear displacements. - // See e.g. eq. 17 of Luding, Gran. Matter 2008, v10,p235 - if (shearupdate) { - rsht = shear[0]*nx + shear[1]*ny + shear[2]*nz; - if (fabs(rsht) < EPSILON) rsht = 0; - if (rsht > 0){ - scalefac = shrmag/(shrmag - rsht); //if rhst == shrmag, contacting pair has rotated 90 deg. in one step, in which case you deserve a crash! - shear[0] -= rsht*nx; - shear[1] -= rsht*ny; - shear[2] -= rsht*nz; - //Also rescale to preserve magnitude - shear[0] *= scalefac; - shear[1] *= scalefac; - shear[2] *= scalefac; - } - //Update shear history - shear[0] += vtr1*dt; - shear[1] += vtr2*dt; - shear[2] += vtr3*dt; - } - - // tangential forces = shear + tangential velocity damping - // following Zhao and Marshall Phys Fluids v20, p043302 (2008) - kt=8.0*G[itype][jtype]*a; - - eta_T = eta_N; //Based on discussion in Marshall; eta_T can also be an independent parameter - fs1 = -kt*shear[0] - eta_T*vtr1; //eq 26 - fs2 = -kt*shear[1] - eta_T*vtr2; - fs3 = -kt*shear[2] - eta_T*vtr3; - - // rescale frictional displacements and forces if needed - Fscrit = muS[itype][jtype] * fabs(Fne + 2*F_C); - // For JKR, use eq 43 of Marshall. For DMT, use Fne instead - - fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); - if (fs > Fscrit) { - if (shrmag != 0.0) { - //shear[0] = (Fcrit/fs) * (shear[0] + eta_T*vtr1/kt) - eta_T*vtr1/kt; - //shear[1] = (Fcrit/fs) * (shear[1] + eta_T*vtr1/kt) - eta_T*vtr1/kt; - //shear[2] = (Fcrit/fs) * (shear[2] + eta_T*vtr1/kt) - eta_T*vtr1/kt; - shear[0] = -1.0/kt*(Fscrit*fs1/fs + eta_T*vtr1); //Same as above, but simpler (check!) - shear[1] = -1.0/kt*(Fscrit*fs2/fs + eta_T*vtr2); - shear[2] = -1.0/kt*(Fscrit*fs3/fs + eta_T*vtr3); - fs1 *= Fscrit/fs; - fs2 *= Fscrit/fs; - fs3 *= Fscrit/fs; - } else fs1 = fs2 = fs3 = 0.0; - } - - //**************************************** - // Rolling force, including shear history effects - //**************************************** - - relrot1 = omega[i][0] - omega[j][0]; - relrot2 = omega[i][1] - omega[j][1]; - relrot3 = omega[i][2] - omega[j][2]; - - // rolling velocity, see eq. 31 of Wang et al, Particuology v 23, p 49 (2015) - // This is different from the Marshall papers, which use the Bagi/Kuhn formulation - // for rolling velocity (see Wang et al for why the latter is wrong) - vrl1 = R*(relrot2*nz - relrot3*ny); //- 0.5*((radj-radi)/radsum)*vtr1; - vrl2 = R*(relrot3*nx - relrot1*nz); //- 0.5*((radj-radi)/radsum)*vtr2; - vrl3 = R*(relrot1*ny - relrot2*nx); //- 0.5*((radj-radi)/radsum)*vtr3; - vrlmag = sqrt(vrl1*vrl1+vrl2*vrl2+vrl3*vrl3); - if (vrlmag != 0.0) vrlmaginv = 1.0/vrlmag; - else vrlmaginv = 0.0; - - // Rolling displacement - rollmag = sqrt(shear[3]*shear[3] + shear[4]*shear[4] + shear[5]*shear[5]); - rolldotn = shear[3]*nx + shear[4]*ny + shear[5]*nz; - - if (shearupdate) { - if (fabs(rolldotn) < EPSILON) rolldotn = 0; - if (rolldotn > 0){ //Rotate into tangential plane - scalefac = rollmag/(rollmag - rolldotn); - shear[3] -= rolldotn*nx; - shear[4] -= rolldotn*ny; - shear[5] -= rolldotn*nz; - //Also rescale to preserve magnitude - shear[3] *= scalefac; - shear[4] *= scalefac; - shear[5] *= scalefac; - } - shear[3] += vrl1*dt; - shear[4] += vrl2*dt; - shear[5] += vrl3*dt; - } - - k_R = kR[itype][jtype]*4.0*F_C*pow(aovera0,1.5); - if (rollingdamp == INDEP) eta_R = etaR[itype][jtype]; - else if (rollingdamp == BRILLROLL) eta_R = muR[itype][jtype]*fabs(Fne); - fr1 = -k_R*shear[3] - eta_R*vrl1; - fr2 = -k_R*shear[4] - eta_R*vrl2; - fr3 = -k_R*shear[5] - eta_R*vrl3; - - // rescale frictional displacements and forces if needed - Frcrit = muR[itype][jtype] * fabs(Fne + 2*F_C); - - fr = sqrt(fr1*fr1 + fr2*fr2 + fr3*fr3); - if (fr > Frcrit) { - if (rollmag != 0.0) { - shear[3] = -1.0/k_R*(Frcrit*fr1/fr + eta_R*vrl1); - shear[4] = -1.0/k_R*(Frcrit*fr2/fr + eta_R*vrl2); - shear[5] = -1.0/k_R*(Frcrit*fr3/fr + eta_R*vrl3); - fr1 *= Frcrit/fr; - fr2 *= Frcrit/fr; - fr3 *= Frcrit/fr; - } else fr1 = fr2 = fr3 = 0.0; - } - - - //**************************************** - // Twisting torque, including shear history effects - //**************************************** - magtwist = relrot1*nx + relrot2*ny + relrot3*nz; //Omega_T (eq 29 of Marshall) - shear[6] += magtwist*dt; - k_Q = 0.5*kt*a*a;; //eq 32 - eta_Q = 0.5*eta_T*a*a; - magtortwist = -k_Q*shear[6] - eta_Q*magtwist;//M_t torque (eq 30) - - signtwist = (magtwist > 0) - (magtwist < 0); - Mtcrit=TWOTHIRDS*a*Fscrit;//critical torque (eq 44) - if (fabs(magtortwist) > Mtcrit) { - //shear[6] = Mtcrit/k_Q*magtwist/fabs(magtwist); - shear[6] = 1.0/k_Q*(Mtcrit*signtwist - eta_Q*magtwist); - magtortwist = -Mtcrit * signtwist; //eq 34 - } - - // Apply forces & torques - - fx = nx*Fntot + fs1; - fy = ny*Fntot + fs2; - fz = nz*Fntot + fs3; - - f[i][0] += fx; - f[i][1] += fy; - f[i][2] += fz; - - tor1 = ny*fs3 - nz*fs2; - tor2 = nz*fs1 - nx*fs3; - tor3 = nx*fs2 - ny*fs1; - - torque[i][0] -= radi*tor1; - torque[i][1] -= radi*tor2; - torque[i][2] -= radi*tor3; - - tortwist1 = magtortwist * nx; - tortwist2 = magtortwist * ny; - tortwist3 = magtortwist * nz; - - torque[i][0] += tortwist1; - torque[i][1] += tortwist2; - torque[i][2] += tortwist3; - - torroll1 = R*(ny*fr3 - nz*fr2); //n cross fr - torroll2 = R*(nz*fr1 - nx*fr3); - torroll3 = R*(nx*fr2 - ny*fr1); - - torque[i][0] += torroll1; - torque[i][1] += torroll2; - torque[i][2] += torroll3; - - if (force->newton_pair || j < nlocal) { - f[j][0] -= fx; - f[j][1] -= fy; - f[j][2] -= fz; - - torque[j][0] -= radj*tor1; - torque[j][1] -= radj*tor2; - torque[j][2] -= radj*tor3; - - torque[j][0] -= tortwist1; - torque[j][1] -= tortwist2; - torque[j][2] -= tortwist3; - - torque[j][0] -= torroll1; - torque[j][1] -= torroll2; - torque[j][2] -= torroll3; - } - if (evflag) ev_tally_xyz(i,j,nlocal,0, - 0.0,0.0,fx,fy,fz,delx,dely,delz); - } - } - } -} - -/* ---------------------------------------------------------------------- - global settings - ------------------------------------------------------------------------- */ - -void PairGranJKRRolling::settings(int narg, char **arg) -{ - if (narg < 6) error->all(FLERR,"Illegal pair_style command"); - - int ntypes = atom->ntypes; - - if (narg < 8*ntypes) error->all(FLERR,"Illegal pair_style command"); - - E_one = new double[ntypes+1]; - G_one = new double[ntypes+1]; - pois = new double[ntypes+1]; - muS_one = new double[ntypes+1]; - cor = new double[ntypes+1]; - alpha_one = new double[ntypes+1]; - Ecoh_one = new double[ntypes+1]; - kR_one = new double[ntypes+1]; - muR_one = new double[ntypes+1]; - etaR_one = new double[ntypes+1]; - - //Defaults - normaldamp = TSUJI; - rollingdamp = INDEP; - - int iarg = 8*ntypes; - while (iarg < narg){ - if (strcmp(arg[iarg],"normaldamp") == 0){ - if (iarg+2 > narg) error->all(FLERR, "Invalid pair/gran/dmt/rolling entry"); - if (strcmp(arg[iarg+1],"tsuji") == 0) normaldamp = TSUJI; - else if (strcmp(arg[iarg+1],"brilliantov") == 0) normaldamp = BRILLIANTOV; - else error->all(FLERR, "Invalid normal damping model for pair/gran/dmt/rolling"); - iarg += 2; - } - else if (strcmp(arg[iarg],"rollingdamp") == 0){ - if (iarg+2 > narg) error->all(FLERR, "Invalid pair/gran/dmt/rolling entry"); - if (strcmp(arg[iarg+1],"independent") == 0) rollingdamp = INDEP; - else if (strcmp(arg[iarg+1],"brilliantov") == 0) rollingdamp = BRILLROLL; - else error->all(FLERR, "Invalid rolling damping model for pair/gran/dmt/rolling"); - iarg +=2; - } - else iarg += 1; - } - - for (int i=0; i < ntypes;i++){ - - E_one[i+1] = force->numeric(FLERR, arg[i]); - G_one[i+1] = force->numeric(FLERR, arg[ntypes+i]); - muS_one[i+1] = force->numeric(FLERR, arg[2*ntypes+i]); - cor[i+1] = force->numeric(FLERR, arg[3*ntypes+i]); - Ecoh_one[i+1] = force->numeric(FLERR, arg[4*ntypes+i]); - kR_one[i+1] = force->numeric(FLERR, arg[5*ntypes+i]); - muR_one[i+1] = force->numeric(FLERR, arg[6*ntypes+i]); - etaR_one[i+1] = force->numeric(FLERR, arg[7*ntypes+i]); - } - - //Optional keywords: - // normaldamp tsuji, or normaldamp brilliantov - // rollingdamp brilliantov - - //Derived from inputs - for (int i=1; i <= ntypes; i++){ - pois[i] = E_one[i]/(2.0*G_one[i]) - 1.0; - alpha_one[i] = 1.2728-4.2783*cor[i]+11.087*cor[i]*cor[i]-22.348*cor[i]*cor[i]*cor[i]+27.467*cor[i]*cor[i]*cor[i]*cor[i]-18.022*cor[i]*cor[i]*cor[i]*cor[i]*cor[i]+4.8218*cor[i]*cor[i]*cor[i]*cor[i]*cor[i]*cor[i]; - for (int j=i; j <= ntypes; j++){ - E[i][j] = E[j][i] = 1/((1-pois[i]*pois[i])/E_one[i]+(1-pois[j]*pois[j])/E_one[j]); - G[i][j] = G[j][i] = 1/((2-pois[i])/G_one[i]+(2-pois[j])/G_one[j]); - if (normaldamp == TSUJI){ - alpha[i][j] = alpha[j][i] = sqrt(alpha_one[i]*alpha_one[j]); - } - else if (normaldamp == BRILLIANTOV){ - gamman[i][j] = gamman[j][i] = sqrt(cor[i]*cor[j]); - } - muS[i][j] = muS[j][i] = sqrt(muS_one[i]*muS_one[j]); - Ecoh[i][j] = Ecoh[j][i] = sqrt(Ecoh_one[i]*Ecoh_one[j]); - kR[i][j] = kR[j][i] = sqrt(kR_one[i]*kR_one[j]); - etaR[i][j] = etaR[j][i] = sqrt(etaR_one[i]*etaR_one[j]); - muR[i][j] = muR[j][i] = sqrt(muR_one[i]*muR_one[j]); - } - } -} - -/* ---------------------------------------------------------------------- */ - -double PairGranJKRRolling::single(int i, int j, int itype, int jtype, - double rsq, - double factor_coul, double factor_lj, - double &fforce) -{//TODO: update PairGranJKRRolling::single for JKR - double radi,radj,radsum; - double r,rinv,rsqinv,delx,dely,delz, nx, ny, nz, R; - double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3,wr1,wr2,wr3; - double overlap, a; - double mi,mj,meff,damp,kn,kt; - double Fdamp,Fne,Fntot,Fscrit; - double eta_N,eta_T; - double vtr1,vtr2,vtr3,vrel; - double fs1,fs2,fs3,fs; - double shrmag; - double F_C, delta_C, olapsq, olapcubed, sqrtterm, tmp, a0; - double keyterm, keyterm2, keyterm3, aovera0, foverFc; - - double *radius = atom->radius; - radi = radius[i]; - radj = radius[j]; - radsum = radi + radj; - - r = sqrt(rsq); - rinv = 1.0/r; - rsqinv = 1.0/rsq; - R = radi*radj/(radi+radj); - a0 = pow(9.0*M_PI*Ecoh[itype][jtype]*R*R/E[itype][jtype],ONETHIRD); - delta_C = 0.5*a0*a0*POW6ONE/R; - - int *touch = fix_history->firstflag[i]; - if ((rsq >= (radsum+delta_C)*(radsum+delta_C) )|| - (rsq >= radsum*radsum && touch[j])){ - fforce = 0.0; - svector[0] = svector[1] = svector[2] = svector[3] = 0.0; - return 0.0; - } - - // relative translational velocity - - double **v = atom->v; - vr1 = v[i][0] - v[j][0]; - vr2 = v[i][1] - v[j][1]; - vr3 = v[i][2] - v[j][2]; - - // normal component - - double **x = atom->x; - delx = x[i][0] - x[j][0]; - dely = x[i][1] - x[j][1]; - delz = x[i][2] - x[j][2]; - - nx = delx*rinv; - ny = dely*rinv; - nz = delz*rinv; - - - vnnr = vr1*nx + vr2*ny + vr3*nz; - vn1 = nx*vnnr; - vn2 = ny*vnnr; - vn3 = nz*vnnr; - - // tangential component - - vt1 = vr1 - vn1; - vt2 = vr2 - vn2; - vt3 = vr3 - vn3; - - // relative rotational velocity - - double **omega = atom->omega; - wr1 = (radi*omega[i][0] + radj*omega[j][0]); - wr2 = (radi*omega[i][1] + radj*omega[j][1]); - wr3 = (radi*omega[i][2] + radj*omega[j][2]); - - // meff = effective mass of pair of particles - // if I or J part of rigid body, use body mass - // if I or J is frozen, meff is other particle - - double *rmass = atom->rmass; - int *type = atom->type; - int *mask = atom->mask; - - mi = rmass[i]; - mj = rmass[j]; - if (fix_rigid) { - // NOTE: ensure mass_rigid is current for owned+ghost atoms? - if (mass_rigid[i] > 0.0) mi = mass_rigid[i]; - if (mass_rigid[j] > 0.0) mj = mass_rigid[j]; - } - - meff = mi*mj / (mi+mj); - if (mask[i] & freeze_group_bit) meff = mj; - if (mask[j] & freeze_group_bit) meff = mi; - - - // normal force = JKR - F_C = 3.0*R*M_PI*Ecoh[itype][jtype]; - overlap = radsum - r; - olapsq = overlap*overlap; - olapcubed = olapsq*olapsq; - sqrtterm = sqrt(1.0 + olapcubed); - tmp = 2.0 + olapcubed + 2.0*sqrtterm; - keyterm = pow(tmp,ONETHIRD); - keyterm2 = olapsq/keyterm; - keyterm3 = sqrt(overlap + keyterm2 + keyterm); - aovera0 = POW6TWO * (keyterm3 + - sqrt(2.0*overlap - keyterm2 - keyterm + 4.0/keyterm3));// eq 41 - a = aovera0*a0; - foverFc = 4.0*((aovera0*aovera0*aovera0) - pow(aovera0,1.5));//F_ne/F_C (eq 40) - - Fne = F_C*foverFc; - - //Damping - kn = 4.0/3.0*E[itype][jtype]*a; - if (normaldamp == BRILLIANTOV) eta_N = a*meff*gamman[itype][jtype]; - else if (normaldamp == TSUJI) eta_N=alpha[itype][jtype]*sqrt(meff*kn); - - Fdamp = -eta_N*vnnr; //F_nd eq 23 and Zhao eq 19 - - Fntot = Fne + Fdamp; - - // relative velocities - - vtr1 = vt1 - (nz*wr2-ny*wr3); - vtr2 = vt2 - (nx*wr3-nz*wr1); - vtr3 = vt3 - (ny*wr1-nx*wr2); - vrel = vtr1*vtr1 + vtr2*vtr2 + vtr3*vtr3; - vrel = sqrt(vrel); - - // shear history effects - // neighprev = index of found neigh on previous call - // search entire jnum list of neighbors of I for neighbor J - // start from neighprev, since will typically be next neighbor - // reset neighprev to 0 as necessary - - int jnum = list->numneigh[i]; - int *jlist = list->firstneigh[i]; - double *allshear = fix_history->firstvalue[i]; - - for (int jj = 0; jj < jnum; jj++) { - neighprev++; - if (neighprev >= jnum) neighprev = 0; - if (jlist[neighprev] == j) break; - } - - double *shear = &allshear[size_history*neighprev]; - shrmag = sqrt(shear[0]*shear[0] + shear[1]*shear[1] + - shear[2]*shear[2]); - - // tangential forces = shear + tangential velocity damping - kt=8.0*G[itype][jtype]*a; - - eta_T = eta_N; - fs1 = -kt*shear[0] - eta_T*vtr1; - fs2 = -kt*shear[1] - eta_T*vtr2; - fs3 = -kt*shear[2] - eta_T*vtr3; - - // rescale frictional displacements and forces if needed - - fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); - Fscrit= muS[itype][jtype] * fabs(Fne + 2*F_C); - - if (fs > Fscrit) { - if (shrmag != 0.0) { - fs1 *= Fscrit/fs; - fs2 *= Fscrit/fs; - fs3 *= Fscrit/fs; - fs *= Fscrit/fs; - } else fs1 = fs2 = fs3 = fs = 0.0; - } - - // set all forces and return no energy - - fforce = Fntot; - - // set single_extra quantities - - svector[0] = fs1; - svector[1] = fs2; - svector[2] = fs3; - svector[3] = fs; - svector[4] = vn1; - svector[5] = vn2; - svector[6] = vn3; - svector[7] = vt1; - svector[8] = vt2; - svector[9] = vt3; - return 0.0; -} diff --git a/src/GRANULAR/pair_gran_jkr_rolling.h b/src/GRANULAR/pair_gran_jkr_rolling.h deleted file mode 100644 index 8c4b339eb3..0000000000 --- a/src/GRANULAR/pair_gran_jkr_rolling.h +++ /dev/null @@ -1,56 +0,0 @@ -/* -*- 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. -------------------------------------------------------------------------- */ - -#ifdef PAIR_CLASS - -PairStyle(gran/jkr/rolling,PairGranJKRRolling) - -#else - -#ifndef LMP_PAIR_GRAN_JKR_ROLLING_H -#define LMP_PAIR_GRAN_JKR_ROLLING_H - -#include "pair_gran_hooke_history.h" - -namespace LAMMPS_NS { - -class PairGranJKRRolling : public PairGranHookeHistory { -public: - PairGranJKRRolling(class LAMMPS *); - virtual ~PairGranJKRRolling(); - virtual void compute(int, int); - void settings(int, char **); //Eventually set this through coeff method so that user can specify a particular i-j set of coefficients - double single(int, int, int, int, double, double, double, double &); - double *E_one, *G_one, *pois, *muS_one, *cor, *alpha_one, *Ecoh_one, *kR_one, *muR_one, *etaR_one; //Public so as to be accessible to fix/wall/gran -private: - double **E, **G, **alpha, **muS, **Ecoh, **kR, **muR, **etaR, **gamman; - int normaldamp, rollingdamp; - - - -}; - -} - -#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. - - */ diff --git a/src/GRANULAR/pair_gran_jkr_rolling_multi.cpp b/src/GRANULAR/pair_gran_jkr_rolling_multi.cpp deleted file mode 100644 index a9156390e5..0000000000 --- a/src/GRANULAR/pair_gran_jkr_rolling_multi.cpp +++ /dev/null @@ -1,1181 +0,0 @@ -/* ---------------------------------------------------------------------- -http://lammps.sandia.gov, Sandia National Laboratories -Steve Plimpton, sjplimp@sandia.gov - -Copyright (2003) Sandia Corporation. Under the terms of Contract -DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains -certain rights in this software. This software is distributed under -the GNU General Public License. - -See the README file in the top-level LAMMPS directory. -------------------------------------------------------------------------- */ - -/* ---------------------------------------------------------------------- - Contributing authors: Leo Silbert (SNL), Gary Grest (SNL) - ------------------------------------------------------------------------- */ - -#include -#include -#include -#include -#include "pair_gran_jkr_rolling_multi.h" -#include "atom.h" -#include "atom_vec.h" -#include "domain.h" -#include "force.h" -#include "update.h" -#include "modify.h" -#include "fix.h" -#include "fix_neigh_history.h" -#include "comm.h" -#include "neighbor.h" -#include "neigh_list.h" -#include "neigh_request.h" -#include "memory.h" -#include "error.h" -#include "math_const.h" -//#include - -using namespace LAMMPS_NS; -using namespace MathConst; - -#define ONETHIRD 0.33333333333333333 -#define TWOTHIRDS 0.66666666666666666 -#define POW6ONE 0.550321208149104 //6^(-1/3) -#define POW6TWO 0.30285343213869 //6^(-2/3) - -#define EPSILON 1e-10 - -enum {TSUJI, BRILLIANTOV}; -enum {INDEP, BRILLROLL}; - -/* ---------------------------------------------------------------------- */ - -PairGranJKRRollingMulti::PairGranJKRRollingMulti(LAMMPS *lmp) : Pair(lmp) -{ - single_enable = 1; - no_virial_fdotr_compute = 1; - history = 1; - fix_history = NULL; - - single_extra = 10; - svector = new double[10]; - - neighprev = 0; - - nmax = 0; - mass_rigid = NULL; - - // set comm size needed by this Pair if used with fix rigid - - comm_forward = 1; -} - -/* ---------------------------------------------------------------------- */ -PairGranJKRRollingMulti::~PairGranJKRRollingMulti() -{ - delete [] svector; - if (fix_history) modify->delete_fix("NEIGH_HISTORY"); - - if (allocated) { - memory->destroy(setflag); - memory->destroy(cutsq); - - memory->destroy(cut); - memory->destroy(E); - memory->destroy(G); - memory->destroy(normaldamp); - memory->destroy(rollingdamp); - memory->destroy(alpha); - memory->destroy(gamman); - memory->destroy(muS); - memory->destroy(Ecoh); - memory->destroy(kR); - memory->destroy(muR); - memory->destroy(etaR); - - delete [] onerad_dynamic; - delete [] onerad_frozen; - delete [] maxrad_dynamic; - delete [] maxrad_frozen; - } - memory->destroy(mass_rigid); -} -/* ---------------------------------------------------------------------- */ - -void PairGranJKRRollingMulti::compute(int eflag, int vflag) -{ -// feenableexcept(FE_INVALID | FE_OVERFLOW); - int i,j,ii,jj,inum,jnum,itype,jtype; - double xtmp,ytmp,ztmp,delx,dely,delz,fx,fy,fz,nx,ny,nz; - double radi,radj,radsum,rsq,r,rinv,rsqinv,R,a; - double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3; - double wr1,wr2,wr3; - double vtr1,vtr2,vtr3,vrel; - double kn, kt, k_Q, k_R, eta_N, eta_T, eta_Q, eta_R; - double Fne, Fdamp, Fntot, Fscrit, Frcrit, F_C, delta_C, delta_Cinv; - double overlap, olapsq, olapcubed, sqrtterm, tmp, a0; - double keyterm, keyterm2, keyterm3, aovera0, foverFc; - double mi,mj,meff,damp,ccel,tor1,tor2,tor3; - double relrot1,relrot2,relrot3,vrl1,vrl2,vrl3,vrlmag,vrlmaginv; - double rollmag, rolldotn, scalefac; - double fr, fr1, fr2, fr3; - double signtwist, magtwist, magtortwist, Mtcrit; - double fs,fs1,fs2,fs3,roll1,roll2,roll3,torroll1,torroll2,torroll3; - double tortwist1, tortwist2, tortwist3; - double shrmag,rsht; - int *ilist,*jlist,*numneigh,**firstneigh; - int *touch,**firsttouch; - double *shear,*allshear,**firstshear; - - if (eflag || vflag) ev_setup(eflag,vflag); - else evflag = vflag_fdotr = 0; - - int shearupdate = 1; - if (update->setupflag) shearupdate = 0; - - // update rigid body info for owned & ghost atoms if using FixRigid masses - // body[i] = which body atom I is in, -1 if none - // mass_body = mass of each rigid body - - if (fix_rigid && neighbor->ago == 0){ - int tmp; - int *body = (int *) fix_rigid->extract("body",tmp); - double *mass_body = (double *) fix_rigid->extract("masstotal",tmp); - if (atom->nmax > nmax) { - memory->destroy(mass_rigid); - nmax = atom->nmax; - memory->create(mass_rigid,nmax,"pair:mass_rigid"); - } - int nlocal = atom->nlocal; - for (i = 0; i < nlocal; i++) - if (body[i] >= 0) mass_rigid[i] = mass_body[body[i]]; - else mass_rigid[i] = 0.0; - comm->forward_comm_pair(this); - } - - double **x = atom->x; - double **v = atom->v; - double **f = atom->f; - int *type = atom->type; - double **omega = atom->omega; - double **torque = atom->torque; - double *radius = atom->radius; - double *rmass = atom->rmass; - int *mask = atom->mask; - int nlocal = atom->nlocal; - int newton_pair = force->newton_pair; - - inum = list->inum; - ilist = list->ilist; - numneigh = list->numneigh; - firstneigh = list->firstneigh; - firsttouch = fix_history->firstflag; - firstshear = fix_history->firstvalue; - - // loop over neighbors of my atoms - - for (ii = 0; ii < inum; ii++) { - i = ilist[ii]; - xtmp = x[i][0]; - ytmp = x[i][1]; - ztmp = x[i][2]; - itype = type[i]; - radi = radius[i]; - touch = firsttouch[i]; - allshear = firstshear[i]; - jlist = firstneigh[i]; - jnum = numneigh[i]; - - for (jj = 0; jj < jnum; jj++) { - j = jlist[jj]; - j &= NEIGHMASK; - - delx = xtmp - x[j][0]; - dely = ytmp - x[j][1]; - delz = ztmp - x[j][2]; - jtype = type[j]; - rsq = delx*delx + dely*dely + delz*delz; - radj = radius[j]; - radsum = radi + radj; - R = radi*radj/(radi+radj); - a0 = pow(9.0*M_PI*Ecoh[itype][jtype]*R*R/E[itype][jtype],ONETHIRD); - delta_C = 0.5*a0*a0*POW6ONE/R; - - if ((rsq >= radsum*radsum && touch[jj] == 0) || - (rsq >= (radsum+delta_C)*(radsum+delta_C))) { - - // unset non-touching neighbors - - touch[jj] = 0; - shear = &allshear[3*jj]; - shear[0] = 0.0; - shear[1] = 0.0; - shear[2] = 0.0; - - } else { - F_C = 3.0*R*M_PI*Ecoh[itype][jtype]; - r = sqrt(rsq); - rinv = 1.0/r; - rsqinv = 1.0/rsq; - - nx = delx*rinv; - ny = dely*rinv; - nz = delz*rinv; - - // relative translational velocity - - vr1 = v[i][0] - v[j][0]; - vr2 = v[i][1] - v[j][1]; - vr3 = v[i][2] - v[j][2]; - - // normal component - - vnnr = vr1*nx + vr2*ny + vr3*nz; //v_R . n - vn1 = nx*vnnr; - vn2 = ny*vnnr; - vn3 = nz*vnnr; - - // meff = effective mass of pair of particles - // if I or J part of rigid body, use body mass - // if I or J is frozen, meff is other particle - - mi = rmass[i]; - mj = rmass[j]; - if (fix_rigid) { - if (mass_rigid[i] > 0.0) mi = mass_rigid[i]; - if (mass_rigid[j] > 0.0) mj = mass_rigid[j]; - } - - meff = mi*mj / (mi+mj); - if (mask[i] & freeze_group_bit) meff = mj; - if (mask[j] & freeze_group_bit) meff = mi; - - //**************************************** - //Normal force = JKR-adjusted Hertzian contact + damping - //**************************************** - if (Ecoh[itype][jtype] != 0.0) delta_Cinv = 1.0/delta_C; - else delta_Cinv = 1.0; - overlap = (radsum - r)*delta_Cinv; - olapsq = overlap*overlap; - olapcubed = olapsq*overlap; - sqrtterm = sqrt(1.0 + olapcubed); - tmp = 2.0 + olapcubed + 2.0*sqrtterm; - keyterm = pow(tmp,ONETHIRD); - keyterm2 = olapsq/keyterm; - keyterm3 = sqrt(overlap + keyterm2 + keyterm); - aovera0 = POW6TWO * (keyterm3 + - sqrt(2.0*overlap - keyterm2 - keyterm + 4.0/keyterm3));// eq 41 - a = aovera0*a0; - foverFc = 4.0*((aovera0*aovera0*aovera0) - pow(aovera0,1.5));//F_ne/F_C (eq 40) - - Fne = F_C*foverFc; - - //Damping - kn = 4.0/3.0*E[itype][jtype]*a; - if (normaldamp[itype][jtype] == BRILLIANTOV) eta_N = a*meff*gamman[itype][jtype]; - else if (normaldamp[itype][jtype] == TSUJI) eta_N=alpha[itype][jtype]*sqrt(meff*kn); - - Fdamp = -eta_N*vnnr; //F_nd eq 23 and Zhao eq 19 - - Fntot = Fne + Fdamp; - //if (screen) fprintf(screen,"%d %d %16.16g %16.16g \n",itype,jtype,Ecoh[itype][jtype],E[itype][jtype]); - //if (logfile) fprintf(logfile,"%d %d %16.16g %16.16g \n",itype,jtype,Ecoh[itype][jtype],E[itype][jtype]); - - //**************************************** - //Tangential force, including shear history effects - //**************************************** - - // tangential component - vt1 = vr1 - vn1; - vt2 = vr2 - vn2; - vt3 = vr3 - vn3; - - // relative rotational velocity - // Luding Gran Matt 2008, v10,p235 suggests correcting radi and radj by subtracting - // delta/2, i.e. instead of radi, use distance to center of contact point? - wr1 = (radi*omega[i][0] + radj*omega[j][0]); - wr2 = (radi*omega[i][1] + radj*omega[j][1]); - wr3 = (radi*omega[i][2] + radj*omega[j][2]); - - // relative tangential velocities - vtr1 = vt1 - (nz*wr2-ny*wr3); - vtr2 = vt2 - (nx*wr3-nz*wr1); - vtr3 = vt3 - (ny*wr1-nx*wr2); - vrel = vtr1*vtr1 + vtr2*vtr2 + vtr3*vtr3; - vrel = sqrt(vrel); - - // shear history effects - touch[jj] = 1; - shear = &allshear[3*jj]; - shrmag = sqrt(shear[0]*shear[0] + shear[1]*shear[1] + - shear[2]*shear[2]); - - // Rotate and update shear displacements. - // See e.g. eq. 17 of Luding, Gran. Matter 2008, v10,p235 - if (shearupdate) { - rsht = shear[0]*nx + shear[1]*ny + shear[2]*nz; - if (fabs(rsht) < EPSILON) rsht = 0; - if (rsht > 0){ - scalefac = shrmag/(shrmag - rsht); //if rhst == shrmag, contacting pair has rotated 90 deg. in one step, in which case you deserve a crash! - shear[0] -= rsht*nx; - shear[1] -= rsht*ny; - shear[2] -= rsht*nz; - //Also rescale to preserve magnitude - shear[0] *= scalefac; - shear[1] *= scalefac; - shear[2] *= scalefac; - } - //Update shear history - shear[0] += vtr1*dt; - shear[1] += vtr2*dt; - shear[2] += vtr3*dt; - } - - // tangential forces = shear + tangential velocity damping - // following Zhao and Marshall Phys Fluids v20, p043302 (2008) - kt=8.0*G[itype][jtype]*a; - - eta_T = eta_N; //Based on discussion in Marshall; eta_T can also be an independent parameter - fs1 = -kt*shear[0] - eta_T*vtr1; //eq 26 - fs2 = -kt*shear[1] - eta_T*vtr2; - fs3 = -kt*shear[2] - eta_T*vtr3; - - // rescale frictional displacements and forces if needed - Fscrit = muS[itype][jtype] * fabs(Fne + 2*F_C); - // For JKR, use eq 43 of Marshall. For DMT, use Fne instead - - fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); - if (fs > Fscrit) { - if (shrmag != 0.0) { - //shear[0] = (Fcrit/fs) * (shear[0] + eta_T*vtr1/kt) - eta_T*vtr1/kt; - //shear[1] = (Fcrit/fs) * (shear[1] + eta_T*vtr1/kt) - eta_T*vtr1/kt; - //shear[2] = (Fcrit/fs) * (shear[2] + eta_T*vtr1/kt) - eta_T*vtr1/kt; - shear[0] = -1.0/kt*(Fscrit*fs1/fs + eta_T*vtr1); //Same as above, but simpler (check!) - shear[1] = -1.0/kt*(Fscrit*fs2/fs + eta_T*vtr2); - shear[2] = -1.0/kt*(Fscrit*fs3/fs + eta_T*vtr3); - fs1 *= Fscrit/fs; - fs2 *= Fscrit/fs; - fs3 *= Fscrit/fs; - } else fs1 = fs2 = fs3 = 0.0; - } - - //**************************************** - // Rolling force, including shear history effects - //**************************************** - - relrot1 = omega[i][0] - omega[j][0]; - relrot2 = omega[i][1] - omega[j][1]; - relrot3 = omega[i][2] - omega[j][2]; - - // rolling velocity, see eq. 31 of Wang et al, Particuology v 23, p 49 (2015) - // This is different from the Marshall papers, which use the Bagi/Kuhn formulation - // for rolling velocity (see Wang et al for why the latter is wrong) - vrl1 = R*(relrot2*nz - relrot3*ny); //- 0.5*((radj-radi)/radsum)*vtr1; - vrl2 = R*(relrot3*nx - relrot1*nz); //- 0.5*((radj-radi)/radsum)*vtr2; - vrl3 = R*(relrot1*ny - relrot2*nx); //- 0.5*((radj-radi)/radsum)*vtr3; - vrlmag = sqrt(vrl1*vrl1+vrl2*vrl2+vrl3*vrl3); - if (vrlmag != 0.0) vrlmaginv = 1.0/vrlmag; - else vrlmaginv = 0.0; - - // Rolling displacement - rollmag = sqrt(shear[3]*shear[3] + shear[4]*shear[4] + shear[5]*shear[5]); - rolldotn = shear[3]*nx + shear[4]*ny + shear[5]*nz; - - if (shearupdate) { - if (fabs(rolldotn) < EPSILON) rolldotn = 0; - if (rolldotn > 0){ //Rotate into tangential plane - scalefac = rollmag/(rollmag - rolldotn); - shear[3] -= rolldotn*nx; - shear[4] -= rolldotn*ny; - shear[5] -= rolldotn*nz; - //Also rescale to preserve magnitude - shear[3] *= scalefac; - shear[4] *= scalefac; - shear[5] *= scalefac; - } - shear[3] += vrl1*dt; - shear[4] += vrl2*dt; - shear[5] += vrl3*dt; - } - - k_R = kR[itype][jtype]*4.0*F_C*pow(aovera0,1.5); - if (rollingdamp[itype][jtype] == INDEP) eta_R = etaR[itype][jtype]; - else if (rollingdamp[itype][jtype] == BRILLROLL) eta_R = muR[itype][jtype]*fabs(Fne); - fr1 = -k_R*shear[3] - eta_R*vrl1; - fr2 = -k_R*shear[4] - eta_R*vrl2; - fr3 = -k_R*shear[5] - eta_R*vrl3; - - // rescale frictional displacements and forces if needed - Frcrit = muR[itype][jtype] * fabs(Fne + 2*F_C); - - fr = sqrt(fr1*fr1 + fr2*fr2 + fr3*fr3); - if (fr > Frcrit) { - if (rollmag != 0.0) { - shear[3] = -1.0/k_R*(Frcrit*fr1/fr + eta_R*vrl1); - shear[4] = -1.0/k_R*(Frcrit*fr2/fr + eta_R*vrl2); - shear[5] = -1.0/k_R*(Frcrit*fr3/fr + eta_R*vrl3); - fr1 *= Frcrit/fr; - fr2 *= Frcrit/fr; - fr3 *= Frcrit/fr; - } else fr1 = fr2 = fr3 = 0.0; - } - - - //**************************************** - // Twisting torque, including shear history effects - //**************************************** - magtwist = relrot1*nx + relrot2*ny + relrot3*nz; //Omega_T (eq 29 of Marshall) - shear[6] += magtwist*dt; - k_Q = 0.5*kt*a*a;; //eq 32 - eta_Q = 0.5*eta_T*a*a; - magtortwist = -k_Q*shear[6] - eta_Q*magtwist;//M_t torque (eq 30) - - signtwist = (magtwist > 0) - (magtwist < 0); - Mtcrit=TWOTHIRDS*a*Fscrit;//critical torque (eq 44) - if (fabs(magtortwist) > Mtcrit) { - //shear[6] = Mtcrit/k_Q*magtwist/fabs(magtwist); - shear[6] = 1.0/k_Q*(Mtcrit*signtwist - eta_Q*magtwist); - magtortwist = -Mtcrit * signtwist; //eq 34 - } - - // Apply forces & torques - - fx = nx*Fntot + fs1; - fy = ny*Fntot + fs2; - fz = nz*Fntot + fs3; - - //if (screen) fprintf(screen,"%16.16g %16.16g %16.16g %16.16g %16.16g %16.16g %16.16g \n",fs1,fs2,fs3,Fntot,nx,ny,nz); - //if (logfile) fprintf(logfile,"%16.16g %16.16g %16.16g %16.16g %16.16g %16.16g %16.16g \n",fs1,fs2,fs3,Fntot,nx,ny,nz); - - f[i][0] += fx; - f[i][1] += fy; - f[i][2] += fz; - - tor1 = ny*fs3 - nz*fs2; - tor2 = nz*fs1 - nx*fs3; - tor3 = nx*fs2 - ny*fs1; - - torque[i][0] -= radi*tor1; - torque[i][1] -= radi*tor2; - torque[i][2] -= radi*tor3; - - tortwist1 = magtortwist * nx; - tortwist2 = magtortwist * ny; - tortwist3 = magtortwist * nz; - - torque[i][0] += tortwist1; - torque[i][1] += tortwist2; - torque[i][2] += tortwist3; - - torroll1 = R*(ny*fr3 - nz*fr2); //n cross fr - torroll2 = R*(nz*fr1 - nx*fr3); - torroll3 = R*(nx*fr2 - ny*fr1); - - torque[i][0] += torroll1; - torque[i][1] += torroll2; - torque[i][2] += torroll3; - - if (force->newton_pair || j < nlocal) { - f[j][0] -= fx; - f[j][1] -= fy; - f[j][2] -= fz; - - torque[j][0] -= radj*tor1; - torque[j][1] -= radj*tor2; - torque[j][2] -= radj*tor3; - - torque[j][0] -= tortwist1; - torque[j][1] -= tortwist2; - torque[j][2] -= tortwist3; - - torque[j][0] -= torroll1; - torque[j][1] -= torroll2; - torque[j][2] -= torroll3; - } - if (evflag) ev_tally_xyz(i,j,nlocal,0, - 0.0,0.0,fx,fy,fz,delx,dely,delz); - } - } - } -} - - -/* ---------------------------------------------------------------------- - allocate all arrays - ------------------------------------------------------------------------- */ - -void PairGranJKRRollingMulti::allocate() -{ - allocated = 1; - int n = atom->ntypes; - - memory->create(setflag,n+1,n+1,"pair:setflag"); - for (int i = 1; i <= n; i++) - for (int j = i; j <= n; j++) - setflag[i][j] = 0; - - memory->create(cutsq,n+1,n+1,"pair:cutsq"); - memory->create(cut,n+1,n+1,"pair:cut"); - memory->create(E,n+1,n+1,"pair:E"); - memory->create(G,n+1,n+1,"pair:G"); - memory->create(normaldamp,n+1,n+1,"pair:normaldamp"); - memory->create(rollingdamp,n+1,n+1,"pair:rollingdamp"); - memory->create(alpha,n+1,n+1,"pair:alpha"); - memory->create(gamman,n+1,n+1,"pair:gamman"); - memory->create(muS,n+1,n+1,"pair:muS"); - memory->create(Ecoh,n+1,n+1,"pair:Ecoh"); - memory->create(kR,n+1,n+1,"pair:kR"); - memory->create(muR,n+1,n+1,"pair:muR"); - memory->create(etaR,n+1,n+1,"pair:etaR"); - - onerad_dynamic = new double[n+1]; - onerad_frozen = new double[n+1]; - maxrad_dynamic = new double[n+1]; - maxrad_frozen = new double[n+1]; -} - -/* ---------------------------------------------------------------------- - global settings - ------------------------------------------------------------------------- */ - -void PairGranJKRRollingMulti::settings(int narg, char **arg) -{ - if (narg != 1) error->all(FLERR,"Illegal pair_style command"); - - if (strcmp(arg[0],"NULL") == 0 ) cut_global = -1.0; - else cut_global = force->numeric(FLERR,arg[0]); - - // reset cutoffs that have been explicitly set - if (allocated) { - int i,j; - for (i = 1; i <= atom->ntypes; i++) - for (j = i; j <= atom->ntypes; j++) - if (setflag[i][j]) cut[i][j] = cut_global; - } -} - -/* ---------------------------------------------------------------------- - set coeffs for one or more type pairs - ------------------------------------------------------------------------- */ - -void PairGranJKRRollingMulti::coeff(int narg, char **arg) -{ - if (narg < 10 || narg > 15) - error->all(FLERR,"Incorrect args for pair coefficients2"); - - if (!allocated) allocate(); - - int ilo,ihi,jlo,jhi; - force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); - force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); - - double E_one = force->numeric(FLERR,arg[2]); - double G_one = force->numeric(FLERR,arg[3]); - double muS_one = force->numeric(FLERR,arg[4]); - double cor_one = force->numeric(FLERR,arg[5]); - double Ecoh_one = force->numeric(FLERR,arg[6]); - double kR_one = force->numeric(FLERR,arg[7]); - double muR_one = force->numeric(FLERR,arg[8]); - double etaR_one = force->numeric(FLERR,arg[9]); - - //Defaults - int normaldamp_one = TSUJI; - int rollingdamp_one = INDEP; - double cut_one = cut_global; - - int iarg = 10; - while (iarg < narg) { - if (strcmp(arg[iarg],"normaldamp") == 0){ - if (iarg+2 > narg) error->all(FLERR, "Invalid pair/gran/dmt/rolling entry"); - if (strcmp(arg[iarg+1],"tsuji") == 0) normaldamp_one = TSUJI; - else if (strcmp(arg[iarg+1],"brilliantov") == 0) normaldamp_one = BRILLIANTOV; - else error->all(FLERR, "Invalid normal damping model for pair/gran/dmt/rolling"); - iarg += 2; - } - else if (strcmp(arg[iarg],"rollingdamp") == 0){ - if (iarg+2 > narg) error->all(FLERR, "Invalid pair/gran/dmt/rolling entry"); - if (strcmp(arg[iarg+1],"independent") == 0) rollingdamp_one = INDEP; - else if (strcmp(arg[iarg+1],"brilliantov") == 0) rollingdamp_one = BRILLROLL; - else error->all(FLERR, "Invalid rolling damping model for pair/gran/dmt/rolling"); - iarg +=2; - } - else { - if (strcmp(arg[iarg],"NULL") == 0) cut_one = -1.0; - else cut_one = force->numeric(FLERR,arg[iarg]); - iarg += 1; - } - } - - int count = 0; - for (int i = ilo; i <= ihi; i++) { - double pois = E_one/(2.0*G_one) - 1.0; - double alpha_one = 1.2728-4.2783*cor_one+11.087*cor_one*cor_one-22.348*cor_one*cor_one*cor_one+27.467*cor_one*cor_one*cor_one*cor_one-18.022*cor_one*cor_one*cor_one*cor_one*cor_one+4.8218*cor_one*cor_one*cor_one*cor_one*cor_one*cor_one; - - for (int j = MAX(jlo,i); j <= jhi; j++) { - E[i][j] = E_one; - G[i][j] = G_one; - if (normaldamp_one == TSUJI) { - normaldamp[i][j] = TSUJI; - alpha[i][j] = alpha_one; - } - else if (normaldamp_one == BRILLIANTOV) { - normaldamp[i][j] = BRILLIANTOV; - gamman[i][j] = cor_one; - } - if (rollingdamp_one == INDEP) { - rollingdamp[i][j] = INDEP; - } - else if (rollingdamp_one == BRILLROLL) { - rollingdamp[i][j] = BRILLROLL; - } - muS[i][j] = muS_one; - Ecoh[i][j] = Ecoh_one; - kR[i][j] = kR_one; - etaR[i][j] = etaR_one; - muR[i][j] = muR_one; - cut[i][j] = cut_one; - setflag[i][j] = 1; - count++; - } - } - - if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients1"); -} - -/* ---------------------------------------------------------------------- - init specific to this pair style - ------------------------------------------------------------------------- */ - -void PairGranJKRRollingMulti::init_style() -{ - int i; - - // error and warning checks - - if (!atom->radius_flag || !atom->rmass_flag) - error->all(FLERR,"Pair granular requires atom attributes radius, rmass"); - if (comm->ghost_velocity == 0) - error->all(FLERR,"Pair granular requires ghost atoms store velocity"); - - // need a granular neigh list - - int irequest = neighbor->request(this,instance_me); - neighbor->requests[irequest]->size = 1; - if (history) neighbor->requests[irequest]->history = 1; - - dt = update->dt; - - // if shear history is stored: - // if first init, create Fix needed for storing shear history - - if (history && fix_history == NULL) { - char dnumstr[16]; - sprintf(dnumstr,"%d",3); - char **fixarg = new char*[4]; - fixarg[0] = (char *) "NEIGH_HISTORY"; - fixarg[1] = (char *) "all"; - fixarg[2] = (char *) "NEIGH_HISTORY"; - fixarg[3] = dnumstr; - modify->add_fix(4,fixarg,1); - delete [] fixarg; - fix_history = (FixNeighHistory *) modify->fix[modify->nfix-1]; - fix_history->pair = this; - } - - // check for FixFreeze and set freeze_group_bit - - for (i = 0; i < modify->nfix; i++) - if (strcmp(modify->fix[i]->style,"freeze") == 0) break; - if (i < modify->nfix) freeze_group_bit = modify->fix[i]->groupbit; - else freeze_group_bit = 0; - - // check for FixRigid so can extract rigid body masses - - fix_rigid = NULL; - for (i = 0; i < modify->nfix; i++) - if (modify->fix[i]->rigid_flag) break; - if (i < modify->nfix) fix_rigid = modify->fix[i]; - - // check for FixPour and FixDeposit so can extract particle radii - - int ipour; - for (ipour = 0; ipour < modify->nfix; ipour++) - if (strcmp(modify->fix[ipour]->style,"pour") == 0) break; - if (ipour == modify->nfix) ipour = -1; - - int idep; - for (idep = 0; idep < modify->nfix; idep++) - if (strcmp(modify->fix[idep]->style,"deposit") == 0) break; - if (idep == modify->nfix) idep = -1; - - // set maxrad_dynamic and maxrad_frozen for each type - // include future FixPour and FixDeposit particles as dynamic - - int itype; - for (i = 1; i <= atom->ntypes; i++) { - onerad_dynamic[i] = onerad_frozen[i] = 0.0; - if (ipour >= 0) { - itype = i; - onerad_dynamic[i] = - *((double *) modify->fix[ipour]->extract("radius",itype)); - } - if (idep >= 0) { - itype = i; - onerad_dynamic[i] = - *((double *) modify->fix[idep]->extract("radius",itype)); - } - } - - double *radius = atom->radius; - int *mask = atom->mask; - int *type = atom->type; - int nlocal = atom->nlocal; - - for (i = 0; i < nlocal; i++) - if (mask[i] & freeze_group_bit) - onerad_frozen[type[i]] = MAX(onerad_frozen[type[i]],radius[i]); - else - onerad_dynamic[type[i]] = MAX(onerad_dynamic[type[i]],radius[i]); - - MPI_Allreduce(&onerad_dynamic[1],&maxrad_dynamic[1],atom->ntypes, - MPI_DOUBLE,MPI_MAX,world); - MPI_Allreduce(&onerad_frozen[1],&maxrad_frozen[1],atom->ntypes, - MPI_DOUBLE,MPI_MAX,world); - - // set fix which stores history info - - if (history) { - int ifix = modify->find_fix("NEIGH_HISTORY"); - if (ifix < 0) error->all(FLERR,"Could not find pair fix neigh history ID"); - fix_history = (FixNeighHistory *) modify->fix[ifix]; - } -} - -/* ---------------------------------------------------------------------- - init for one type pair i,j and corresponding j,i - ------------------------------------------------------------------------- */ - -double PairGranJKRRollingMulti::init_one(int i, int j) -{ - if (setflag[i][j] == 0) { - E[i][j] = mix_stiffnessE(E[i][i],E[j][j],G[i][i],G[j][j]); - G[i][j] = mix_stiffnessG(G[i][i],E[j][j],G[i][i],G[j][j]); - if (normaldamp[i][j] == TSUJI) { - alpha[i][j] = mix_geom(alpha[i][i],alpha[j][j]); - } - else if (normaldamp[i][j] == BRILLIANTOV) { - gamman[i][j] = mix_geom(gamman[i][i],gamman[j][j]); - } - muS[i][j] = mix_geom(muS[i][i],muS[j][j]); - Ecoh[i][j] = mix_geom(Ecoh[i][i],Ecoh[j][j]); - kR[i][j] = mix_geom(kR[i][i],kR[j][j]); - etaR[i][j] = mix_geom(etaR[i][i],etaR[j][j]); - muR[i][j] = mix_geom(muR[i][i],muR[j][j]); - } - - E[j][i] = E[i][j]; - G[j][i] = G[i][j]; - normaldamp[j][i] = normaldamp[i][j]; - alpha[j][i] = alpha[i][j]; - gamman[j][i] = gamman[i][j]; - rollingdamp[j][i] = rollingdamp[i][j]; - muS[j][i] = muS[i][j]; - Ecoh[j][i] = Ecoh[i][j]; - kR[j][i] = kR[i][j]; - etaR[j][i] = etaR[i][j]; - muR[j][i] = muR[i][j]; - - double cutoff = cut[i][j]; - - // It is likely that cut[i][j] at this point is still 0.0. This can happen when - // there is a future fix_pour after the current run. A cut[i][j] = 0.0 creates - // problems because neighbor.cpp uses min(cut[i][j]) to decide on the bin size - // To avoid this issue,for cases involving cut[i][j] = 0.0 (possible only - // if there is no current information about radius/cutoff of type i and j). - // we assign cutoff = min(cut[i][j]) for i,j such that cut[i][j] > 0.0. - - if (cut[i][j] < 0.0) { - if (((maxrad_dynamic[i] > 0.0) && (maxrad_dynamic[j] > 0.0)) || ((maxrad_dynamic[i] > 0.0) && (maxrad_frozen[j] > 0.0)) || - ((maxrad_frozen[i] > 0.0) && (maxrad_dynamic[j] > 0.0))) { // radius info about both i and j exist - cutoff = maxrad_dynamic[i]+maxrad_dynamic[j]; - cutoff = MAX(cutoff,maxrad_frozen[i]+maxrad_dynamic[j]); - cutoff = MAX(cutoff,maxrad_dynamic[i]+maxrad_frozen[j]); - } - else { // radius info about either i or j does not exist (i.e. not present and not about to get poured; set to largest value to not interfere with neighbor list) - double cutmax = 0.0; - for (int k = 1; k <= atom->ntypes; k++) { - cutmax = MAX(cutmax,2.0*maxrad_dynamic[k]); - cutmax = MAX(cutmax,2.0*maxrad_frozen[k]); - } - cutoff = cutmax; - } - } - return cutoff; -} - - -/* ---------------------------------------------------------------------- - proc 0 writes to restart file - ------------------------------------------------------------------------- */ - -void PairGranJKRRollingMulti::write_restart(FILE *fp) -{ - write_restart_settings(fp); - - int i,j; - for (i = 1; i <= atom->ntypes; i++) { - for (j = i; j <= atom->ntypes; j++) { - fwrite(&setflag[i][j],sizeof(int),1,fp); - if (setflag[i][j]) { - fwrite(&E[i][j],sizeof(double),1,fp); - fwrite(&G[i][j],sizeof(double),1,fp); - fwrite(&normaldamp[i][j],sizeof(int),1,fp); - fwrite(&rollingdamp[i][j],sizeof(int),1,fp); - fwrite(&alpha[i][j],sizeof(double),1,fp); - fwrite(&gamman[i][j],sizeof(double),1,fp); - fwrite(&muS[i][j],sizeof(double),1,fp); - fwrite(&Ecoh[i][j],sizeof(double),1,fp); - fwrite(&kR[i][j],sizeof(double),1,fp); - fwrite(&muR[i][j],sizeof(double),1,fp); - fwrite(&etaR[i][j],sizeof(double),1,fp); - fwrite(&cut[i][j],sizeof(double),1,fp); - } - } - } -} - -/* ---------------------------------------------------------------------- - proc 0 reads from restart file, bcasts - ------------------------------------------------------------------------- */ - -void PairGranJKRRollingMulti::read_restart(FILE *fp) -{ - read_restart_settings(fp); - allocate(); - - int i,j; - int me = comm->me; - for (i = 1; i <= atom->ntypes; i++) { - for (j = i; j <= atom->ntypes; j++) { - if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp); - MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world); - if (setflag[i][j]) { - if (me == 0) { - fread(&E[i][j],sizeof(double),1,fp); - fread(&G[i][j],sizeof(double),1,fp); - fread(&normaldamp[i][j],sizeof(int),1,fp); - fread(&rollingdamp[i][j],sizeof(int),1,fp); - fread(&alpha[i][j],sizeof(double),1,fp); - fread(&gamman[i][j],sizeof(double),1,fp); - fread(&muS[i][j],sizeof(double),1,fp); - fread(&Ecoh[i][j],sizeof(double),1,fp); - fread(&kR[i][j],sizeof(double),1,fp); - fread(&muR[i][j],sizeof(double),1,fp); - fread(&etaR[i][j],sizeof(double),1,fp); - fread(&cut[i][j],sizeof(double),1,fp); - } - MPI_Bcast(&E[i][j],1,MPI_DOUBLE,0,world); - MPI_Bcast(&G[i][j],1,MPI_DOUBLE,0,world); - MPI_Bcast(&normaldamp[i][j],1,MPI_INT,0,world); - MPI_Bcast(&rollingdamp[i][j],1,MPI_INT,0,world); - MPI_Bcast(&alpha[i][j],1,MPI_DOUBLE,0,world); - MPI_Bcast(&gamman[i][j],1,MPI_DOUBLE,0,world); - MPI_Bcast(&muS[i][j],1,MPI_DOUBLE,0,world); - MPI_Bcast(&Ecoh[i][j],1,MPI_DOUBLE,0,world); - MPI_Bcast(&kR[i][j],1,MPI_DOUBLE,0,world); - MPI_Bcast(&muR[i][j],1,MPI_DOUBLE,0,world); - MPI_Bcast(&etaR[i][j],1,MPI_DOUBLE,0,world); - MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); - } - } - } -} - -/* ---------------------------------------------------------------------- - proc 0 writes to restart file - ------------------------------------------------------------------------- */ - -void PairGranJKRRollingMulti::write_restart_settings(FILE *fp) -{ - fwrite(&cut_global,sizeof(double),1,fp); -} - -/* ---------------------------------------------------------------------- - proc 0 reads from restart file, bcasts - ------------------------------------------------------------------------- */ - -void PairGranJKRRollingMulti::read_restart_settings(FILE *fp) -{ - if (comm->me == 0) { - fread(&cut_global,sizeof(double),1,fp); - } - MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world); -} - -/* ---------------------------------------------------------------------- */ - -void PairGranJKRRollingMulti::reset_dt() -{ - dt = update->dt; -} - -/* ---------------------------------------------------------------------- */ - -double PairGranJKRRollingMulti::single(int i, int j, int itype, int jtype, - double rsq, double factor_coul, double factor_lj, double &fforce) -{ -// feenableexcept(FE_INVALID | FE_OVERFLOW); - double radi,radj,radsum; - double r,rinv,rsqinv,delx,dely,delz, nx, ny, nz, R; - double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3,wr1,wr2,wr3; - double overlap, a; - double mi,mj,meff,damp,kn,kt; - double Fdamp,Fne,Fntot,Fscrit; - double eta_N,eta_T; - double vtr1,vtr2,vtr3,vrel; - double fs1,fs2,fs3,fs; - double shrmag; - double F_C, delta_C, olapsq, olapcubed, sqrtterm, tmp, a0; - double keyterm, keyterm2, keyterm3, aovera0, foverFc; - - double *radius = atom->radius; - radi = radius[i]; - radj = radius[j]; - radsum = radi + radj; - - r = sqrt(rsq); - rinv = 1.0/r; - rsqinv = 1.0/rsq; - R = radi*radj/(radi+radj); - a0 = pow(9.0*M_PI*Ecoh[itype][jtype]*R*R/E[itype][jtype],ONETHIRD); - delta_C = 0.5*a0*a0*POW6ONE/R; - - int *touch = fix_history->firstflag[i]; - if ((rsq >= (radsum+delta_C)*(radsum+delta_C) )|| - (rsq >= radsum*radsum && touch[j])){ - fforce = 0.0; - svector[0] = svector[1] = svector[2] = svector[3] = 0.0; - return 0.0; - } - - // relative translational velocity - - double **v = atom->v; - vr1 = v[i][0] - v[j][0]; - vr2 = v[i][1] - v[j][1]; - vr3 = v[i][2] - v[j][2]; - - // normal component - - double **x = atom->x; - delx = x[i][0] - x[j][0]; - dely = x[i][1] - x[j][1]; - delz = x[i][2] - x[j][2]; - - nx = delx*rinv; - ny = dely*rinv; - nz = delz*rinv; - - - vnnr = vr1*nx + vr2*ny + vr3*nz; - vn1 = nx*vnnr; - vn2 = ny*vnnr; - vn3 = nz*vnnr; - - // tangential component - - vt1 = vr1 - vn1; - vt2 = vr2 - vn2; - vt3 = vr3 - vn3; - - // relative rotational velocity - - double **omega = atom->omega; - wr1 = (radi*omega[i][0] + radj*omega[j][0]); - wr2 = (radi*omega[i][1] + radj*omega[j][1]); - wr3 = (radi*omega[i][2] + radj*omega[j][2]); - - // meff = effective mass of pair of particles - // if I or J part of rigid body, use body mass - // if I or J is frozen, meff is other particle - - double *rmass = atom->rmass; - int *type = atom->type; - int *mask = atom->mask; - - mi = rmass[i]; - mj = rmass[j]; - if (fix_rigid) { - // NOTE: ensure mass_rigid is current for owned+ghost atoms? - if (mass_rigid[i] > 0.0) mi = mass_rigid[i]; - if (mass_rigid[j] > 0.0) mj = mass_rigid[j]; - } - - meff = mi*mj / (mi+mj); - if (mask[i] & freeze_group_bit) meff = mj; - if (mask[j] & freeze_group_bit) meff = mi; - - - // normal force = JKR - F_C = 3.0*R*M_PI*Ecoh[itype][jtype]; - overlap = radsum - r; - olapsq = overlap*overlap; - olapcubed = olapsq*olapsq; - sqrtterm = sqrt(1.0 + olapcubed); - tmp = 2.0 + olapcubed + 2.0*sqrtterm; - keyterm = pow(tmp,ONETHIRD); - keyterm2 = olapsq/keyterm; - keyterm3 = sqrt(overlap + keyterm2 + keyterm); - aovera0 = POW6TWO * (keyterm3 + - sqrt(2.0*overlap - keyterm2 - keyterm + 4.0/keyterm3));// eq 41 - a = aovera0*a0; - foverFc = 4.0*((aovera0*aovera0*aovera0) - pow(aovera0,1.5));//F_ne/F_C (eq 40) - - Fne = F_C*foverFc; - - //Damping - kn = 4.0/3.0*E[itype][jtype]*a; - if (normaldamp[itype][jtype] == BRILLIANTOV) eta_N = a*meff*gamman[itype][jtype]; - else if (normaldamp[itype][jtype] == TSUJI) eta_N=alpha[itype][jtype]*sqrt(meff*kn); - - Fdamp = -eta_N*vnnr; //F_nd eq 23 and Zhao eq 19 - - Fntot = Fne + Fdamp; - - // relative velocities - - vtr1 = vt1 - (nz*wr2-ny*wr3); - vtr2 = vt2 - (nx*wr3-nz*wr1); - vtr3 = vt3 - (ny*wr1-nx*wr2); - vrel = vtr1*vtr1 + vtr2*vtr2 + vtr3*vtr3; - vrel = sqrt(vrel); - - // shear history effects - // neighprev = index of found neigh on previous call - // search entire jnum list of neighbors of I for neighbor J - // start from neighprev, since will typically be next neighbor - // reset neighprev to 0 as necessary - - int jnum = list->numneigh[i]; - int *jlist = list->firstneigh[i]; - double *allshear = fix_history->firstvalue[i]; - - for (int jj = 0; jj < jnum; jj++) { - neighprev++; - if (neighprev >= jnum) neighprev = 0; - if (jlist[neighprev] == j) break; - } - - double *shear = &allshear[3*neighprev]; - shrmag = sqrt(shear[0]*shear[0] + shear[1]*shear[1] + - shear[2]*shear[2]); - - // tangential forces = shear + tangential velocity damping - kt=8.0*G[itype][jtype]*a; - - eta_T = eta_N; - fs1 = -kt*shear[0] - eta_T*vtr1; - fs2 = -kt*shear[1] - eta_T*vtr2; - fs3 = -kt*shear[2] - eta_T*vtr3; - - // rescale frictional displacements and forces if needed - - fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); - Fscrit= muS[itype][jtype] * fabs(Fne + 2*F_C); - - if (fs > Fscrit) { - if (shrmag != 0.0) { - fs1 *= Fscrit/fs; - fs2 *= Fscrit/fs; - fs3 *= Fscrit/fs; - fs *= Fscrit/fs; - } else fs1 = fs2 = fs3 = fs = 0.0; - } - - // set all forces and return no energy - - fforce = Fntot; - - // set single_extra quantities - - svector[0] = fs1; - svector[1] = fs2; - svector[2] = fs3; - svector[3] = fs; - svector[4] = vn1; - svector[5] = vn2; - svector[6] = vn3; - svector[7] = vt1; - svector[8] = vt2; - svector[9] = vt3; - return 0.0; -} - -/* ---------------------------------------------------------------------- */ - -int PairGranJKRRollingMulti::pack_forward_comm(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = mass_rigid[j]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void PairGranJKRRollingMulti::unpack_forward_comm(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) - mass_rigid[i] = buf[m++]; -} - -/* ---------------------------------------------------------------------- - memory usage of local atom-based arrays - ------------------------------------------------------------------------- */ - -double PairGranJKRRollingMulti::memory_usage() -{ - double bytes = nmax * sizeof(double); - return bytes; -} - -/* ---------------------------------------------------------------------- - mixing of stiffness (E) - ------------------------------------------------------------------------- */ - -double PairGranJKRRollingMulti::mix_stiffnessE(double Eii, double Ejj, double Gii, double Gjj) -{ - double poisii = Eii/(2.0*Gii) - 1.0; - double poisjj = Ejj/(2.0*Gjj) - 1.0; - return 1/((1-poisii*poisjj)/Eii+(1-poisjj*poisjj)/Ejj); -} - -/* ---------------------------------------------------------------------- - mixing of stiffness (G) - ------------------------------------------------------------------------- */ - -double PairGranJKRRollingMulti::mix_stiffnessG(double Eii, double Ejj, double Gii, double Gjj) -{ - double poisii = Eii/(2.0*Gii) - 1.0; - double poisjj = Ejj/(2.0*Gjj) - 1.0; - return 1/((2.0 -poisjj)/Gii+(2.0-poisjj)/Gjj); -} - -/* ---------------------------------------------------------------------- - mixing of everything else - ------------------------------------------------------------------------- */ - -double PairGranJKRRollingMulti::mix_geom(double valii, double valjj) -{ - return sqrt(valii*valjj); -} diff --git a/src/GRANULAR/pair_gran_jkr_rolling_multi.h b/src/GRANULAR/pair_gran_jkr_rolling_multi.h deleted file mode 100644 index c9c75de9a6..0000000000 --- a/src/GRANULAR/pair_gran_jkr_rolling_multi.h +++ /dev/null @@ -1,87 +0,0 @@ -/* -*- 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. -------------------------------------------------------------------------- */ - -#ifdef PAIR_CLASS - -PairStyle(gran/jkr/rolling/multi,PairGranJKRRollingMulti) - -#else - -#ifndef LMP_PAIR_GRAN_JKR_ROLLING_MULTI_H -#define LMP_PAIR_GRAN_JKR_ROLLING_MULTI_H - -#include "pair.h" - -namespace LAMMPS_NS { - -class PairGranJKRRollingMulti : public Pair { -public: - PairGranJKRRollingMulti(class LAMMPS *); - virtual ~PairGranJKRRollingMulti(); - virtual void compute(int, int); - virtual void settings(int, char **); - virtual void coeff(int, char **); // Made Virtual by IS Oct 7 2017 - void init_style(); - double init_one(int, int); - void write_restart(FILE *); - void read_restart(FILE *); - void write_restart_settings(FILE *); - void read_restart_settings(FILE *); - void reset_dt(); - virtual double single(int, int, int, int, double, double, double, double &); - int pack_forward_comm(int, int *, double *, int, int *); - void unpack_forward_comm(int, int, double *); - double memory_usage(); - - protected: - double cut_global; - double **E,**G,**alpha,**gamman,**muS,**Ecoh,**kR,**muR,**etaR,**cut; - int **normaldamp, **rollingdamp; - double dt; - int freeze_group_bit; - int history; - - int neighprev; - double *onerad_dynamic,*onerad_frozen; - double *maxrad_dynamic,*maxrad_frozen; - - class FixNeighHistory *fix_history; - - // storage of rigid body masses for use in granular interactions - - class Fix *fix_rigid; // ptr to rigid body fix, NULL if none - double *mass_rigid; // rigid mass for owned+ghost atoms - int nmax; // allocated size of mass_rigid - - virtual void allocate(); // Made Virtual by IS Oct 7 2017 - -private: - double mix_stiffnessE(double Eii, double Ejj, double Gii, double Gjj); - double mix_stiffnessG(double Eii, double Ejj, double Gii, double Gjj); - double mix_geom(double valii, double valjj); -}; - -} - -#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. - - */ diff --git a/src/GRANULAR/pair_granular_multi.cpp b/src/GRANULAR/pair_granular_multi.cpp deleted file mode 100644 index 07a6cab3dd..0000000000 --- a/src/GRANULAR/pair_granular_multi.cpp +++ /dev/null @@ -1,1624 +0,0 @@ -/* ---------------------------------------------------------------------- -http://lammps.sandia.gov, Sandia National Laboratories -Steve Plimpton, sjplimp@sandia.gov - -Copyright (2003) Sandia Corporation. Under the terms of Contract -DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains -certain rights in this software. This software is distributed under -the GNU General Public License. - -See the README file in the top-level LAMMPS directory. -------------------------------------------------------------------------- */ - -/* ---------------------------------------------------------------------- -Contributing authors: -Dan Bolintineanu (SNL), Ishan Srivastava (SNL), Jeremy Lechman(SNL) -Leo Silbert (SNL), Gary Grest (SNL) ------------------------------------------------------------------------ */ - -#include -#include -#include -#include -#include "pair_granular_multi.h" -#include "atom.h" -#include "atom_vec.h" -#include "domain.h" -#include "force.h" -#include "update.h" -#include "modify.h" -#include "fix.h" -#include "fix_neigh_history.h" -#include "comm.h" -#include "neighbor.h" -#include "neigh_list.h" -#include "neigh_request.h" -#include "memory.h" -#include "error.h" -#include "math_const.h" - -using namespace LAMMPS_NS; -using namespace MathConst; - -#define PI27SQ 266.47931882941264802866 // 27*PI**2 -#define THREEROOT3 5.19615242270663202362 // 3*sqrt(3) -#define SIXROOT6 14.69693845669906728801 // 6*sqrt(6) -#define INVROOT6 0.40824829046386307274 // 1/sqrt(6) -#define FOURTHIRDS 1.333333333333333 // 4/3 -#define TWOPI 6.28318530717959 // 2*PI - -#define EPSILON 1e-10 - -enum {HOOKE, HERTZ, HERTZ_MATERIAL, DMT, JKR}; -enum {VELOCITY, VISCOELASTIC, TSUJI}; -enum {TANGENTIAL_NOHISTORY, TANGENTIAL_MINDLIN}; -enum {TWIST_NONE, TWIST_NOHISTORY, TWIST_SDS, TWIST_MARSHALL}; -enum {ROLL_NONE, ROLL_NOHISTORY, ROLL_SDS}; - -/* ---------------------------------------------------------------------- */ - -PairGranularMulti::PairGranularMulti(LAMMPS *lmp) : Pair(lmp) -{ - single_enable = 1; - no_virial_fdotr_compute = 1; - fix_history = NULL; - - single_extra = 9; - svector = new double[single_extra]; - - neighprev = 0; - - nmax = 0; - mass_rigid = NULL; - - onerad_dynamic = NULL; - onerad_frozen = NULL; - maxrad_dynamic = NULL; - maxrad_frozen = NULL; - - dt = update->dt; - - // set comm size needed by this Pair if used with fix rigid - - comm_forward = 1; - - use_history = 0; - beyond_contact = 0; - nondefault_history_transfer = 0; - tangential_history_index = 0; - roll_history_index = twist_history_index = 0; - -} - -/* ---------------------------------------------------------------------- */ -PairGranularMulti::~PairGranularMulti() -{ - delete [] svector; - if (fix_history) modify->delete_fix("NEIGH_HISTORY"); - - if (allocated) { - memory->destroy(setflag); - memory->destroy(cutsq); - memory->destroy(cut); - - memory->destroy(normal_coeffs); - memory->destroy(tangential_coeffs); - memory->destroy(roll_coeffs); - memory->destroy(twist_coeffs); - - memory->destroy(normal); - memory->destroy(damping); - memory->destroy(tangential); - memory->destroy(roll); - memory->destroy(twist); - - delete [] onerad_dynamic; - delete [] onerad_frozen; - delete [] maxrad_dynamic; - delete [] maxrad_frozen; - } - memory->destroy(mass_rigid); -} - -void PairGranularMulti::compute(int eflag, int vflag) -{ - int i,j,ii,jj,inum,jnum,itype,jtype; - double xtmp,ytmp,ztmp,delx,dely,delz,fx,fy,fz,nx,ny,nz; - double radi,radj,radsum,rsq,r,rinv,rsqinv; - double Reff, delta, dR, dR2; - - double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3; - double wr1,wr2,wr3; - double vtr1,vtr2,vtr3,vrel; - - double knfac, damp_normal; - double k_tangential, damp_tangential; - double Fne, Ft, Fdamp, Fntot, Fcrit, Fscrit, Frcrit; - double fs, fs1, fs2, fs3; - - //For JKR - double R2, coh, F_pulloff, delta_pulloff, dist_pulloff, a, a2, E; - double t0, t1, t2, t3, t4, t5, t6; - double sqrt1, sqrt2, sqrt3, sqrt4; - - double mi,mj,meff,damp,ccel,tor1,tor2,tor3; - double relrot1,relrot2,relrot3,vrl1,vrl2,vrl3,vrlmag,vrlmaginv; - - //Rolling - double k_roll, damp_roll; - double roll1, roll2, roll3, torroll1, torroll2, torroll3; - double rollmag, rolldotn, scalefac; - double fr, fr1, fr2, fr3; - - //Twisting - double k_twist, damp_twist, mu_twist; - double signtwist, magtwist, magtortwist, Mtcrit; - double tortwist1, tortwist2, tortwist3; - - double shrmag,rsht; - int *ilist,*jlist,*numneigh,**firstneigh; - int *touch,**firsttouch; - double *history,*allhistory,**firsthistory; - - bool touchflag; - - if (eflag || vflag) ev_setup(eflag,vflag); - else evflag = vflag_fdotr = 0; - - int historyupdate = 1; - if (update->setupflag) historyupdate = 0; - - // update rigid body info for owned & ghost atoms if using FixRigid masses - // body[i] = which body atom I is in, -1 if none - // mass_body = mass of each rigid body - - if (fix_rigid && neighbor->ago == 0){ - int tmp; - int *body = (int *) fix_rigid->extract("body",tmp); - double *mass_body = (double *) fix_rigid->extract("masstotal",tmp); - if (atom->nmax > nmax) { - memory->destroy(mass_rigid); - nmax = atom->nmax; - memory->create(mass_rigid,nmax,"pair:mass_rigid"); - } - int nlocal = atom->nlocal; - for (i = 0; i < nlocal; i++) - if (body[i] >= 0) mass_rigid[i] = mass_body[body[i]]; - else mass_rigid[i] = 0.0; - comm->forward_comm_pair(this); - } - - double **x = atom->x; - double **v = atom->v; - double **f = atom->f; - int *type = atom->type; - double **omega = atom->omega; - double **torque = atom->torque; - double *radius = atom->radius; - double *rmass = atom->rmass; - int *mask = atom->mask; - int nlocal = atom->nlocal; - int newton_pair = force->newton_pair; - - inum = list->inum; - ilist = list->ilist; - numneigh = list->numneigh; - firstneigh = list->firstneigh; - firsttouch = fix_history->firstflag; - firsthistory = fix_history->firstvalue; - - for (ii = 0; ii < inum; ii++) { - i = ilist[ii]; - itype = type[i]; - xtmp = x[i][0]; - ytmp = x[i][1]; - ztmp = x[i][2]; - itype = type[i]; - radi = radius[i]; - touch = firsttouch[i]; - allhistory = firsthistory[i]; - jlist = firstneigh[i]; - jnum = numneigh[i]; - - for (jj = 0; jj < jnum; jj++){ - j = jlist[jj]; - j &= NEIGHMASK; - - delx = xtmp - x[j][0]; - dely = ytmp - x[j][1]; - delz = ztmp - x[j][2]; - jtype = type[j]; - rsq = delx*delx + dely*dely + delz*delz; - radj = radius[j]; - radsum = radi + radj; - - E = normal_coeffs[itype][jtype][0]; - Reff = radi*radj/(radi+radj); - touchflag = false; - - if (normal[itype][jtype] == JKR){ - if (touch[jj]){ - R2 = Reff*Reff; - coh = normal_coeffs[itype][jtype][3]; - a = cbrt(9.0*M_PI*coh*R2/(4*E)); - delta_pulloff = a*a/Reff - 2*sqrt(M_PI*coh*a/E); - dist_pulloff = radsum-delta_pulloff; - touchflag = (rsq < dist_pulloff*dist_pulloff); - } - else{ - touchflag = (rsq < radsum*radsum); - } - } - else{ - touchflag = (rsq < radsum*radsum); - } - - if (!touchflag){ - // unset non-touching neighbors - touch[jj] = 0; - history = &allhistory[size_history*jj]; - for (int k = 0; k < size_history; k++) history[k] = 0.0; - } - else{ - r = sqrt(rsq); - rinv = 1.0/r; - - nx = delx*rinv; - ny = dely*rinv; - nz = delz*rinv; - - // relative translational velocity - - vr1 = v[i][0] - v[j][0]; - vr2 = v[i][1] - v[j][1]; - vr3 = v[i][2] - v[j][2]; - - // normal component - - vnnr = vr1*nx + vr2*ny + vr3*nz; //v_R . n - vn1 = nx*vnnr; - vn2 = ny*vnnr; - vn3 = nz*vnnr; - - // meff = effective mass of pair of particles - // if I or J part of rigid body, use body mass - // if I or J is frozen, meff is other particle - - mi = rmass[i]; - mj = rmass[j]; - if (fix_rigid) { - if (mass_rigid[i] > 0.0) mi = mass_rigid[i]; - if (mass_rigid[j] > 0.0) mj = mass_rigid[j]; - } - - meff = mi*mj / (mi+mj); - if (mask[i] & freeze_group_bit) meff = mj; - if (mask[j] & freeze_group_bit) meff = mi; - - delta = radsum - r; - dR = delta*Reff; - if (normal[itype][jtype] == JKR){ - touch[jj] = 1; - R2=Reff*Reff; - coh = normal_coeffs[itype][jtype][3]; - dR2 = dR*dR; - t0 = coh*coh*R2*R2*E; - t1 = PI27SQ*t0; - t2 = 8*dR*dR2*E*E*E; - t3 = 4*dR2*E; - sqrt1 = MAX(0, t0*(t1+2*t2)); //In case of sqrt(0) < 0 due to precision issues - t4 = cbrt(t1+t2+THREEROOT3*M_PI*sqrt(sqrt1)); - t5 = t3/t4 + t4/E; - sqrt2 = MAX(0, 2*dR + t5); - t6 = sqrt(sqrt2); - sqrt3 = MAX(0, 4*dR - t5 + SIXROOT6*coh*M_PI*R2/(E*t6)); - a = INVROOT6*(t6 + sqrt(sqrt3)); - a2 = a*a; - knfac = FOURTHIRDS*E*a; - Fne = knfac*a2/Reff - TWOPI*a2*sqrt(4*coh*E/(M_PI*a)); - } - else{ - knfac = E; //Hooke - Fne = knfac*delta; - if (normal[itype][jtype] != HOOKE) - a = sqrt(dR); - Fne *= a; - if (normal[itype][jtype] == DMT) - Fne -= 4*MY_PI*normal_coeffs[itype][jtype][3]*Reff; - } - - //Consider restricting Hooke to only have 'velocity' as an option for damping? - if (damping[itype][jtype] == VELOCITY){ - damp_normal = 1; - } - else if (damping[itype][jtype] == VISCOELASTIC){ - if (normal[itype][jtype] == HOOKE) a = sqrt(dR); - damp_normal = a*meff; - } - else if (damping[itype][jtype] == TSUJI){ - damp_normal = sqrt(meff*knfac); - } - - Fdamp = -normal_coeffs[itype][jtype][1]*damp_normal*vnnr; - - Fntot = Fne + Fdamp; - - //**************************************** - //Tangential force, including history effects - //**************************************** - - // tangential component - vt1 = vr1 - vn1; - vt2 = vr2 - vn2; - vt3 = vr3 - vn3; - - // relative rotational velocity - wr1 = (radi*omega[i][0] + radj*omega[j][0]); - wr2 = (radi*omega[i][1] + radj*omega[j][1]); - wr3 = (radi*omega[i][2] + radj*omega[j][2]); - - // relative tangential velocities - vtr1 = vt1 - (nz*wr2-ny*wr3); - vtr2 = vt2 - (nx*wr3-nz*wr1); - vtr3 = vt3 - (ny*wr1-nx*wr2); - vrel = vtr1*vtr1 + vtr2*vtr2 + vtr3*vtr3; - vrel = sqrt(vrel); - - // If any history is needed: - if (use_history){ - touch[jj] = 1; - history = &allhistory[size_history*jj]; - } - - if (normal[itype][jtype] == JKR){ - F_pulloff = 3*M_PI*coh*Reff; - Fcrit = fabs(Fne + 2*F_pulloff); - } - else{ - Fcrit = fabs(Fne); - } - - //------------------------------ - //Tangential forces - //------------------------------ - k_tangential = tangential_coeffs[itype][jtype][0]; - damp_tangential = tangential_coeffs[itype][jtype][1]*damp_normal; - - if (tangential_history){ - shrmag = sqrt(history[0]*history[0] + history[1]*history[1] + - history[2]*history[2]); - - // Rotate and update displacements. - // See e.g. eq. 17 of Luding, Gran. Matter 2008, v10,p235 - if (historyupdate) { - rsht = history[0]*nx + history[1]*ny + history[2]*nz; - if (fabs(rsht) < EPSILON) rsht = 0; - if (rsht > 0){ - scalefac = shrmag/(shrmag - rsht); //if rhst == shrmag, contacting pair has rotated 90 deg. in one step, in which case you deserve a crash! - history[0] -= rsht*nx; - history[1] -= rsht*ny; - history[2] -= rsht*nz; - //Also rescale to preserve magnitude - history[0] *= scalefac; - history[1] *= scalefac; - history[2] *= scalefac; - } - //Update history - history[0] += vtr1*dt; - history[1] += vtr2*dt; - history[2] += vtr3*dt; - } - - // tangential forces = history + tangential velocity damping - fs1 = -k_tangential*history[0] - damp_tangential*vtr1; - fs2 = -k_tangential*history[1] - damp_tangential*vtr2; - fs3 = -k_tangential*history[2] - damp_tangential*vtr3; - - // rescale frictional displacements and forces if needed - Fscrit = tangential_coeffs[itype][jtype][2] * Fcrit; - fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); - if (fs > Fscrit) { - if (shrmag != 0.0) { - history[0] = -1.0/k_tangential*(Fscrit*fs1/fs + damp_tangential*vtr1); - history[1] = -1.0/k_tangential*(Fscrit*fs2/fs + damp_tangential*vtr2); - history[2] = -1.0/k_tangential*(Fscrit*fs3/fs + damp_tangential*vtr3); - fs1 *= Fscrit/fs; - fs2 *= Fscrit/fs; - fs3 *= Fscrit/fs; - } else fs1 = fs2 = fs3 = 0.0; - } - } - else{ //Classic pair gran/hooke (no history) - fs = meff*damp_tangential*vrel; - if (vrel != 0.0) Ft = MIN(Fne,fs) / vrel; - else Ft = 0.0; - fs1 = -Ft*vtr1; - fs2 = -Ft*vtr2; - fs3 = -Ft*vtr3; - } - - //**************************************** - // Rolling resistance - //**************************************** - - if (roll[itype][jtype] != ROLL_NONE){ - relrot1 = omega[i][0] - omega[j][0]; - relrot2 = omega[i][1] - omega[j][1]; - relrot3 = omega[i][2] - omega[j][2]; - - // rolling velocity, see eq. 31 of Wang et al, Particuology v 23, p 49 (2015) - // This is different from the Marshall papers, which use the Bagi/Kuhn formulation - // for rolling velocity (see Wang et al for why the latter is wrong) - vrl1 = Reff*(relrot2*nz - relrot3*ny); //- 0.5*((radj-radi)/radsum)*vtr1; - vrl2 = Reff*(relrot3*nx - relrot1*nz); //- 0.5*((radj-radi)/radsum)*vtr2; - vrl3 = Reff*(relrot1*ny - relrot2*nx); //- 0.5*((radj-radi)/radsum)*vtr3; - vrlmag = sqrt(vrl1*vrl1+vrl2*vrl2+vrl3*vrl3); - if (vrlmag != 0.0) vrlmaginv = 1.0/vrlmag; - else vrlmaginv = 0.0; - - if (roll_history){ - int rhist0 = roll_history_index; - int rhist1 = rhist0 + 1; - int rhist2 = rhist1 + 1; - - // Rolling displacement - rollmag = sqrt(history[rhist0]*history[rhist0] + - history[rhist1]*history[rhist1] + - history[rhist2]*history[rhist2]); - - rolldotn = history[rhist0]*nx + history[rhist1]*ny + history[rhist2]*nz; - - if (historyupdate){ - if (fabs(rolldotn) < EPSILON) rolldotn = 0; - if (rolldotn > 0){ //Rotate into tangential plane - scalefac = rollmag/(rollmag - rolldotn); - history[rhist0] -= rolldotn*nx; - history[rhist1] -= rolldotn*ny; - history[rhist2] -= rolldotn*nz; - //Also rescale to preserve magnitude - history[rhist0] *= scalefac; - history[rhist1] *= scalefac; - history[rhist2] *= scalefac; - } - history[rhist0] += vrl1*dt; - history[rhist1] += vrl2*dt; - history[rhist2] += vrl3*dt; - } - - - k_roll = roll_coeffs[itype][jtype][0]; - damp_roll = roll_coeffs[itype][jtype][1]; - fr1 = -k_roll*history[rhist0] - damp_roll*vrl1; - fr2 = -k_roll*history[rhist1] - damp_roll*vrl2; - fr3 = -k_roll*history[rhist2] - damp_roll*vrl3; - - // rescale frictional displacements and forces if needed - Frcrit = roll_coeffs[itype][jtype][2] * Fcrit; - - fr = sqrt(fr1*fr1 + fr2*fr2 + fr3*fr3); - if (fr > Frcrit) { - if (rollmag != 0.0) { - history[rhist0] = -1.0/k_roll*(Frcrit*fr1/fr + damp_roll*vrl1); - history[rhist1] = -1.0/k_roll*(Frcrit*fr2/fr + damp_roll*vrl2); - history[rhist2] = -1.0/k_roll*(Frcrit*fr3/fr + damp_roll*vrl3); - fr1 *= Frcrit/fr; - fr2 *= Frcrit/fr; - fr3 *= Frcrit/fr; - } else fr1 = fr2 = fr3 = 0.0; - } - } - else{ // - fr = meff*roll_coeffs[itype][jtype][1]*vrlmag; - if (vrlmag != 0.0) fr = MIN(Fne, fr) / vrlmag; - else fr = 0.0; - fr1 = -fr*vrl1; - fr2 = -fr*vrl2; - fr3 = -fr*vrl3; - } - } - - //**************************************** - // Twisting torque, including history effects - //**************************************** - if (twist[itype][jtype] != TWIST_NONE){ - magtwist = relrot1*nx + relrot2*ny + relrot3*nz; //Omega_T (eq 29 of Marshall) - if (twist[itype][jtype] == TWIST_MARSHALL){ - k_twist = 0.5*k_tangential*a*a;; //eq 32 - damp_twist = 0.5*damp_tangential*a*a; - mu_twist = TWOTHIRDS*a; - } - else{ - k_twist = twist_coeffs[itype][jtype][0]; - damp_twist = twist_coeffs[itype][jtype][1]; - mu_twist = twist_coeffs[itype][jtype][2]; - } - if (twist[itype][jtype] > 1){ - if (historyupdate){ - history[twist_history_index] += magtwist*dt; - } - magtortwist = -k_twist*history[twist_history_index] - damp_twist*magtwist;//M_t torque (eq 30) - signtwist = (magtwist > 0) - (magtwist < 0); - Mtcrit = TWOTHIRDS*a*Fscrit;//critical torque (eq 44) - if (fabs(magtortwist) > Mtcrit) { - history[twist_history_index] = 1.0/k_twist*(Mtcrit*signtwist - damp_twist*magtwist); - magtortwist = -Mtcrit * signtwist; //eq 34 - } - } - else{ - if (magtwist > 0) magtortwist = -damp_twist*magtwist; - else magtortwist = 0; - } - } - // Apply forces & torques - - fx = nx*Fntot + fs1; - fy = ny*Fntot + fs2; - fz = nz*Fntot + fs3; - - f[i][0] += fx; - f[i][1] += fy; - f[i][2] += fz; - - tor1 = ny*fs3 - nz*fs2; - tor2 = nz*fs1 - nx*fs3; - tor3 = nx*fs2 - ny*fs1; - - torque[i][0] -= radi*tor1; - torque[i][1] -= radi*tor2; - torque[i][2] -= radi*tor3; - - if (twist[itype][jtype] != TWIST_NONE){ - tortwist1 = magtortwist * nx; - tortwist2 = magtortwist * ny; - tortwist3 = magtortwist * nz; - - torque[i][0] += tortwist1; - torque[i][1] += tortwist2; - torque[i][2] += tortwist3; - } - - if (roll[itype][jtype] != ROLL_NONE){ - torroll1 = Reff*(ny*fr3 - nz*fr2); //n cross fr - torroll2 = Reff*(nz*fr1 - nx*fr3); - torroll3 = Reff*(nx*fr2 - ny*fr1); - - torque[i][0] += torroll1; - torque[i][1] += torroll2; - torque[i][2] += torroll3; - } - - if (force->newton_pair || j < nlocal) { - f[j][0] -= fx; - f[j][1] -= fy; - f[j][2] -= fz; - - torque[j][0] -= radj*tor1; - torque[j][1] -= radj*tor2; - torque[j][2] -= radj*tor3; - - if (twist[itype][jtype] != TWIST_NONE){ - torque[j][0] -= tortwist1; - torque[j][1] -= tortwist2; - torque[j][2] -= tortwist3; - } - if (roll[itype][jtype] != ROLL_NONE){ - torque[j][0] -= torroll1; - torque[j][1] -= torroll2; - torque[j][2] -= torroll3; - } - } - if (evflag) ev_tally_xyz(i,j,nlocal,0, - 0.0,0.0,fx,fy,fz,delx,dely,delz); - } - } - } -} - - -/* ---------------------------------------------------------------------- -allocate all arrays -------------------------------------------------------------------------- */ - -void PairGranularMulti::allocate() -{ - allocated = 1; - int n = atom->ntypes; - - memory->create(setflag,n+1,n+1,"pair:setflag"); - for (int i = 1; i <= n; i++) - for (int j = i; j <= n; j++) - setflag[i][j] = 0; - - memory->create(cutsq,n+1,n+1,"pair:cutsq"); - memory->create(cut,n+1,n+1,"pair:cut"); - memory->create(normal_coeffs,n+1,n+1,4,"pair:normal_coeffs"); - memory->create(tangential_coeffs,n+1,n+1,3,"pair:tangential_coeffs"); - memory->create(roll_coeffs,n+1,n+1,3,"pair:roll_coeffs"); - memory->create(twist_coeffs,n+1,n+1,3,"pair:twist_coeffs"); - - memory->create(normal,n+1,n+1,"pair:normal"); - memory->create(damping,n+1,n+1,"pair:damping"); - memory->create(tangential,n+1,n+1,"pair:tangential"); - memory->create(roll,n+1,n+1,"pair:roll"); - memory->create(twist,n+1,n+1,"pair:twist"); - - onerad_dynamic = new double[n+1]; - onerad_frozen = new double[n+1]; - maxrad_dynamic = new double[n+1]; - maxrad_frozen = new double[n+1]; -} - -/* ---------------------------------------------------------------------- - global settings -------------------------------------------------------------------------- */ - -void PairGranularMulti::settings(int narg, char **arg) -{ - if (narg == 1){ - cutoff_global = force->numeric(FLERR,arg[0]); - } - else{ - cutoff_global = -1; //Will be set based on particle sizes, model choice - } - - tangential_history = 0; - roll_history = twist_history = 0; -} - -/* ---------------------------------------------------------------------- - set coeffs for one or more type pairs -------------------------------------------------------------------------- */ - -void PairGranularMulti::coeff(int narg, char **arg) -{ - int normal_local, damping_local, tangential_local, roll_local, twist_local; - - double normal_coeffs_local[4]; - double tangential_coeffs_local[4]; - double roll_coeffs_local[4]; - double twist_coeffs_local[4]; - - if (narg < 2) - error->all(FLERR,"Incorrect args for pair coefficients"); - - if (!allocated) allocate(); - - int ilo,ihi,jlo,jhi; - force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi); - force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi); - - //Defaults - normal_local = tangential_local = -1; - roll_local = twist_local = 0; - damping_local = VISCOELASTIC; - - int iarg = 2; - while (iarg < narg){ - if (strcmp(arg[iarg], "hooke") == 0){ - if (iarg + 2 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hooke option"); - normal_local = HOOKE; - normal_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1]); //kn - normal_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //damping - iarg += 3; - } - else if (strcmp(arg[iarg], "hertz") == 0){ - int num_coeffs = 2; - if (iarg + num_coeffs >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hertz option"); - normal_local = HERTZ; - normal_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1]); //kn - normal_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //damping - iarg += num_coeffs+1; - } - else if (strcmp(arg[iarg], "hertz/material") == 0){ - int num_coeffs = 3; - if (iarg + num_coeffs >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hertz option"); - normal_local = HERTZ; - normal_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1])*FOURTHIRDS; //E - normal_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //damping - normal_coeffs_local[2] = force->numeric(FLERR,arg[iarg+3]); //G - iarg += num_coeffs+1; - } - else if (strcmp(arg[iarg], "dmt") == 0){ - if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hertz option"); - normal_local = DMT; - normal_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1])*FOURTHIRDS; //E - normal_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //damping - normal_coeffs_local[2] = force->numeric(FLERR,arg[iarg+3]); //G - normal_coeffs_local[3] = force->numeric(FLERR,arg[iarg+3]); //cohesion - iarg += 5; - } - else if (strcmp(arg[iarg], "jkr") == 0){ - if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for JKR option"); - beyond_contact = 1; - normal_local = JKR; - normal_coeffs_local[0] = force->numeric(FLERR,arg[iarg+1]); //E - normal_coeffs_local[1] = force->numeric(FLERR,arg[iarg+2]); //damping - normal_coeffs_local[2] = force->numeric(FLERR,arg[iarg+3]); //G - normal_coeffs_local[3] = force->numeric(FLERR,arg[iarg+4]); //cohesion - iarg += 5; - } - else if (strcmp(arg[iarg], "damp") == 0){ - if (iarg+1 >= narg) error->all(FLERR, "Illegal pair_coeff command, not enough parameters provided for damping model"); - if (strcmp(arg[iarg+1], "velocity") == 0){ - damping_local = VELOCITY; - iarg += 1; - } - else if (strcmp(arg[iarg+1], "viscoelastic") == 0){ - damping_local = VISCOELASTIC; - iarg += 1; - } - else if (strcmp(arg[iarg], "tsuji") == 0){ - damping_local = TSUJI; - iarg += 1; - } - } - else if (strcmp(arg[iarg], "tangential") == 0){ - if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for tangential model"); - if (strcmp(arg[iarg+1], "nohistory") == 0){ - tangential_local = TANGENTIAL_NOHISTORY; - } - else if (strcmp(arg[iarg+1], "mindlin") == 0){ - tangential_local = TANGENTIAL_MINDLIN; - tangential_history = 1; - } - else{ - error->all(FLERR, "Illegal pair_coeff command, tangential model not recognized"); - } - tangential_coeffs_local[0] = force->numeric(FLERR,arg[iarg+2]); //kt - tangential_coeffs_local[1] = force->numeric(FLERR,arg[iarg+3]); //gammat - tangential_coeffs_local[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. - iarg += 5; - } - else if (strcmp(arg[iarg], "rolling") == 0){ - if (iarg + 1 >= narg) error->all(FLERR, "Illegal pair_coeff command, not enough parameters"); - if (strcmp(arg[iarg+1], "none") == 0){ - roll_local = ROLL_NONE; - iarg += 2; - } - else{ - if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for rolling model"); - if (strcmp(arg[iarg+1], "nohistory") == 0){ - roll_local = ROLL_NOHISTORY; - } - else if (strcmp(arg[iarg+1], "sds") == 0){ - roll_local = ROLL_SDS; - roll_history = 1; - } - else{ - error->all(FLERR, "Illegal pair_coeff command, rolling friction model not recognized"); - } - roll_coeffs_local[0] = force->numeric(FLERR,arg[iarg+2]); //kR - roll_coeffs_local[1] = force->numeric(FLERR,arg[iarg+3]); //gammaR - roll_coeffs_local[2] = force->numeric(FLERR,arg[iarg+4]); //rolling friction coeff. - iarg += 5; - } - } - else if (strcmp(arg[iarg], "twisting") == 0){ - if (iarg + 1 >= narg) error->all(FLERR, "Illegal pair_coeff command, not enough parameters"); - if (strcmp(arg[iarg+1], "none") == 0){ - twist_local = TWIST_NONE; - iarg += 2; - } - else if (strcmp(arg[iarg+1], "marshall") == 0){ - twist_local = TWIST_MARSHALL; - twist_history = 1; - iarg += 2; - } - else{ - if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for twist model"); - if (strcmp(arg[iarg+1], "nohistory") == 0){ - twist_local = TWIST_NOHISTORY; - } - else if (strcmp(arg[iarg+1], "sds") == 0){ - twist_local = TWIST_SDS; - twist_history = 1; - } - else{ - error->all(FLERR, "Illegal pair_coeff command, twisting friction model not recognized"); - } - twist_coeffs_local[0] = force->numeric(FLERR,arg[iarg+2]); //kt - twist_coeffs_local[1] = force->numeric(FLERR,arg[iarg+3]); //gammat - twist_coeffs_local[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. - iarg += 5; - } - } - else error->all(FLERR, "Illegal pair coeff command"); - } - - //It is an error not to specify normal or tangential model - if ((normal_local < 0) || (tangential_local < 0)) error->all(FLERR, "Illegal pair coeff command, must specify normal contact model"); - - int count = 0; - double damp; - if (damping_local == TSUJI){ - double cor; - cor = normal_coeffs_local[1]; - damp = 1.2728-4.2783*cor+11.087*pow(cor,2)-22.348*pow(cor,3)+ - 27.467*pow(cor,4)-18.022*pow(cor,5)+ - 4.8218*pow(cor,6); - } - else damp = normal_coeffs_local[1]; - - for (int i = ilo; i <= ihi; i++) { - for (int j = MAX(jlo,i); j <= jhi; j++) { - normal[i][j] = normal[j][i] = normal_local; - normal_coeffs[i][j][0] = normal_coeffs[j][i][0] = normal_coeffs_local[0]; - normal_coeffs[i][j][1] = normal_coeffs[j][i][1] = damp; - if (normal_local != HERTZ && normal_local != HOOKE) normal_coeffs[i][j][2] = normal_coeffs_local[2]; - if ((normal_local == JKR) || (normal_local == DMT)) - normal_coeffs[i][j][3] = normal_coeffs[j][i][3] = normal_coeffs_local[3]; - - damping[i][j] = damping[j][i] = damping_local; - - tangential[i][j] = tangential[j][i] = tangential_local; - for (int k = 0; k < 3; k++) - tangential_coeffs[i][j][k] = tangential_coeffs[j][i][k] = tangential_coeffs_local[k]; - - roll[i][j] = roll[j][i] = roll_local; - if (roll_local != ROLL_NONE) - for (int k = 0; k < 3; k++) - roll_coeffs[i][j][k] = roll_coeffs[j][i][k] = roll_coeffs_local[k]; - - twist[i][j] = twist[j][i] = twist_local; - if (twist_local != TWIST_NONE && twist_local != TWIST_MARSHALL) - for (int k = 0; k < 3; k++) - twist_coeffs[i][j][k] = twist_coeffs[j][i][k] = twist_coeffs_local[k]; - - setflag[i][j] = 1; - count++; - } - } - if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); -} - -/* ---------------------------------------------------------------------- - init specific to this pair style -------------------------------------------------------------------------- */ - -void PairGranularMulti::init_style() -{ - int i; - - // error and warning checks - - if (!atom->radius_flag || !atom->rmass_flag) - error->all(FLERR,"Pair granular requires atom attributes radius, rmass"); - if (comm->ghost_velocity == 0) - error->all(FLERR,"Pair granular requires ghost atoms store velocity"); - - // Determine whether we need a granular neigh list, how large it needs to be - use_history = tangential_history || roll_history || twist_history; - - //For JKR, will need fix/neigh/history to keep track of touch arrays - for (int i = 1; i <= atom->ntypes; i++) - for (int j = 1; j <= atom->ntypes; j++) - if (normal[i][j] == JKR) use_history = 1; - - size_history = 3*tangential_history + 3*roll_history + twist_history; - - //Determine location of tangential/roll/twist histories in array - if (roll_history){ - if (tangential_history) roll_history_index = 3; - else roll_history_index = 0; - } - if (twist_history){ - if (tangential_history){ - if (roll_history) twist_history_index = 6; - else twist_history_index = 3; - } - else{ - if (roll_history) twist_history_index = 3; - else twist_history_index = 0; - } - } - - int irequest = neighbor->request(this,instance_me); - neighbor->requests[irequest]->size = 1; - if (use_history) neighbor->requests[irequest]->history = 1; - - dt = update->dt; - - // if history is stored: - // if first init, create Fix needed for storing history - - if (use_history && fix_history == NULL) { - char dnumstr[16]; - sprintf(dnumstr,"%d",size_history); - char **fixarg = new char*[4]; - fixarg[0] = (char *) "NEIGH_HISTORY"; - fixarg[1] = (char *) "all"; - fixarg[2] = (char *) "NEIGH_HISTORY"; - fixarg[3] = dnumstr; - modify->add_fix(4,fixarg,1); - delete [] fixarg; - fix_history = (FixNeighHistory *) modify->fix[modify->nfix-1]; - fix_history->pair = this; - } - - // check for FixFreeze and set freeze_group_bit - - for (i = 0; i < modify->nfix; i++) - if (strcmp(modify->fix[i]->style,"freeze") == 0) break; - if (i < modify->nfix) freeze_group_bit = modify->fix[i]->groupbit; - else freeze_group_bit = 0; - - // check for FixRigid so can extract rigid body masses - - fix_rigid = NULL; - for (i = 0; i < modify->nfix; i++) - if (modify->fix[i]->rigid_flag) break; - if (i < modify->nfix) fix_rigid = modify->fix[i]; - - // check for FixPour and FixDeposit so can extract particle radii - - int ipour; - for (ipour = 0; ipour < modify->nfix; ipour++) - if (strcmp(modify->fix[ipour]->style,"pour") == 0) break; - if (ipour == modify->nfix) ipour = -1; - - int idep; - for (idep = 0; idep < modify->nfix; idep++) - if (strcmp(modify->fix[idep]->style,"deposit") == 0) break; - if (idep == modify->nfix) idep = -1; - - // set maxrad_dynamic and maxrad_frozen for each type - // include future FixPour and FixDeposit particles as dynamic - - int itype; - for (i = 1; i <= atom->ntypes; i++) { - onerad_dynamic[i] = onerad_frozen[i] = 0.0; - if (ipour >= 0) { - itype = i; - double radmax = *((double *) modify->fix[ipour]->extract("radius",itype)); - if (normal[itype][itype] == JKR) radmax = radmax - 0.5*pulloff_distance(radmax, itype); - onerad_dynamic[i] = radmax; - } - if (idep >= 0) { - itype = i; - double radmax = *((double *) modify->fix[idep]->extract("radius",itype)); - if (normal[itype][itype] == JKR) radmax = radmax - 0.5*pulloff_distance(radmax, itype); - onerad_dynamic[i] = radmax; - } - } - - double *radius = atom->radius; - int *mask = atom->mask; - int *type = atom->type; - int nlocal = atom->nlocal; - - for (i = 0; i < nlocal; i++){ - double radius_cut = radius[i]; - if (normal[type[i]][type[i]] == JKR){ - radius_cut = radius[i] - 0.5*pulloff_distance(radius[i], type[i]); - } - if (mask[i] & freeze_group_bit){ - onerad_frozen[type[i]] = MAX(onerad_frozen[type[i]],radius_cut); - } - else{ - onerad_dynamic[type[i]] = MAX(onerad_dynamic[type[i]],radius_cut); - } - } - - MPI_Allreduce(&onerad_dynamic[1],&maxrad_dynamic[1],atom->ntypes, - MPI_DOUBLE,MPI_MAX,world); - MPI_Allreduce(&onerad_frozen[1],&maxrad_frozen[1],atom->ntypes, - MPI_DOUBLE,MPI_MAX,world); - - // set fix which stores history info - - if (size_history > 0){ - int ifix = modify->find_fix("NEIGH_HISTORY"); - if (ifix < 0) error->all(FLERR,"Could not find pair fix neigh history ID"); - fix_history = (FixNeighHistory *) modify->fix[ifix]; - } -} - -/* ---------------------------------------------------------------------- - init for one type pair i,j and corresponding j,i -------------------------------------------------------------------------- */ - -double PairGranularMulti::init_one(int i, int j) -{ - double cutoff; - if (setflag[i][j] == 0) { - if ((normal[i][i] != normal[j][j]) || - (damping[i][i] != damping[j][j]) || - (tangential[i][i] != tangential[j][j]) || - (roll[i][i] != roll[j][j]) || - (twist[i][i] != twist[j][j])){ - - char str[512]; - sprintf(str,"Granular pair style functional forms are different, cannot mix coefficients for types %d and %d. \nThis combination must be set explicitly via pair_coeff command.",i,j); - error->one(FLERR,str); - } - - if (normal[i][j] != HOOKE && normal[i][j] != HERTZ){ - normal_coeffs[i][j][0] = normal_coeffs[j][i][0] = mix_stiffnessE(normal_coeffs[i][i][0], normal_coeffs[j][j][0], - normal_coeffs[i][i][2], normal_coeffs[j][j][2]); - normal_coeffs[i][j][2] = normal_coeffs[j][i][2] = mix_stiffnessG(normal_coeffs[i][i][0], normal_coeffs[j][j][0], - normal_coeffs[i][i][2], normal_coeffs[j][j][2]); - } - else{ - normal_coeffs[i][j][0] = normal_coeffs[j][i][0] = mix_geom(normal_coeffs[i][i][0], normal_coeffs[j][j][0]); - } - - normal_coeffs[i][j][1] = normal_coeffs[j][i][1] = mix_geom(normal_coeffs[i][i][1], normal_coeffs[j][j][1]); - if ((normal[i][i] == JKR) || (normal[i][i] == DMT)) - normal_coeffs[i][j][3] = normal_coeffs[j][i][3] = mix_geom(normal_coeffs[i][i][3], normal_coeffs[j][j][3]); - - for (int k = 0; k < 3; k++) - tangential_coeffs[i][j][k] = normal_coeffs[j][i][k] = mix_geom(tangential_coeffs[i][i][k], tangential_coeffs[j][j][k]); - - - if (roll[i][i] != ROLL_NONE){ - for (int k = 0; k < 3; k++) - roll_coeffs[i][j][k] = roll_coeffs[j][i][k] = mix_geom(roll_coeffs[i][i][k], roll_coeffs[j][j][k]); - } - - if (twist[i][i] != TWIST_NONE && twist[i][i] != TWIST_MARSHALL){ - for (int k = 0; k < 3; k++) - twist_coeffs[i][j][k] = twist_coeffs[j][i][k] = mix_geom(twist_coeffs[i][i][k], twist_coeffs[j][j][k]); - } - } - - // It is possible that cut[i][j] at this point is still 0.0. This can happen when - // there is a future fix_pour after the current run. A cut[i][j] = 0.0 creates - // problems because neighbor.cpp uses min(cut[i][j]) to decide on the bin size - // To avoid this issue, for cases involving cut[i][j] = 0.0 (possible only - // if there is no current information about radius/cutoff of type i and j). - // we assign cutoff = max(cut[i][j]) for i,j such that cut[i][j] > 0.0. - - if (cutoff_global < 0){ - if (((maxrad_dynamic[i] > 0.0) && (maxrad_dynamic[j] > 0.0)) || - ((maxrad_dynamic[i] > 0.0) && (maxrad_frozen[j] > 0.0)) || - ((maxrad_frozen[i] > 0.0) && (maxrad_dynamic[j] > 0.0))) { // radius info about both i and j exist - cutoff = maxrad_dynamic[i]+maxrad_dynamic[j]; - cutoff = MAX(cutoff,maxrad_frozen[i]+maxrad_dynamic[j]); - cutoff = MAX(cutoff,maxrad_dynamic[i]+maxrad_frozen[j]); - } - else { // radius info about either i or j does not exist (i.e. not present and not about to get poured; set to largest value to not interfere with neighbor list) - double cutmax = 0.0; - for (int k = 1; k <= atom->ntypes; k++) { - cutmax = MAX(cutmax,2.0*maxrad_dynamic[k]); - cutmax = MAX(cutmax,2.0*maxrad_frozen[k]); - } - cutoff = cutmax; - } - } - else{ - cutoff = cutoff_global; - } - return cutoff; -} - - -/* ---------------------------------------------------------------------- - proc 0 writes to restart file - ------------------------------------------------------------------------- */ - -void PairGranularMulti::write_restart(FILE *fp) -{ - int i,j; - for (i = 1; i <= atom->ntypes; i++) { - for (j = i; j <= atom->ntypes; j++) { - fwrite(&setflag[i][j],sizeof(int),1,fp); - if (setflag[i][j]) { - fwrite(&normal[i][j],sizeof(int),1,fp); - fwrite(&damping[i][j],sizeof(int),1,fp); - fwrite(&tangential[i][j],sizeof(int),1,fp); - fwrite(&roll[i][j],sizeof(int),1,fp); - fwrite(&twist[i][j],sizeof(int),1,fp); - fwrite(&normal_coeffs[i][j],sizeof(double),4,fp); - fwrite(&tangential_coeffs[i][j],sizeof(double),3,fp); - fwrite(&roll_coeffs[i][j],sizeof(double),3,fp); - fwrite(&twist_coeffs[i][j],sizeof(double),3,fp); - fwrite(&cut[i][j],sizeof(double),1,fp); - } - } - } -} - -/* ---------------------------------------------------------------------- - proc 0 reads from restart file, bcasts - ------------------------------------------------------------------------- */ - -void PairGranularMulti::read_restart(FILE *fp) -{ - allocate(); - int i,j; - int me = comm->me; - for (i = 1; i <= atom->ntypes; i++) { - for (j = i; j <= atom->ntypes; j++) { - if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp); - MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world); - if (setflag[i][j]) { - if (me == 0) { - fread(&normal[i][j],sizeof(int),1,fp); - fread(&damping[i][j],sizeof(int),1,fp); - fread(&tangential[i][j],sizeof(int),1,fp); - fread(&roll[i][j],sizeof(int),1,fp); - fread(&twist[i][j],sizeof(int),1,fp); - fread(&normal_coeffs[i][j],sizeof(double),4,fp); - fread(&tangential_coeffs[i][j],sizeof(double),3,fp); - fread(&roll_coeffs[i][j],sizeof(double),3,fp); - fread(&twist_coeffs[i][j],sizeof(double),3,fp); - fread(&cut[i][j],sizeof(double),1,fp); - } - MPI_Bcast(&normal[i][j],1,MPI_INT,0,world); - MPI_Bcast(&damping[i][j],1,MPI_INT,0,world); - MPI_Bcast(&tangential[i][j],1,MPI_INT,0,world); - MPI_Bcast(&roll[i][j],1,MPI_INT,0,world); - MPI_Bcast(&twist[i][j],1,MPI_INT,0,world); - MPI_Bcast(&normal_coeffs[i][j],4,MPI_DOUBLE,0,world); - MPI_Bcast(&tangential_coeffs[i][j],3,MPI_DOUBLE,0,world); - MPI_Bcast(&roll_coeffs[i][j],3,MPI_DOUBLE,0,world); - MPI_Bcast(&twist_coeffs[i][j],3,MPI_DOUBLE,0,world); - MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); - } - } - } -} - - -/* ---------------------------------------------------------------------- */ - -void PairGranularMulti::reset_dt() -{ - dt = update->dt; -} - -/* ---------------------------------------------------------------------- */ - -double PairGranularMulti::single(int i, int j, int itype, int jtype, - double rsq, double factor_coul, double factor_lj, double &fforce) -{ - double radi,radj,radsum; - double r,rinv,rsqinv,delx,dely,delz, nx, ny, nz, Reff; - double dR, dR2; - double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3,wr1,wr2,wr3; - double vtr1,vtr2,vtr3,vrel; - double mi,mj,meff,damp,ccel,tor1,tor2,tor3; - double relrot1,relrot2,relrot3,vrl1,vrl2,vrl3,vrlmag,vrlmaginv; - - double knfac, damp_normal; - double k_tangential, damp_tangential; - double Fne, Ft, Fdamp, Fntot, Fcrit, Fscrit, Frcrit; - double fs, fs1, fs2, fs3; - - //For JKR - double R2, coh, F_pulloff, delta_pulloff, dist_pulloff, a, a2, E; - double delta, t0, t1, t2, t3, t4, t5, t6; - double sqrt1, sqrt2, sqrt3, sqrt4; - - - //Rolling - double k_roll, damp_roll; - double roll1, roll2, roll3, torroll1, torroll2, torroll3; - double rollmag, rolldotn, scalefac; - double fr, fr1, fr2, fr3; - - //Twisting - double k_twist, damp_twist, mu_twist; - double signtwist, magtwist, magtortwist, Mtcrit; - double tortwist1, tortwist2, tortwist3; - - double shrmag,rsht; - int jnum; - int *ilist,*jlist,*numneigh,**firstneigh; - int *touch,**firsttouch; - double *history,*allhistory,**firsthistory; - - double *radius = atom->radius; - radi = radius[i]; - radj = radius[j]; - radsum = radi + radj; - Reff = radi*radj/(radi+radj); - - bool touchflag; - if (normal[itype][jtype] == JKR){ - R2 = Reff*Reff; - coh = normal_coeffs[itype][jtype][3]; - a = cbrt(9.0*M_PI*coh*R2/(4*E)); - delta_pulloff = a*a/Reff - 2*sqrt(M_PI*coh*a/E); - dist_pulloff = radsum+delta_pulloff; - touchflag = (rsq <= dist_pulloff*dist_pulloff); - } - else{ - touchflag = (rsq <= radsum*radsum); - } - - if (touchflag){ - fforce = 0.0; - for (int m = 0; m < single_extra; m++) svector[m] = 0.0; - return 0.0; - } - - double **x = atom->x; - delx = x[i][0] - x[j][0]; - dely = x[i][1] - x[j][1]; - delz = x[i][2] - x[j][2]; - r = sqrt(rsq); - rinv = 1.0/r; - - nx = delx*rinv; - ny = dely*rinv; - nz = delz*rinv; - - // relative translational velocity - - double **v = atom->v; - vr1 = v[i][0] - v[j][0]; - vr2 = v[i][1] - v[j][1]; - vr3 = v[i][2] - v[j][2]; - - // normal component - - vnnr = vr1*nx + vr2*ny + vr3*nz; - vn1 = nx*vnnr; - vn2 = ny*vnnr; - vn3 = nz*vnnr; - - double *rmass = atom->rmass; - int *mask = atom->mask; - mi = rmass[i]; - mj = rmass[j]; - if (fix_rigid) { - if (mass_rigid[i] > 0.0) mi = mass_rigid[i]; - if (mass_rigid[j] > 0.0) mj = mass_rigid[j]; - } - - meff = mi*mj / (mi+mj); - if (mask[i] & freeze_group_bit) meff = mj; - if (mask[j] & freeze_group_bit) meff = mi; - - delta = radsum - r; - dR = delta*Reff; - - // tangential component - - vt1 = vr1 - vn1; - vt2 = vr2 - vn2; - vt3 = vr3 - vn3; - - // relative rotational velocity - - double **omega = atom->omega; - wr1 = (radi*omega[i][0] + radj*omega[j][0]); - wr2 = (radi*omega[i][1] + radj*omega[j][1]); - wr3 = (radi*omega[i][2] + radj*omega[j][2]); - - // meff = effective mass of pair of particles - // if I or J part of rigid body, use body mass - // if I or J is frozen, meff is other particle - - int *type = atom->type; - - mi = rmass[i]; - mj = rmass[j]; - if (fix_rigid) { - // NOTE: ensure mass_rigid is current for owned+ghost atoms? - if (mass_rigid[i] > 0.0) mi = mass_rigid[i]; - if (mass_rigid[j] > 0.0) mj = mass_rigid[j]; - } - - meff = mi*mj / (mi+mj); - if (mask[i] & freeze_group_bit) meff = mj; - if (mask[j] & freeze_group_bit) meff = mi; - - delta = radsum - r; - dR = delta*Reff; - if (normal[itype][jtype] == JKR){ - dR2 = dR*dR; - t0 = coh*coh*R2*R2*E; - t1 = PI27SQ*t0; - t2 = 8*dR*dR2*E*E*E; - t3 = 4*dR2*E; - sqrt1 = MAX(0, t0*(t1+2*t2)); //In case of sqrt(0) < 0 due to precision issues - t4 = cbrt(t1+t2+THREEROOT3*M_PI*sqrt(sqrt1)); - t5 = t3/t4 + t4/E; - sqrt2 = MAX(0, 2*dR + t5); - t6 = sqrt(sqrt2); - sqrt3 = MAX(0, 4*dR - t5 + SIXROOT6*coh*M_PI*R2/(E*t6)); - a = INVROOT6*(t6 + sqrt(sqrt3)); - a2 = a*a; - knfac = FOURTHIRDS*E*a; - Fne = knfac*a2/Reff - TWOPI*a2*sqrt(4*coh*E/(M_PI*a)); - } - else{ - knfac = E; - Fne = knfac*delta; - if (normal[itype][jtype] != HOOKE) - a = sqrt(dR); - Fne *= a; - if (normal[itype][jtype] == DMT) - Fne -= 4*MY_PI*normal_coeffs[itype][jtype][3]*Reff; - } - - //Consider restricting Hooke to only have 'velocity' as an option for damping? - if (damping[itype][jtype] == VELOCITY){ - damp_normal = normal_coeffs[itype][jtype][1]; - } - else if (damping[itype][jtype] == VISCOELASTIC){ - if (normal[itype][jtype] == HOOKE) a = sqrt(dR); - damp_normal = normal_coeffs[itype][jtype][1]*a*meff; - } - else if (damping[itype][jtype] == TSUJI){ - damp_normal = normal_coeffs[itype][jtype][1]*sqrt(meff*knfac); - } - - Fdamp = -damp_normal*vnnr; - - Fntot = Fne + Fdamp; - - jnum = list->numneigh[i]; - jlist = list->firstneigh[i]; - - if (use_history){ - allhistory = fix_history->firstvalue[i]; - for (int jj = 0; jj < jnum; jj++) { - neighprev++; - if (neighprev >= jnum) neighprev = 0; - if (jlist[neighprev] == j) break; - } - history = &allhistory[size_history*neighprev]; - } - - //**************************************** - //Tangential force, including history effects - //**************************************** - - // tangential component - vt1 = vr1 - vn1; - vt2 = vr2 - vn2; - vt3 = vr3 - vn3; - - // relative rotational velocity - wr1 = (radi*omega[i][0] + radj*omega[j][0]); - wr2 = (radi*omega[i][1] + radj*omega[j][1]); - wr3 = (radi*omega[i][2] + radj*omega[j][2]); - - // relative tangential velocities - vtr1 = vt1 - (nz*wr2-ny*wr3); - vtr2 = vt2 - (nx*wr3-nz*wr1); - vtr3 = vt3 - (ny*wr1-nx*wr2); - vrel = vtr1*vtr1 + vtr2*vtr2 + vtr3*vtr3; - vrel = sqrt(vrel); - - if (normal[itype][jtype] == JKR){ - F_pulloff = 3*M_PI*coh*Reff; - Fcrit = fabs(Fne + 2*F_pulloff); - } - else{ - Fcrit = fabs(Fne); - } - - //------------------------------ - //Tangential forces - //------------------------------ - k_tangential = tangential_coeffs[itype][jtype][0]; - if (normal[itype][jtype] != HOOKE){ - k_tangential *= a; - } - damp_tangential = tangential_coeffs[itype][jtype][1]*damp_normal; - - if (tangential_history){ - shrmag = sqrt(history[0]*history[0] + history[1]*history[1] + - history[2]*history[2]); - - // tangential forces = history + tangential velocity damping - fs1 = -k_tangential*history[0] - damp_tangential*vtr1; - fs2 = -k_tangential*history[1] - damp_tangential*vtr2; - fs3 = -k_tangential*history[2] - damp_tangential*vtr3; - - // rescale frictional displacements and forces if needed - Fscrit = tangential_coeffs[itype][jtype][2] * Fcrit; - fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); - if (fs > Fscrit) { - if (shrmag != 0.0) { - history[0] = -1.0/k_tangential*(Fscrit*fs1/fs + damp_tangential*vtr1); - history[1] = -1.0/k_tangential*(Fscrit*fs2/fs + damp_tangential*vtr2); - history[2] = -1.0/k_tangential*(Fscrit*fs3/fs + damp_tangential*vtr3); - fs1 *= Fscrit/fs; - fs2 *= Fscrit/fs; - fs3 *= Fscrit/fs; - } else fs1 = fs2 = fs3 = 0.0; - } - } - else{ //Classic pair gran/hooke (no history) - fs = meff*damp_tangential*vrel; - if (vrel != 0.0) Ft = MIN(Fne,fs) / vrel; - else Ft = 0.0; - fs1 = -Ft*vtr1; - fs2 = -Ft*vtr2; - fs3 = -Ft*vtr3; - } - - //**************************************** - // Rolling resistance - //**************************************** - - if (roll[itype][jtype] != ROLL_NONE){ - relrot1 = omega[i][0] - omega[j][0]; - relrot2 = omega[i][1] - omega[j][1]; - relrot3 = omega[i][2] - omega[j][2]; - - // rolling velocity, see eq. 31 of Wang et al, Particuology v 23, p 49 (2015) - // This is different from the Marshall papers, which use the Bagi/Kuhn formulation - // for rolling velocity (see Wang et al for why the latter is wrong) - vrl1 = Reff*(relrot2*nz - relrot3*ny); //- 0.5*((radj-radi)/radsum)*vtr1; - vrl2 = Reff*(relrot3*nx - relrot1*nz); //- 0.5*((radj-radi)/radsum)*vtr2; - vrl3 = Reff*(relrot1*ny - relrot2*nx); //- 0.5*((radj-radi)/radsum)*vtr3; - vrlmag = sqrt(vrl1*vrl1+vrl2*vrl2+vrl3*vrl3); - if (vrlmag != 0.0) vrlmaginv = 1.0/vrlmag; - else vrlmaginv = 0.0; - - if (roll_history){ - int rhist0 = roll_history_index; - int rhist1 = rhist0 + 1; - int rhist2 = rhist1 + 1; - - // Rolling displacement - rollmag = sqrt(history[rhist0]*history[rhist0] + - history[rhist1]*history[rhist1] + - history[rhist2]*history[rhist2]); - - rolldotn = history[rhist0]*nx + history[rhist1]*ny + history[rhist2]*nz; - - k_roll = roll_coeffs[itype][jtype][0]; - damp_roll = roll_coeffs[itype][jtype][1]; - fr1 = -k_roll*history[rhist0] - damp_roll*vrl1; - fr2 = -k_roll*history[rhist1] - damp_roll*vrl2; - fr3 = -k_roll*history[rhist2] - damp_roll*vrl3; - - // rescale frictional displacements and forces if needed - Frcrit = roll_coeffs[itype][jtype][2] * Fcrit; - - fr = sqrt(fr1*fr1 + fr2*fr2 + fr3*fr3); - if (fr > Frcrit) { - if (rollmag != 0.0) { - history[rhist0] = -1.0/k_roll*(Frcrit*fr1/fr + damp_roll*vrl1); - history[rhist1] = -1.0/k_roll*(Frcrit*fr2/fr + damp_roll*vrl2); - history[rhist2] = -1.0/k_roll*(Frcrit*fr3/fr + damp_roll*vrl3); - fr1 *= Frcrit/fr; - fr2 *= Frcrit/fr; - fr3 *= Frcrit/fr; - } else fr1 = fr2 = fr3 = 0.0; - } - } - else{ // - fr = meff*roll_coeffs[itype][jtype][1]*vrlmag; - if (vrlmag != 0.0) fr = MIN(Fne, fr) / vrlmag; - else fr = 0.0; - fr1 = -fr*vrl1; - fr2 = -fr*vrl2; - fr3 = -fr*vrl3; - } - } - - //**************************************** - // Twisting torque, including history effects - //**************************************** - if (twist[itype][jtype] != TWIST_NONE){ - magtwist = relrot1*nx + relrot2*ny + relrot3*nz; //Omega_T (eq 29 of Marshall) - if (twist[itype][jtype] == TWIST_MARSHALL){ - k_twist = 0.5*k_tangential*a*a;; //eq 32 - damp_twist = 0.5*damp_tangential*a*a; - mu_twist = TWOTHIRDS*a; - } - else{ - k_twist = twist_coeffs[itype][jtype][0]; - damp_twist = twist_coeffs[itype][jtype][1]; - mu_twist = twist_coeffs[itype][jtype][2]; - } - if (twist_history){ - magtortwist = -k_twist*history[twist_history_index] - damp_twist*magtwist;//M_t torque (eq 30) - signtwist = (magtwist > 0) - (magtwist < 0); - Mtcrit = TWOTHIRDS*a*Fscrit;//critical torque (eq 44) - if (fabs(magtortwist) > Mtcrit) { - history[twist_history_index] = 1.0/k_twist*(Mtcrit*signtwist - damp_twist*magtwist); - magtortwist = -Mtcrit * signtwist; //eq 34 - } - } - else{ - if (magtwist > 0) magtortwist = -damp_twist*magtwist; - else magtortwist = 0; - } - } - - // set single_extra quantities - - svector[0] = fs1; - svector[1] = fs2; - svector[2] = fs3; - svector[3] = fs; - svector[4] = fr1; - svector[5] = fr2; - svector[6] = fr3; - svector[7] = fr; - svector[8] = magtortwist; - return 0.0; -} - -/* ---------------------------------------------------------------------- */ - -int PairGranularMulti::pack_forward_comm(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = mass_rigid[j]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void PairGranularMulti::unpack_forward_comm(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) - mass_rigid[i] = buf[m++]; -} - -/* ---------------------------------------------------------------------- - memory usage of local atom-based arrays - ------------------------------------------------------------------------- */ - -double PairGranularMulti::memory_usage() -{ - double bytes = nmax * sizeof(double); - return bytes; -} - -/* ---------------------------------------------------------------------- - mixing of Young's modulus (E) -------------------------------------------------------------------------- */ - -double PairGranularMulti::mix_stiffnessE(double Eii, double Ejj, double Gii, double Gjj) -{ - double poisii = Eii/(2.0*Gii) - 1.0; - double poisjj = Ejj/(2.0*Gjj) - 1.0; - return 1/((1-poisii*poisjj)/Eii+(1-poisjj*poisjj)/Ejj); -} - -/* ---------------------------------------------------------------------- - mixing of shear modulus (G) - ------------------------------------------------------------------------- */ - -double PairGranularMulti::mix_stiffnessG(double Eii, double Ejj, double Gii, double Gjj) -{ - double poisii = Eii/(2.0*Gii) - 1.0; - double poisjj = Ejj/(2.0*Gjj) - 1.0; - return 1/((2.0 -poisjj)/Gii+(2.0-poisjj)/Gjj); -} - -/* ---------------------------------------------------------------------- - mixing of everything else -------------------------------------------------------------------------- */ - -double PairGranularMulti::mix_geom(double valii, double valjj) -{ - return sqrt(valii*valjj); -} - - -/* ---------------------------------------------------------------------- - Compute pull-off distance (beyond contact) for a given radius and atom type -------------------------------------------------------------------------- */ - -double PairGranularMulti::pulloff_distance(double radius, int itype) -{ - double E, coh, a, delta_pulloff; - coh = normal_coeffs[itype][itype][3]; - E = mix_stiffnessE(normal_coeffs[itype][itype][0], normal_coeffs[itype][itype][0], - normal_coeffs[itype][itype][2], normal_coeffs[itype][itype][2]); - a = cbrt(9*M_PI*coh*radius*radius/(4*E)); - return a*a/radius - 2*sqrt(M_PI*coh*a/E); -} - diff --git a/src/GRANULAR/pair_granular_multi.h b/src/GRANULAR/pair_granular_multi.h deleted file mode 100644 index 95beb950f4..0000000000 --- a/src/GRANULAR/pair_granular_multi.h +++ /dev/null @@ -1,107 +0,0 @@ -/* ---------------------------------------------------------- - LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator - http://lammps.sandia.gov, Sandia National Laboratories - Steve Plimpton, sjplimp@sandia.gov - - Copyright (2003) Sandia Corporation. Under the terms of Contract - DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains - certain 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(granular/multi,PairGranularMulti) - -#else - -#ifndef LMP_PAIR_GRANULAR_MULTI_H -#define LMP_PAIR_GRANULAR_MULTI_H - -#include "pair.h" - -namespace LAMMPS_NS { - -class PairGranularMulti : public Pair { -public: - PairGranularMulti(class LAMMPS *); - virtual ~PairGranularMulti(); - virtual void compute(int, int); - virtual void settings(int, char **); - virtual void coeff(int, char **); - void init_style(); - double init_one(int, int); - void write_restart(FILE *); - void read_restart(FILE *); - void reset_dt(); - virtual double single(int, int, int, int, double, double, double, double &); - int pack_forward_comm(int, int *, double *, int, int *); - void unpack_forward_comm(int, int, double *); - double memory_usage(); - - protected: - double cut_global; - double dt; - int freeze_group_bit; - int use_history; - - int neighprev; - double *onerad_dynamic,*onerad_frozen; - double *maxrad_dynamic,*maxrad_frozen; - double **cut; - - class FixNeighHistory *fix_history; - - // storage of rigid body masses for use in granular interactions - - class Fix *fix_rigid; // ptr to rigid body fix, NULL if none - double *mass_rigid; // rigid mass for owned+ghost atoms - int nmax; // allocated size of mass_rigid - - virtual void allocate(); - -private: - int size_history; - - //Models - int **normal, **damping, **tangential, **roll, **twist; - - //History flags - int tangential_history, roll_history, twist_history; - - //Indices of history entries - int tangential_history_index; - int roll_history_index; - int twist_history_index; - - //Per-type coefficients, set in pair coeff command - double ***normal_coeffs; - double ***tangential_coeffs; - double ***roll_coeffs; - double ***twist_coeffs; - - //Optional user-specified global cutoff - double cutoff_global; - - double mix_stiffnessE(double Eii, double Ejj, double Gii, double Gjj); - double mix_stiffnessG(double Eii, double Ejj, double Gii, double Gjj); - double mix_geom(double valii, double valjj); - double pulloff_distance(double radius, int itype); -}; - -} - -#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. - - */ From 4ee98d18daad7150e1c53f29c1db0962b4f92a1b Mon Sep 17 00:00:00 2001 From: "Dan S. Bolintineanu" Date: Wed, 6 Mar 2019 14:15:19 -0700 Subject: [PATCH 25/44] Fixed missing reference in pair_granular doc page --- doc/src/pair_granular.txt | 56 +++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/doc/src/pair_granular.txt b/doc/src/pair_granular.txt index 911e3cc1dc..dcc756201c 100644 --- a/doc/src/pair_granular.txt +++ b/doc/src/pair_granular.txt @@ -264,7 +264,7 @@ F_\{n0\} = \|\mathbf\{F\}_n\| \end\{equation\} For cohesive models such as {jkr} and {dmt}, the critical force is adjusted so that the critical tangential -force approaches \(\mu_t F_\{pulloff\}\), see "Marshall"_#Marshall2009, equation 43, and "Thornton"_#. +force approaches \(\mu_t F_\{pulloff\}\), see "Marshall"_#Marshall2009, equation 43, and "Thornton"_#Thornton1991. For both models, \(F_\{n0\}\) takes the form: \begin\{equation\} @@ -578,41 +578,41 @@ For the {pair_coeff} settings: {damping viscoelastic}, {rolling none}, {twisting [References:] - :link(Brill1996) +:link(Brill1996) [(Brilliantov et al, 1996)] Brilliantov, N. V., Spahn, F., Hertzsch, J. M., & Poschel, T. (1996). Model for collisions in granular gases. Physical review E, 53(5), 5382. - :link(Tsuji1992) - [(Tsuji et al, 1992)] Tsuji, Y., Tanaka, T., & Ishida, T. (1992). Lagrangian numerical simulation of plug flow of - cohesionless particles in a horizontal pipe. Powder technology, 71(3), 239-250. +:link(Tsuji1992) +[(Tsuji et al, 1992)] Tsuji, Y., Tanaka, T., & Ishida, T. (1992). Lagrangian numerical simulation of plug flow of +cohesionless particles in a horizontal pipe. Powder technology, 71(3), 239-250. - :link(JKR1971) - [(Johnson et al, 1971)] Johnson, K. L., Kendall, K., & Roberts, A. D. (1971). - Surface energy and the contact of elastic solids. Proc. R. Soc. Lond. A, 324(1558), 301-313. +:link(JKR1971) +[(Johnson et al, 1971)] Johnson, K. L., Kendall, K., & Roberts, A. D. (1971). +Surface energy and the contact of elastic solids. Proc. R. Soc. Lond. A, 324(1558), 301-313. - :link(DMT1975) - [Derjaguin et al, 1975)] Derjaguin, B. V., Muller, V. M., & Toporov, Y. P. (1975). Effect of contact deformations on the - adhesion of particles. Journal of Colloid and interface science, 53(2), 314-326. +:link(DMT1975) +[Derjaguin et al, 1975)] Derjaguin, B. V., Muller, V. M., & Toporov, Y. P. (1975). Effect of contact deformations on the +adhesion of particles. Journal of Colloid and interface science, 53(2), 314-326. - :link(Luding2008) - [(Luding, 2008)] Luding, S. (2008). Cohesive, frictional powders: contact models for tension. Granular matter, 10(4), 235. +:link(Luding2008) +[(Luding, 2008)] Luding, S. (2008). Cohesive, frictional powders: contact models for tension. Granular matter, 10(4), 235. - :link(Marshall2009) - [(Marshall, 2009)] Marshall, J. S. (2009). Discrete-element modeling of particulate aerosol flows. - Journal of Computational Physics, 228(5), 1541-1561. +:link(Marshall2009) +[(Marshall, 2009)] Marshall, J. S. (2009). Discrete-element modeling of particulate aerosol flows. +Journal of Computational Physics, 228(5), 1541-1561. - :link(Silbert2001) - [(Silbert, 2001)] Silbert, L. E., Ertas, D., Grest, G. S., Halsey, T. C., Levine, D., & Plimpton, S. J. (2001). - Granular flow down an inclined plane: Bagnold scaling and rheology. Physical Review E, 64(5), 051302. +:link(Silbert2001) +[(Silbert, 2001)] Silbert, L. E., Ertas, D., Grest, G. S., Halsey, T. C., Levine, D., & Plimpton, S. J. (2001). +Granular flow down an inclined plane: Bagnold scaling and rheology. Physical Review E, 64(5), 051302. - :link(Kuhn2004) - [(Kuhn and Bagi, 2005)] Kuhn, M. R., & Bagi, K. (2004). Contact rolling and deformation in granular media. - International journal of solids and structures, 41(21), 5793-5820. +:link(Kuhn2004) +[(Kuhn and Bagi, 2005)] Kuhn, M. R., & Bagi, K. (2004). Contact rolling and deformation in granular media. +International journal of solids and structures, 41(21), 5793-5820. - :link(Wang2015) - [(Wang et al, 2015)] Wang, Y., Alonso-Marroquin, F., & Guo, W. W. (2015). - Rolling and sliding in 3-D discrete element models. Particuology, 23, 49-55. +:link(Wang2015) +[(Wang et al, 2015)] Wang, Y., Alonso-Marroquin, F., & Guo, W. W. (2015). +Rolling and sliding in 3-D discrete element models. Particuology, 23, 49-55. - :link(Thornton1991) - [(Thornton, 1991)] Thornton, C. (1991). Interparticle sliding in the presence of adhesion. - J. Phys. D: Appl. Phys. 24 1942 \ No newline at end of file +:link(Thornton1991) +[(Thornton, 1991)] Thornton, C. (1991). Interparticle sliding in the presence of adhesion. +J. Phys. D: Appl. Phys. 24 1942 From e0c935b52d9d0384cfa397b13b48e66acf02f721 Mon Sep 17 00:00:00 2001 From: "Dan S. Bolintineanu" Date: Mon, 11 Mar 2019 14:28:18 -0600 Subject: [PATCH 26/44] Additional changes to pair_granular: -added mindlin and mindlin/rescale tangential model options -torque from tangential force is now applied at the same point on both contacting particles -updated doc page to reflect changes above --- doc/src/pair_granular.txt | 56 ++++++++++++++++++---- src/GRANULAR/pair_granular.cpp | 88 +++++++++++++++++++++++++--------- src/GRANULAR/pair_granular.h | 2 + 3 files changed, 116 insertions(+), 30 deletions(-) diff --git a/doc/src/pair_granular.txt b/doc/src/pair_granular.txt index dcc756201c..8db9567692 100644 --- a/doc/src/pair_granular.txt +++ b/doc/src/pair_granular.txt @@ -28,17 +28,17 @@ pair_style granular pair_coeff * * hooke 1000.0 50.0 tangential linear_nohistory 1.0 0.4 :pre pair_style granular -pair_coeff * * hertz 1000.0 50.0 tangential linear_history 800.0 1.0 0.4 :pre +pair_coeff * * hertz 1000.0 50.0 tangential mindlin 800.0 1.0 0.4 :pre pair_style granular pair_coeff * * hertz 1000.0 0.3 tangential linear_history 800.0 1.0 0.4 damping tsuji :pre pair_style granular -pair_coeff 1 1 jkr 1000.0 50.0 tangential linear_history 800.0 1.0 0.5 rolling sds 500.0 200.0 0.5 twisting marshall +pair_coeff 1 1 jkr 1000.0 50.0 tangential mindlin 800.0 1.0 0.5 rolling sds 500.0 200.0 0.5 twisting marshall pair_coeff 2 2 hertz 200.0 20.0 tangential linear_history 300.0 1.0 0.1 rolling sds 200.0 100.0 0.1 twisting marshall :pre pair_style granular -pair_coeff 1 1 hertz 1000.0 50.0 tangential linear_history 800.0 0.5 0.5 rolling sds 500.0 200.0 0.5 twisting marshall +pair_coeff 1 1 hertz 1000.0 50.0 tangential mindlin 800.0 0.5 0.5 rolling sds 500.0 200.0 0.5 twisting marshall pair_coeff 2 2 dmt 1000.0 50.0 0.3 10.0 tangential linear_history 800.0 0.5 0.1 roll sds 500.0 200.0 0.1 twisting marshall pair_coeff 1 2 dmt 1000.0 50.0 0.3 10.0 tangential linear_history 800.0 0.5 0.1 roll sds 500.0 200.0 0.1 twisting marshall :pre @@ -219,7 +219,9 @@ choice and associated parameters. Currently supported tangential model choices a expected parameters are as follows: {linear_nohistory} : \(x_\{\gamma,t\}\), \(\mu_s\) -{linear_history} : \(k_t\), \(x_\{\gamma,t\}\), \(\mu_s\) :ol +{linear_history} : \(k_t\), \(x_\{\gamma,t\}\), \(\mu_s\) +{mindlin} : \(k_t\), \(x_\{\gamma,t\}\), \(\mu_s\) +{mindlin_rescale} : \(k_t\), \(x_\{\gamma,t\}\), \(\mu_s\) :ol Here, \(x_\{\gamma,t\}\) is a dimensionless multiplier for the normal damping \(\eta_n\) that determines the magnitude of the @@ -273,6 +275,10 @@ F_\{n0\} = \|\mathbf\{F\}_ne + 2 F_\{pulloff\}\| Where \(F_\{pulloff\} = 3\pi \gamma R \) for {jkr}, and \(F_\{pulloff\} = 4\pi \gamma R \) for {dmt}. +The remaining tangential options all use accumulated tangential displacement (i.e. contact history). This +is discussed below in the context of the {linear_history} option, but the same treatment of the +accumulated displacement applies to the other options as well. + For {tangential linear_history}, the tangential force is given by: \begin\{equation\} @@ -320,17 +326,39 @@ equation 20 and related discussion): \end\{equation\} The tangential force is added to the total normal force (elastic plus damping) to produce the total force -on the particle. The tangential force also acts at the contact point to induce a torque on each -particle according to: +on the particle. The tangential force also acts at the contact point (defined as the center of the overlap region) +to induce a torque on each particle according to: \begin\{equation\} -\mathbf\{\tau\}_i = -R_i \mathbf\{n\} \times \mathbf\{F\}_t +\mathbf\{\tau\}_i = -(R_i - 0.5 \delta) \mathbf\{n\} \times \mathbf\{F\}_t \end\{equation\} \begin\{equation\} -\mathbf\{\tau\}_j = -R_j \mathbf\{n\} \times \mathbf\{F\}_t +\mathbf\{\tau\}_j = -(R_j - 0.5 \delta) \mathbf\{n\} \times \mathbf\{F\}_t \end\{equation\} +For {tangential mindlin}, the Mindlin no-slip solution is used, which differs from the {linear_history} +option by an additional factor of {a}, the radius of the contact region. The tangential force is given by: + +\begin\{equation\} +\mathbf\{F\}_t = -min(\mu_t F_\{n0\}, \|-k_t a \mathbf\{\xi\} + \mathbf\{F\}_\mathrm\{t,damp\}\|) \mathbf\{t\} +\end\{equation\} + +Here, {a} is the radius of the contact region, given by \(a = \delta R\) for all normal contact models, +except for {jkr}, where it is given implicitly by \(\delta = a^2/R - 2\sqrt\{\pi \gamma a/E\}\), +see discussion above. + +The {mindlin_rescale} option uses the same form as {mindlin}, but the magnitude of the tangential +displacement is re-scaled as the contact unloads, i.e. if \(a < a_\{t_n-1\}\): +\begin\{equation\} +\mathbf\{\xi\} = \mathbf\{xi_\{t_n-1\}\} \frac\{a\}\{a_\{t_n-1\}\} +\end\{equation\} + +This accounts for the fact that a decrease in the contact area upon unloading leads to the contact +being unable to support the previous tangential loading, and spurious energy is created +without the rescaling above ("Walton"_#WaltonPC). See also discussion in "Thornton et al, 2013"_#Thornton2013, +particularly equation 18(b) of that work and associated discussion. + :line The optional {rolling} keyword enables rolling friction, which resists pure rolling @@ -616,3 +644,15 @@ Rolling and sliding in 3-D discrete element models. Particuology, 23, 49-55. :link(Thornton1991) [(Thornton, 1991)] Thornton, C. (1991). Interparticle sliding in the presence of adhesion. J. Phys. D: Appl. Phys. 24 1942 + +:link(Mindlin1949) +[(Mindlin, 1949)] Mindlin, R. D. (1949). Compliance of elastic bodies in contact. +J. Appl. Mech., ASME 16, 259-268. + +:line(Thornton2013) +[(Thornton et al, 2013)] Thornton, C., Cummins, S. J., & Cleary, P. W. (2013). +An investigation of the comparative behaviour of alternative contact force models +during inelastic collisions. Powder Technology, 233, 30-46. + +:line(WaltonPC) +[(Otis R. Walton)] Walton, O.R., Personal Communication diff --git a/src/GRANULAR/pair_granular.cpp b/src/GRANULAR/pair_granular.cpp index caef852ab0..19633a96c2 100644 --- a/src/GRANULAR/pair_granular.cpp +++ b/src/GRANULAR/pair_granular.cpp @@ -52,7 +52,7 @@ using namespace MathConst; enum {HOOKE, HERTZ, HERTZ_MATERIAL, DMT, JKR}; enum {VELOCITY, VISCOELASTIC, TSUJI}; -enum {TANGENTIAL_NOHISTORY, TANGENTIAL_HISTORY, TANGENTIAL_MINDLIN}; +enum {TANGENTIAL_NOHISTORY, TANGENTIAL_HISTORY, TANGENTIAL_MINDLIN, TANGENTIAL_MINDLIN_RESCALE}; enum {TWIST_NONE, TWIST_SDS, TWIST_MARSHALL}; enum {ROLL_NONE, ROLL_SDS}; @@ -77,6 +77,8 @@ PairGranular::PairGranular(LAMMPS *lmp) : Pair(lmp) maxrad_dynamic = NULL; maxrad_frozen = NULL; + history_transfer_factors = NULL; + dt = update->dt; // set comm size needed by this Pair if used with fix rigid @@ -131,7 +133,7 @@ void PairGranular::compute(int eflag, int vflag) int i,j,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,fx,fy,fz,nx,ny,nz; double radi,radj,radsum,rsq,r,rinv; - double Reff, delta, dR, dR2; + double Reff, delta, dR, dR2, dist_to_contact; double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3; double wr1,wr2,wr3; @@ -397,16 +399,27 @@ void PairGranular::compute(int eflag, int vflag) damp_tangential = tangential_coeffs[itype][jtype][1]*damp_normal_prefactor; if (tangential_history){ - shrmag = sqrt(history[0]*history[0] + history[1]*history[1] + - history[2]*history[2]); - + if (tangential_model[itype][jtype] == TANGENTIAL_MINDLIN){ + k_tangential *= a; + } + else if (tangential_model[itype][jtype] == TANGENTIAL_MINDLIN_RESCALE){ + k_tangential *= a; + if (a < history[3]){ //On unloading, rescale the shear displacements + double factor = a/history[3]; + history[0] *= factor; + history[1] *= factor; + history[2] *= factor; + } + } // Rotate and update displacements. // See e.g. eq. 17 of Luding, Gran. Matter 2008, v10,p235 if (historyupdate) { rsht = history[0]*nx + history[1]*ny + history[2]*nz; if (fabs(rsht) < EPSILON) rsht = 0; if (rsht > 0){ - scalefac = shrmag/(shrmag - rsht); //if rhst == shrmag, contacting pair has rotated 90 deg. in one step, in which case you deserve a crash! + shrmag = sqrt(history[0]*history[0] + history[1]*history[1] + + history[2]*history[2]); + scalefac = shrmag/(shrmag - rsht); //if rsht == shrmag, contacting pair has rotated 90 deg. in one step, in which case you deserve a crash! history[0] -= rsht*nx; history[1] -= rsht*ny; history[2] -= rsht*nz; @@ -419,6 +432,7 @@ void PairGranular::compute(int eflag, int vflag) history[0] += vtr1*dt; history[1] += vtr2*dt; history[2] += vtr3*dt; + if (tangential_model[itype][jtype] == TANGENTIAL_MINDLIN_RESCALE) history[3] = a; } // tangential forces = history + tangential velocity damping @@ -430,6 +444,8 @@ void PairGranular::compute(int eflag, int vflag) Fscrit = tangential_coeffs[itype][jtype][2] * Fncrit; fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); if (fs > Fscrit) { + shrmag = sqrt(history[0]*history[0] + history[1]*history[1] + + history[2]*history[2]); if (shrmag != 0.0) { history[0] = -1.0/k_tangential*(Fscrit*fs1/fs + damp_tangential*vtr1); history[1] = -1.0/k_tangential*(Fscrit*fs2/fs + damp_tangential*vtr2); @@ -469,16 +485,13 @@ void PairGranular::compute(int eflag, int vflag) int rhist1 = rhist0 + 1; int rhist2 = rhist1 + 1; - // Rolling displacement - rollmag = sqrt(history[rhist0]*history[rhist0] + - history[rhist1]*history[rhist1] + - history[rhist2]*history[rhist2]); - rolldotn = history[rhist0]*nx + history[rhist1]*ny + history[rhist2]*nz; - if (historyupdate){ if (fabs(rolldotn) < EPSILON) rolldotn = 0; if (rolldotn > 0){ //Rotate into tangential plane + rollmag = sqrt(history[rhist0]*history[rhist0] + + history[rhist1]*history[rhist1] + + history[rhist2]*history[rhist2]); scalefac = rollmag/(rollmag - rolldotn); history[rhist0] -= rolldotn*nx; history[rhist1] -= rolldotn*ny; @@ -504,6 +517,9 @@ void PairGranular::compute(int eflag, int vflag) fr = sqrt(fr1*fr1 + fr2*fr2 + fr3*fr3); if (fr > Frcrit) { + rollmag = sqrt(history[rhist0]*history[rhist0] + + history[rhist1]*history[rhist1] + + history[rhist2]*history[rhist2]); if (rollmag != 0.0) { history[rhist0] = -1.0/k_roll*(Frcrit*fr1/fr + damp_roll*vrl1); history[rhist1] = -1.0/k_roll*(Frcrit*fr2/fr + damp_roll*vrl2); @@ -555,9 +571,10 @@ void PairGranular::compute(int eflag, int vflag) tor2 = nz*fs1 - nx*fs3; tor3 = nx*fs2 - ny*fs1; - torque[i][0] -= radi*tor1; - torque[i][1] -= radi*tor2; - torque[i][2] -= radi*tor3; + dist_to_contact = radi-0.5*delta; + torque[i][0] -= dist_to_contact*tor1; + torque[i][1] -= dist_to_contact*tor2; + torque[i][2] -= dist_to_contact*tor3; if (twist_model[itype][jtype] != TWIST_NONE){ tortwist1 = magtortwist * nx; @@ -584,9 +601,10 @@ void PairGranular::compute(int eflag, int vflag) f[j][1] -= fy; f[j][2] -= fz; - torque[j][0] -= radj*tor1; - torque[j][1] -= radj*tor2; - torque[j][2] -= radj*tor3; + dist_to_contact = radj-0.5*delta; + torque[j][0] -= dist_to_contact*tor1; + torque[j][1] -= dist_to_contact*tor2; + torque[j][2] -= dist_to_contact*tor3; if (twist_model[itype][jtype] != TWIST_NONE){ torque[j][0] -= tortwist1; @@ -762,9 +780,13 @@ void PairGranular::coeff(int narg, char **arg) tangential_coeffs_one[2] = force->numeric(FLERR,arg[iarg+3]); //friction coeff. iarg += 4; } - else if (strcmp(arg[iarg+1], "linear_history") == 0){ + else if ((strcmp(arg[iarg+1], "linear_history") == 0) || + (strcmp(arg[iarg+1], "mindlin") == 0) || + (strcmp(arg[iarg+1], "mindlin_rescale") == 0)){ if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for tangential model"); - tangential_model_one = TANGENTIAL_HISTORY; + if (strcmp(arg[iarg+1], "linear_history") == 0) tangential_model_one = TANGENTIAL_HISTORY; + else if (strcmp(arg[iarg+1], "mindlin") == 0) tangential_model_one = TANGENTIAL_MINDLIN; + else if (strcmp(arg[iarg+1], "mindlin_rescale") == 0) tangential_model_one = TANGENTIAL_MINDLIN_RESCALE; tangential_history = 1; tangential_coeffs_one[0] = force->numeric(FLERR,arg[iarg+2]); //kt tangential_coeffs_one[1] = force->numeric(FLERR,arg[iarg+3]); //gammat @@ -896,11 +918,11 @@ void PairGranular::init_style() error->all(FLERR,"Pair granular requires ghost atoms store velocity"); // Determine whether we need a granular neigh list, how large it needs to be - use_history = tangential_history || roll_history || twist_history; + use_history = normal_history || tangential_history || roll_history || twist_history; //For JKR, will need fix/neigh/history to keep track of touch arrays for (int i = 1; i <= atom->ntypes; i++) - for (int j = 1; j <= atom->ntypes; j++) + for (int j = i; j <= atom->ntypes; j++) if (normal_model[i][j] == JKR) use_history = 1; size_history = 3*tangential_history + 3*roll_history + twist_history; @@ -920,6 +942,19 @@ void PairGranular::init_style() else twist_history_index = 0; } } + for (int i = 1; i <= atom->ntypes; i++) + for (int j = i; j <= atom->ntypes; j++) + if (tangential_model[i][j] == TANGENTIAL_MINDLIN_RESCALE){ + size_history += 1; + roll_history_index += 1; + twist_history_index += 1; + nondefault_history_transfer = 1; + history_transfer_factors = new int[size_history]; + for (int ii = 0; ii < size_history; ++ii) + history_transfer_factors[ii] = -1; + history_transfer_factors[3] = 1; + break; + } int irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->size = 1; @@ -1612,3 +1647,12 @@ double PairGranular::pulloff_distance(double radi, double radj, int itype, int j return a*a/Reff - 2*sqrt(M_PI*coh*a/E); } +/* ---------------------------------------------------------------------- + Transfer history during fix/neigh/history exchange + Only needed if any history entries i-j are not just negative of j-i entries +------------------------------------------------------------------------- */ +void PairGranular::transfer_history(double* source, double* target){ + for (int i = 0; i < size_history; i++) + target[i] = history_transfer_factors[i]*source[i]; +} + diff --git a/src/GRANULAR/pair_granular.h b/src/GRANULAR/pair_granular.h index 7bce3831f1..ebddc17ade 100644 --- a/src/GRANULAR/pair_granular.h +++ b/src/GRANULAR/pair_granular.h @@ -61,9 +61,11 @@ public: int nmax; // allocated size of mass_rigid void allocate(); + void transfer_history(double*, double*); private: int size_history; + int *history_transfer_factors; //Model choices int **normal_model, **damping_model; From 2cc35ee7771f9fed8be9cba1521fd198485bad04 Mon Sep 17 00:00:00 2001 From: "Dan S. Bolintineanu" Date: Wed, 13 Mar 2019 00:42:08 -0600 Subject: [PATCH 27/44] A few additional enhancements to pair granular and fix wall granular option: - NULL option for tangential stiffness, to set it based on shear modulus - calculation of effective shear moduli from elastic moduli and Poisson's ratio - updates to doc page example syntax --- doc/src/fix_wall_gran.txt | 4 +-- doc/src/pair_granular.txt | 43 ++++++++++++++---------- src/GRANULAR/fix_wall_gran.cpp | 43 +++++++++++++++++++++--- src/GRANULAR/pair_granular.cpp | 60 ++++++++++++++++++++++++++-------- 4 files changed, 113 insertions(+), 37 deletions(-) diff --git a/doc/src/fix_wall_gran.txt b/doc/src/fix_wall_gran.txt index 096bec4920..e8c2247594 100644 --- a/doc/src/fix_wall_gran.txt +++ b/doc/src/fix_wall_gran.txt @@ -49,8 +49,8 @@ fix 1 all wall/gran hooke 200000.0 NULL 50.0 NULL 0.5 0 xplane -10.0 10.0 fix 1 all wall/gran hooke/history 200000.0 NULL 50.0 NULL 0.5 0 zplane 0.0 NULL fix 2 all wall/gran hooke 100000.0 20000.0 50.0 30.0 0.5 1 zcylinder 15.0 wiggle z 3.0 2.0 fix 3 all wall/gran granular hooke 1000.0 50.0 tangential linear_nohistory 1.0 0.4 zplane 0.0 NULL -fix 4 all wall/gran granular jkr 1000.0 50.0 tangential linear_history 800.0 1.0 0.5 rolling sds 500.0 200.0 0.5 twisting marshall zcylinder 15.0 wiggle z 3.0 2.0 -fix 5 all wall/gran granular dmt 1000.0 50.0 0.3 10.0 tangential linear_history 800.0 0.5 0.1 roll sds 500.0 200.0 0.1 twisting marshall zplane 0.0 NULL :pre +fix 4 all wall/gran granular jkr 1000.0 50.0 0.3 5.0 tangential mindlin 800.0 1.0 0.5 rolling sds 500.0 200.0 0.5 twisting marshall zcylinder 15.0 wiggle z 3.0 2.0 +fix 5 all wall/gran granular dmt 1000.0 50.0 0.3 10.0 tangential mindlin 800.0 0.5 0.1 roll sds 500.0 200.0 0.1 twisting marshall zplane 0.0 NULL :pre [Description:] diff --git a/doc/src/pair_granular.txt b/doc/src/pair_granular.txt index 8db9567692..7a58435a83 100644 --- a/doc/src/pair_granular.txt +++ b/doc/src/pair_granular.txt @@ -28,10 +28,10 @@ pair_style granular pair_coeff * * hooke 1000.0 50.0 tangential linear_nohistory 1.0 0.4 :pre pair_style granular -pair_coeff * * hertz 1000.0 50.0 tangential mindlin 800.0 1.0 0.4 :pre +pair_coeff * * hertz 1000.0 50.0 tangential mindlin NULL 1.0 0.4 :pre pair_style granular -pair_coeff * * hertz 1000.0 0.3 tangential linear_history 800.0 1.0 0.4 damping tsuji :pre +pair_coeff * * hertz/material 1e8 0.3 tangential mindlin_rescale NULL 1.0 0.4 damping tsuji :pre pair_style granular pair_coeff 1 1 jkr 1000.0 50.0 tangential mindlin 800.0 1.0 0.5 rolling sds 500.0 200.0 0.5 twisting marshall @@ -39,8 +39,8 @@ pair_coeff 2 2 hertz 200.0 20.0 tangential linear_history 300.0 1.0 0.1 rolling pair_style granular pair_coeff 1 1 hertz 1000.0 50.0 tangential mindlin 800.0 0.5 0.5 rolling sds 500.0 200.0 0.5 twisting marshall -pair_coeff 2 2 dmt 1000.0 50.0 0.3 10.0 tangential linear_history 800.0 0.5 0.1 roll sds 500.0 200.0 0.1 twisting marshall -pair_coeff 1 2 dmt 1000.0 50.0 0.3 10.0 tangential linear_history 800.0 0.5 0.1 roll sds 500.0 200.0 0.1 twisting marshall :pre +pair_coeff 2 2 dmt 1000.0 50.0 0.3 10.0 tangential mindlin 800.0 0.5 0.1 roll sds 500.0 200.0 0.1 twisting marshall +pair_coeff 1 2 dmt 1000.0 50.0 0.3 10.0 tangential mindlin 800.0 0.5 0.1 roll sds 500.0 200.0 0.1 twisting marshall :pre [Description:] @@ -220,8 +220,8 @@ expected parameters are as follows: {linear_nohistory} : \(x_\{\gamma,t\}\), \(\mu_s\) {linear_history} : \(k_t\), \(x_\{\gamma,t\}\), \(\mu_s\) -{mindlin} : \(k_t\), \(x_\{\gamma,t\}\), \(\mu_s\) -{mindlin_rescale} : \(k_t\), \(x_\{\gamma,t\}\), \(\mu_s\) :ol +{mindlin} : \(k_t\) or NULL, \(x_\{\gamma,t\}\), \(\mu_s\) +{mindlin_rescale} : \(k_t\) or NULL, \(x_\{\gamma,t\}\), \(\mu_s\) :ol Here, \(x_\{\gamma,t\}\) is a dimensionless multiplier for the normal damping \(\eta_n\) that determines the magnitude of the @@ -337,7 +337,7 @@ to induce a torque on each particle according to: \mathbf\{\tau\}_j = -(R_j - 0.5 \delta) \mathbf\{n\} \times \mathbf\{F\}_t \end\{equation\} -For {tangential mindlin}, the Mindlin no-slip solution is used, which differs from the {linear_history} +For {tangential mindlin}, the "Mindlin"_#Mindlin1949 no-slip solution is used, which differs from the {linear_history} option by an additional factor of {a}, the radius of the contact region. The tangential force is given by: \begin\{equation\} @@ -346,18 +346,27 @@ option by an additional factor of {a}, the radius of the contact region. The tan Here, {a} is the radius of the contact region, given by \(a = \delta R\) for all normal contact models, except for {jkr}, where it is given implicitly by \(\delta = a^2/R - 2\sqrt\{\pi \gamma a/E\}\), -see discussion above. - -The {mindlin_rescale} option uses the same form as {mindlin}, but the magnitude of the tangential -displacement is re-scaled as the contact unloads, i.e. if \(a < a_\{t_n-1\}\): +see discussion above. To match the Mindlin solution, one should set \(k_t = 8G\), where +\(G\) is the shear modulus, related to Young's modulus \(E\) by \(G = E/(2(1+\nu))\), where \(\nu\) +is Poisson's ratio. This can also be achieved by specifying {NULL} for \(k_t\), in which case +a normal contact model that specifies material parameters \(E\) and \(\nu\) is required (e.g. {hertz/material}, +{dmt} or {jkr}). In this case, mixing of shear moduli for different particle types {i} and {j} is done according +to: \begin\{equation\} -\mathbf\{\xi\} = \mathbf\{xi_\{t_n-1\}\} \frac\{a\}\{a_\{t_n-1\}\} +1/G = 2(2-\nu_i)(1+\nu_i)/E_i + 2(2-\nu_j)(1+\nu_j)/E_j \end\{equation\} -This accounts for the fact that a decrease in the contact area upon unloading leads to the contact +The {mindlin_rescale} option uses the same form as {mindlin}, but the magnitude of the tangential +displacement is re-scaled as the contact unloads, i.e. if \(a < a_\{t_\{n-1\}\}\): +\begin\{equation\} +\mathbf\{\xi\} = \mathbf\{\xi_\{t_\{n-1\}\}\} \frac\{a\}\{a_\{t_\{n-1\}\}\} +\end\{equation\} + +Here, \(t_\{n-1\}\) indicates the value at the previous time step. This rescaling +accounts for the fact that a decrease in the contact area upon unloading leads to the contact being unable to support the previous tangential loading, and spurious energy is created -without the rescaling above ("Walton"_#WaltonPC). See also discussion in "Thornton et al, 2013"_#Thornton2013, -particularly equation 18(b) of that work and associated discussion. +without the rescaling above ("Walton"_#WaltonPC ). See also discussion in "Thornton et al, 2013"_#Thornton2013 +, particularly equation 18(b) of that work and associated discussion. :line @@ -649,10 +658,10 @@ J. Phys. D: Appl. Phys. 24 1942 [(Mindlin, 1949)] Mindlin, R. D. (1949). Compliance of elastic bodies in contact. J. Appl. Mech., ASME 16, 259-268. -:line(Thornton2013) +:link(Thornton2013) [(Thornton et al, 2013)] Thornton, C., Cummins, S. J., & Cleary, P. W. (2013). An investigation of the comparative behaviour of alternative contact force models during inelastic collisions. Powder Technology, 233, 30-46. -:line(WaltonPC) +:link(WaltonPC) [(Otis R. Walton)] Walton, O.R., Personal Communication diff --git a/src/GRANULAR/fix_wall_gran.cpp b/src/GRANULAR/fix_wall_gran.cpp index 3b959e1a01..3a929771e9 100644 --- a/src/GRANULAR/fix_wall_gran.cpp +++ b/src/GRANULAR/fix_wall_gran.cpp @@ -54,7 +54,7 @@ enum{NONE,CONSTANT,EQUAL}; enum {NORMAL_HOOKE, NORMAL_HERTZ, HERTZ_MATERIAL, DMT, JKR}; enum {VELOCITY, VISCOELASTIC, TSUJI}; -enum {TANGENTIAL_NOHISTORY, TANGENTIAL_HISTORY, TANGENTIAL_MINDLIN}; +enum {TANGENTIAL_NOHISTORY, TANGENTIAL_HISTORY, TANGENTIAL_MINDLIN, TANGENTIAL_MINDLIN_RESCALE}; enum {TWIST_NONE, TWIST_SDS, TWIST_MARSHALL}; enum {ROLL_NONE, ROLL_SDS}; @@ -198,11 +198,24 @@ FixWallGran::FixWallGran(LAMMPS *lmp, int narg, char **arg) : tangential_coeffs[2] = force->numeric(FLERR,arg[iarg+3]); //friction coeff. iarg += 4; } - else if (strcmp(arg[iarg+1], "linear_history") == 0){ + else if ((strcmp(arg[iarg+1], "linear_history") == 0) || + (strcmp(arg[iarg+1], "mindlin") == 0) || + (strcmp(arg[iarg+1], "mindlin_rescale") == 0)){ if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for tangential model"); - tangential_model = TANGENTIAL_HISTORY; + if (strcmp(arg[iarg+1], "linear_history") == 0) tangential_model = TANGENTIAL_HISTORY; + else if (strcmp(arg[iarg+1], "mindlin") == 0) tangential_model = TANGENTIAL_MINDLIN; + else if (strcmp(arg[iarg+1], "mindlin_rescale") == 0) tangential_model = TANGENTIAL_MINDLIN_RESCALE; + if ((tangential_model == TANGENTIAL_MINDLIN || tangential_model == TANGENTIAL_MINDLIN_RESCALE) && + (strcmp(arg[iarg+2], "NULL") == 0)){ + if (normal_model == NORMAL_HERTZ || normal_model == NORMAL_HOOKE){ + error->all(FLERR, "NULL setting for Mindlin tangential stiffness requires a normal contact model that specifies material properties"); + } + tangential_coeffs[0] = 4*(2-poiss)*(1+poiss)/Emod; + } + else{ + tangential_coeffs[0] = force->numeric(FLERR,arg[iarg+2]); //kt + } tangential_history = 1; - tangential_coeffs[0] = force->numeric(FLERR,arg[iarg+2]); //kt tangential_coeffs[1] = force->numeric(FLERR,arg[iarg+3]); //gammat tangential_coeffs[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. iarg += 5; @@ -265,7 +278,9 @@ FixWallGran::FixWallGran(LAMMPS *lmp, int narg, char **arg) : error->all(FLERR, "Illegal fix wall/gran command"); } } - size_history = (normal_model == JKR) + 3*tangential_history + 3*roll_history + twist_history; + size_history = 3*tangential_history + 3*roll_history + twist_history; + if (normal_model == JKR) size_history += 1; + if (tangential_model == TANGENTIAL_MINDLIN_RESCALE) size_history += 1; } // wallstyle args @@ -466,6 +481,10 @@ void FixWallGran::init() roll_history_index += 1; twist_history_index += 1; } + if (tangential_model == TANGENTIAL_MINDLIN_RESCALE){ + roll_history_index += 1; + twist_history_index += 1; + } if (damping_model == TSUJI){ double cor = normal_coeffs[1]; @@ -473,6 +492,8 @@ void FixWallGran::init() 27.467*pow(cor,4)-18.022*pow(cor,5)+ 4.8218*pow(cor,6); } + + } /* ---------------------------------------------------------------------- */ @@ -1177,6 +1198,18 @@ void FixWallGran::granular(double rsq, double dx, double dy, double dz, int thist2 = thist1 + 1; if (tangential_history){ + if (tangential_model == TANGENTIAL_MINDLIN){ + k_tangential *= a; + } + else if (tangential_model == TANGENTIAL_MINDLIN_RESCALE){ + k_tangential *= a; + if (a < history[3]){ //On unloading, rescale the shear displacements + double factor = a/history[thist2+1]; + history[thist0] *= factor; + history[thist1] *= factor; + history[thist2] *= factor; + } + } shrmag = sqrt(history[thist0]*history[thist0] + history[thist1]*history[thist1] + history[thist2]*history[thist2]); diff --git a/src/GRANULAR/pair_granular.cpp b/src/GRANULAR/pair_granular.cpp index 19633a96c2..97cf02676f 100644 --- a/src/GRANULAR/pair_granular.cpp +++ b/src/GRANULAR/pair_granular.cpp @@ -211,8 +211,10 @@ void PairGranular::compute(int eflag, int vflag) ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; - firsttouch = fix_history->firstflag; - firsthistory = fix_history->firstvalue; + if (use_history){ + firsttouch = fix_history->firstflag; + firsthistory = fix_history->firstvalue; + } for (ii = 0; ii < inum; ii++) { i = ilist[ii]; @@ -222,8 +224,10 @@ void PairGranular::compute(int eflag, int vflag) ztmp = x[i][2]; itype = type[i]; radi = radius[i]; - touch = firsttouch[i]; - allhistory = firsthistory[i]; + if (use_history){ + touch = firsttouch[i]; + allhistory = firsthistory[i]; + } jlist = firstneigh[i]; jnum = numneigh[i]; @@ -263,9 +267,11 @@ void PairGranular::compute(int eflag, int vflag) if (!touchflag){ // unset non-touching neighbors - touch[jj] = 0; - history = &allhistory[size_history*jj]; - for (int k = 0; k < size_history; k++) history[k] = 0.0; + if (use_history){ + touch[jj] = 0; + history = &allhistory[size_history*jj]; + for (int k = 0; k < size_history; k++) history[k] = 0.0; + } } else{ r = sqrt(rsq); @@ -788,7 +794,16 @@ void PairGranular::coeff(int narg, char **arg) else if (strcmp(arg[iarg+1], "mindlin") == 0) tangential_model_one = TANGENTIAL_MINDLIN; else if (strcmp(arg[iarg+1], "mindlin_rescale") == 0) tangential_model_one = TANGENTIAL_MINDLIN_RESCALE; tangential_history = 1; - tangential_coeffs_one[0] = force->numeric(FLERR,arg[iarg+2]); //kt + if ((tangential_model_one == TANGENTIAL_MINDLIN || tangential_model_one == TANGENTIAL_MINDLIN_RESCALE) && + (strcmp(arg[iarg+2], "NULL") == 0)){ + if (normal_model_one == HERTZ || normal_model_one == HOOKE){ + error->all(FLERR, "NULL setting for Mindlin tangential stiffness requires a normal contact model that specifies material properties"); + } + tangential_coeffs_one[0] = -1; + } + else{ + tangential_coeffs_one[0] = force->numeric(FLERR,arg[iarg+2]); //kt + } tangential_coeffs_one[1] = force->numeric(FLERR,arg[iarg+3]); //gammat tangential_coeffs_one[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. iarg += 5; @@ -879,7 +894,13 @@ void PairGranular::coeff(int narg, char **arg) damping_model[i][j] = damping_model[j][i] = damping_model_one; tangential_model[i][j] = tangential_model[j][i] = tangential_model_one; - for (int k = 0; k < 3; k++) + if (tangential_coeffs_one[0] == -1){ + tangential_coeffs[i][j][0] = tangential_coeffs[j][i][0] = 8*mix_stiffnessG(Emod[i][j], Emod[i][j], poiss[i][j], poiss[i][j]); + } + else{ + tangential_coeffs[i][j][0] = tangential_coeffs[j][i][0] = tangential_coeffs_one[0]; + } + for (int k = 1; k < 3; k++) tangential_coeffs[i][j][k] = tangential_coeffs[j][i][k] = tangential_coeffs_one[k]; roll_model[i][j] = roll_model[j][i] = roll_model_one; @@ -1276,7 +1297,7 @@ double PairGranular::single(int i, int j, int itype, int jtype, touchflag = (rsq <= radsum*radsum); } - if (touchflag){ + if (!touchflag){ fforce = 0.0; for (int m = 0; m < single_extra; m++) svector[m] = 0.0; return 0.0; @@ -1373,8 +1394,8 @@ double PairGranular::single(int i, int j, int itype, int jtype, } else{ knfac = E; - a = sqrt(dR); Fne = knfac*delta; + a = sqrt(dR); if (normal_model[itype][jtype] != HOOKE){ Fne *= a; knfac *= a; @@ -1451,6 +1472,19 @@ double PairGranular::single(int i, int j, int itype, int jtype, damp_tangential = tangential_coeffs[itype][jtype][1]*damp_normal_prefactor; if (tangential_history){ + if (tangential_model[itype][jtype] == TANGENTIAL_MINDLIN){ + k_tangential *= a; + } + else if (tangential_model[itype][jtype] == TANGENTIAL_MINDLIN_RESCALE){ + k_tangential *= a; + if (a < history[3]){ //On unloading, rescale the shear displacements + double factor = a/history[3]; + history[0] *= factor; + history[1] *= factor; + history[2] *= factor; + } + } + shrmag = sqrt(history[0]*history[0] + history[1]*history[1] + history[2]*history[2]); @@ -1617,9 +1651,9 @@ double PairGranular::mix_stiffnessE(double Eii, double Ejj, double poisii, doubl mixing of shear modulus (G) ------------------------------------------------------------------------ */ -double PairGranular::mix_stiffnessG(double Gii, double Gjj, double poisii, double poisjj) +double PairGranular::mix_stiffnessG(double Eii, double Ejj, double poisii, double poisjj) { - return 1/((2.0 -poisii)/Gii+(2.0-poisjj)/Gjj); + return 1/((2*(2-poisii)*(1+poisii)/Eii) + (2*(2-poisjj)*(1+poisjj)/Ejj)); } /* ---------------------------------------------------------------------- From 3abfce01caab080498564eaa99b093af04bfc57f Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 15 Mar 2019 14:06:03 -0400 Subject: [PATCH 28/44] remove diverged fix wall/gran/omp --- src/Purge.list | 3 + src/USER-OMP/fix_wall_gran_omp.cpp | 186 ----------------------------- src/USER-OMP/fix_wall_gran_omp.h | 38 ------ 3 files changed, 3 insertions(+), 224 deletions(-) delete mode 100644 src/USER-OMP/fix_wall_gran_omp.cpp delete mode 100644 src/USER-OMP/fix_wall_gran_omp.h diff --git a/src/Purge.list b/src/Purge.list index 6cfc580c25..430f842d7c 100644 --- a/src/Purge.list +++ b/src/Purge.list @@ -24,6 +24,9 @@ style_nstencil.h style_ntopo.h # other auto-generated files lmpinstalledpkgs.h +# removed on 15 March 2019 +fix_wall_gran_omp.h +fix_wall_gran_omp.cpp # renamed on 25 September 2018 compute_smd_triangle_mesh_vertices.h compute_smd_triangle_mesh_vertices.cpp diff --git a/src/USER-OMP/fix_wall_gran_omp.cpp b/src/USER-OMP/fix_wall_gran_omp.cpp deleted file mode 100644 index d45e748b6a..0000000000 --- a/src/USER-OMP/fix_wall_gran_omp.cpp +++ /dev/null @@ -1,186 +0,0 @@ -/* ---------------------------------------------------------------------- - LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator - http://lammps.sandia.gov, Sandia National Laboratories - Steve Plimpton, sjplimp@sandia.gov - - Copyright (2003) Sandia Corporation. Under the terms of Contract - DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains - certain rights in this software. This software is distributed under - the GNU General Public License. - - See the README file in the top-level LAMMPS directory. -------------------------------------------------------------------------- */ - -/* ---------------------------------------------------------------------- - Contributing author: Axel Kohlmeyer (Temple U) -------------------------------------------------------------------------- */ - -#include -#include "fix_wall_gran_omp.h" -#include "atom.h" -#include "memory.h" -#include "neighbor.h" -#include "update.h" - -using namespace LAMMPS_NS; -using namespace FixConst; - -enum{XPLANE=0,YPLANE=1,ZPLANE=2,ZCYLINDER,REGION}; // XYZ PLANE need to be 0,1,2 -enum{HOOKE,HOOKE_HISTORY,HERTZ_HISTORY,BONDED_HISTORY}; - -#define BIG 1.0e20 - -/* ---------------------------------------------------------------------- */ - -FixWallGranOMP::FixWallGranOMP(LAMMPS *lmp, int narg, char **arg) : - FixWallGran(lmp, narg, arg) { } - -/* ---------------------------------------------------------------------- */ - -void FixWallGranOMP::post_force(int vflag) -{ - double vwall[3]; - - // if just reneighbored: - // update rigid body masses for owned atoms if using FixRigid - // body[i] = which body atom I is in, -1 if none - // mass_body = mass of each rigid body - - if (neighbor->ago == 0 && fix_rigid) { - int tmp; - const int * const body = (const int * const) fix_rigid->extract("body",tmp); - double *mass_body = (double *) fix_rigid->extract("masstotal",tmp); - if (atom->nmax > nmax) { - memory->destroy(mass_rigid); - nmax = atom->nmax; - memory->create(mass_rigid,nmax,"wall/gran:mass_rigid"); - } - const int nlocal = atom->nlocal; - for (int i = 0; i < nlocal; i++) { - if (body[i] >= 0) mass_rigid[i] = mass_body[body[i]]; - else mass_rigid[i] = 0.0; - } - } - - // set position of wall to initial settings and velocity to 0.0 - // if wiggle or shear, set wall position and velocity accordingly - - double wlo = lo; - double whi = hi; - vwall[0] = vwall[1] = vwall[2] = 0.0; - if (wiggle) { - double arg = omega * (update->ntimestep - time_origin) * dt; - if (wallstyle == axis) { - wlo = lo + amplitude - amplitude*cos(arg); - whi = hi + amplitude - amplitude*cos(arg); - } - vwall[axis] = amplitude*omega*sin(arg); - } else if (wshear) vwall[axis] = vshear; - - // loop over all my atoms - // rsq = distance from wall - // dx,dy,dz = signed distance from wall - // for rotating cylinder, reset vwall based on particle position - // skip atom if not close enough to wall - // if wall was set to NULL, it's skipped since lo/hi are infinity - // compute force and torque on atom if close enough to wall - // via wall potential matched to pair potential - // set shear if pair potential stores history - - double * const * const x = atom->x; - double * const * const v = atom->v; - double * const * const f = atom->f; - double * const * const omega = atom->omega; - double * const * const torque = atom->torque; - double * const radius = atom->radius; - double * const rmass = atom->rmass; - const int * const mask = atom->mask; - const int nlocal = atom->nlocal; - - shearupdate = (update->setupflag) ? 0 : 1; - - int i; -#if defined(_OPENMP) -#pragma omp parallel for private(i) default(none) firstprivate(vwall,wlo,whi) -#endif - for (i = 0; i < nlocal; i++) { - - if (mask[i] & groupbit) { - double dx,dy,dz,del1,del2,delxy,delr,rsq; - double rwall = 0.0; - - dx = dy = dz = 0.0; - - if (wallstyle == XPLANE) { - del1 = x[i][0] - wlo; - del2 = whi - x[i][0]; - if (del1 < del2) dx = del1; - else dx = -del2; - } else if (wallstyle == YPLANE) { - del1 = x[i][1] - wlo; - del2 = whi - x[i][1]; - if (del1 < del2) dy = del1; - else dy = -del2; - } else if (wallstyle == ZPLANE) { - del1 = x[i][2] - wlo; - del2 = whi - x[i][2]; - if (del1 < del2) dz = del1; - else dz = -del2; - } else if (wallstyle == ZCYLINDER) { - delxy = sqrt(x[i][0]*x[i][0] + x[i][1]*x[i][1]); - delr = cylradius - delxy; - if (delr > radius[i]) { - dz = cylradius; - rwall = 0.0; - } else { - dx = -delr/delxy * x[i][0]; - dy = -delr/delxy * x[i][1]; - rwall = (delxy < cylradius) ? -2*cylradius : 2*cylradius; - if (wshear && axis != 2) { - vwall[0] += vshear * x[i][1]/delxy; - vwall[1] += -vshear * x[i][0]/delxy; - vwall[2] = 0.0; - } - } - } - - rsq = dx*dx + dy*dy + dz*dz; - - if (rsq > radius[i]*radius[i]) { - if (history) - for (int j = 0; j < sheardim; j++) - shearone[i][j] = 0.0; - - } else { - - // meff = effective mass of sphere - // if I is part of rigid body, use body mass - - double meff = rmass[i]; - if (fix_rigid && mass_rigid[i] > 0.0) meff = mass_rigid[i]; - - // invoke sphere/wall interaction - - if (pairstyle == HOOKE) - hooke(rsq,dx,dy,dz,vwall,v[i],f[i], - omega[i],torque[i],radius[i],meff); - else if (pairstyle == HOOKE_HISTORY) - hooke_history(rsq,dx,dy,dz,vwall,v[i],f[i], - omega[i],torque[i],radius[i],meff,shearone[i]); - else if (pairstyle == HERTZ_HISTORY) - hertz_history(rsq,dx,dy,dz,vwall,rwall,v[i],f[i], - omega[i],torque[i],radius[i],meff,shearone[i]); - else if (pairstyle == BONDED_HISTORY) - bonded_history(rsq,dx,dy,dz,vwall,rwall,v[i],f[i], - omega[i],torque[i],radius[i],meff,shearone[i]); - } - } - } -} - -/* ---------------------------------------------------------------------- */ - -void FixWallGranOMP::post_force_respa(int vflag, int ilevel, int iloop) -{ - if (ilevel == nlevels_respa-1) post_force(vflag); -} diff --git a/src/USER-OMP/fix_wall_gran_omp.h b/src/USER-OMP/fix_wall_gran_omp.h deleted file mode 100644 index cd26a7b40a..0000000000 --- a/src/USER-OMP/fix_wall_gran_omp.h +++ /dev/null @@ -1,38 +0,0 @@ -/* -*- 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. -------------------------------------------------------------------------- */ - -#ifdef FIX_CLASS - -FixStyle(wall/gran/omp,FixWallGranOMP) - -#else - -#ifndef LMP_FIX_WALL_GRAN_OMP_H -#define LMP_FIX_WALL_GRAN_OMP_H - -#include "fix_wall_gran.h" - -namespace LAMMPS_NS { - -class FixWallGranOMP : public FixWallGran { - - public: - FixWallGranOMP(class LAMMPS *, int, char **); - virtual void post_force(int); - virtual void post_force_respa(int, int, int); -}; - -} - -#endif -#endif From 3f0f2383b460d219bdadb36773b9d70f6097f2ea Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 15 Mar 2019 14:18:04 -0400 Subject: [PATCH 29/44] fix spelling and record false positives --- doc/src/pair_granular.txt | 21 ++++++++++----------- doc/utils/sphinx-config/false_positives.txt | 19 +++++++++++++++++++ 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/doc/src/pair_granular.txt b/doc/src/pair_granular.txt index 7a58435a83..5854a8faf6 100644 --- a/doc/src/pair_granular.txt +++ b/doc/src/pair_granular.txt @@ -111,8 +111,7 @@ For the {hertz/material} model, the force is given by: Here, \(E_\{eff\} = E = \left(\frac\{1-\nu_i^2\}\{E_i\} + \frac\{1-\nu_j^2\}\{E_j\}\right)^\{-1\}\) is the effective Young's modulus, with \(\nu_i, \nu_j \) the Poisson ratios of the particles of types {i} and {j}. Note that -if the elastic and shear moduli of the -two particles are the same, the {hertz/material} +if the elastic modulus and the shear modulus of the two particles are the same, the {hertz/material} model is equivalent to the {hertz} model with \(k_N = 4/3 E_\{eff\}\) The {dmt} model corresponds to the "(Derjaguin-Muller-Toporov)"_#DMT1975 cohesive model, @@ -188,7 +187,7 @@ for all models except {jkr}, for which it is given implicitly according to \(del In this case, \eta_\{n0\}\ is in units of 1/({time}*{distance}). The {tsuji} model is based on the work of "(Tsuji et al)"_#Tsuji1992. Here, the -damping coefficient specified as part of the normal model is intepreted +damping coefficient specified as part of the normal model is interpreted as a restitution coefficient \(e\). The damping constant \(\eta_n\) is given by: \begin\{equation\} @@ -242,7 +241,7 @@ The tangential damping force \(\mathbf\{F\}_\mathrm\{t,damp\}\) is given by: \mathbf\{F\}_\mathrm\{t,damp\} = -\eta_t \mathbf\{v\}_\{t,rel\} \end\{equation\} -The tangetial damping prefactor \(\eta_t\) is calculated by scaling the normal damping \(\eta_n\) (see above): +The tangential damping prefactor \(\eta_t\) is calculated by scaling the normal damping \(\eta_n\) (see above): \begin\{equation\} \eta_t = -x_\{\gamma,t\} \eta_n \end\{equation\} @@ -292,7 +291,7 @@ duration of the contact: \mathbf\{\xi\} = \int_\{t0\}^t \mathbf\{v\}_\{t,rel\}(\tau) \mathrm\{d\}\tau \end\{equation\} -This accumlated tangential displacement must be adjusted to account for changes +This accumulated tangential displacement must be adjusted to account for changes in the frame of reference of the contacting pair of particles during contact. This occurs due to the overall motion of the contacting particles in a rigid-body-like fashion during the duration of the contact. There are two modes of motion @@ -304,7 +303,7 @@ made by rotating the accumulated displacement into the plane that is tangential to the contact vector at each step, or equivalently removing any component of the tangential displacement that lies along \(\mathbf\{n\}\), and rescaling to preserve the magnitude. -This folllows the discussion in "Luding"_#Luding2008, see equation 17 and +This follows the discussion in "Luding"_#Luding2008, see equation 17 and relevant discussion in that work: \begin\{equation\} @@ -350,7 +349,7 @@ see discussion above. To match the Mindlin solution, one should set \(k_t = 8G\) \(G\) is the shear modulus, related to Young's modulus \(E\) by \(G = E/(2(1+\nu))\), where \(\nu\) is Poisson's ratio. This can also be achieved by specifying {NULL} for \(k_t\), in which case a normal contact model that specifies material parameters \(E\) and \(\nu\) is required (e.g. {hertz/material}, -{dmt} or {jkr}). In this case, mixing of shear moduli for different particle types {i} and {j} is done according +{dmt} or {jkr}). In this case, mixing of the shear modulus for different particle types {i} and {j} is done according to: \begin\{equation\} 1/G = 2(2-\nu_i)(1+\nu_i)/E_i + 2(2-\nu_j)(1+\nu_j)/E_j @@ -381,7 +380,7 @@ If the {rolling} keyword is not specified, the model defaults to {none}. For {rolling sds}, rolling friction is computed via a spring-dashpot-slider, using a 'pseudo-force' formulation, as detailed by "Luding"_#Luding2008. Unlike the formulation in "Marshall"_#Marshall2009, this allows for the required adjustment of -rolling displacement due to changes in the frame of referenece of the contacting pair. +rolling displacement due to changes in the frame of reference of the contacting pair. The rolling pseudo-force is computed analogously to the tangential force: \begin\{equation\} @@ -487,7 +486,7 @@ Finally, the twisting torque on each particle is given by: :line LAMMPS automatically sets pairwise cutoff values for {pair_style granular} based on particle radii (and in the case -of {jkr} pulloff distances). In the vast majority of situations, this is adequate. +of {jkr} pull-off distances). In the vast majority of situations, this is adequate. However, a cutoff value can optionally be appended to the {pair_style granular} command to specify a global cutoff (i.e. a cutoff for all atom types). Additionally, the optional {cutoff} keyword can be passed to the {pair_coeff} command, followed by a cutoff value. @@ -533,7 +532,7 @@ Mixing of coefficients is carried out using geometric averaging for most quantities, e.g. if friction coefficient for type 1-type 1 interactions is set to \(\mu_1\), and friction coefficient for type 2-type 2 interactions is set to \(\mu_2\), the friction coefficient for type1-type2 interactions -is computed as \(\sqrt\{\mu_1\mu_2\}\) (unless explictly specified to +is computed as \(\sqrt\{\mu_1\mu_2\}\) (unless explicitly specified to a different value by a {pair_coeff 1 2 ...} command. The exception to this is elastic modulus, only applicable to {hertz/material}, {dmt} and {jkr} normal contact models. In that case, the effective elastic modulus is computed as: @@ -542,7 +541,7 @@ contact models. In that case, the effective elastic modulus is computed as: E_\{eff,ij\} = \left(\frac\{1-\nu_i^2\}\{E_i\} + \frac\{1-\nu_j^2\}\{E_j\}\right)^\{-1\} \end\{equation\} -If the {i-j} coefficients \(E_\{ij\}\) and \(\nu_\{ij\}\) are explictly specified, +If the {i-j} coefficients \(E_\{ij\}\) and \(\nu_\{ij\}\) are explicitly specified, the effective modulus is computed as: \begin\{equation\} diff --git a/doc/utils/sphinx-config/false_positives.txt b/doc/utils/sphinx-config/false_positives.txt index 08e106f6d7..c55378826e 100644 --- a/doc/utils/sphinx-config/false_positives.txt +++ b/doc/utils/sphinx-config/false_positives.txt @@ -155,6 +155,8 @@ ba Babadi backcolor Baczewski +Bagi +Bagnold Bal balancer Balankura @@ -343,6 +345,7 @@ Cij cis civ clearstore +Cleary Clebsch clemson Clermont @@ -369,6 +372,7 @@ Coeff CoefficientN coeffs Coeffs +cohesionless Coker Colberg coleman @@ -442,6 +446,7 @@ cuda Cuda CUDA CuH +Cummins Curk customIDs cutbond @@ -485,6 +490,7 @@ darkturquoise darkviolet Das Dasgupta +dashpot dat datafile datums @@ -521,6 +527,7 @@ Dequidt der derekt Derjagin +Derjaguin Derlet Deserno Destree @@ -1065,6 +1072,7 @@ Hyoungki hyperdynamics hyperradius hyperspherical +hysteretic Ibanez ibar ibm @@ -1124,6 +1132,7 @@ interconvert interial interlayer intermolecular +Interparticle interstitials Intr intra @@ -1141,6 +1150,7 @@ IPython Isele isenthalpic ish +Ishida iso isodemic isoenergetic @@ -1430,6 +1440,7 @@ logfile logfreq logicals Lomdahl +Lond lookups Lookups LoopVar @@ -1444,6 +1455,7 @@ lsfftw ltbbmalloc lubricateU lucy +Luding Lussetti Lustig lwsock @@ -1482,6 +1494,7 @@ manybody MANYBODY Maras Marrink +Marroquin Marsaglia Marseille Martyna @@ -1493,6 +1506,7 @@ masstotal Masuhiro Matchett Materias +mathbf matlab matplotlib Mattox @@ -1580,6 +1594,7 @@ Mie Mikami Militzer Minary +Mindlin mincap mingw minima @@ -2260,6 +2275,7 @@ rg Rg Rhaphson rheological +rheology rhodo Rhodo rhodopsin @@ -2572,6 +2588,7 @@ Tait taitwater Tajkhorshid Tamaskovics +Tanaka tanh Tartakovsky taskset @@ -2659,6 +2676,7 @@ tokyo tol toolchain topologies +Toporov Torder torsions Tosi @@ -2703,6 +2721,7 @@ Tsrd Tstart tstat Tstop +Tsuji Tsuzuki tt Tt From 8845a1a0ae8847a175a36520e88363574276cca4 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 15 Mar 2019 14:20:10 -0400 Subject: [PATCH 30/44] whitespace cleanup (remove ctrl-m, trailing whitespace) --- doc/src/pair_granular.txt | 1332 ++++++++++++++++++------------------- 1 file changed, 666 insertions(+), 666 deletions(-) diff --git a/doc/src/pair_granular.txt b/doc/src/pair_granular.txt index 5854a8faf6..73c2bbdd3b 100644 --- a/doc/src/pair_granular.txt +++ b/doc/src/pair_granular.txt @@ -1,666 +1,666 @@ - - - -"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c - -:link(lws,http://lammps.sandia.gov) -:link(ld,Manual.html) -:link(lc,Commands_all.html) - -:line - -pair_style granular command :h3 - -[Syntax:] - -pair_style granular cutoff :pre - -cutoff = global cutoff (optional). See discussion below. :l -:ule - -[Examples:] - -pair_style granular -pair_coeff * * hooke 1000.0 50.0 tangential linear_nohistory 1.0 0.4 :pre - -pair_style granular -pair_coeff * * hertz 1000.0 50.0 tangential mindlin NULL 1.0 0.4 :pre - -pair_style granular -pair_coeff * * hertz/material 1e8 0.3 tangential mindlin_rescale NULL 1.0 0.4 damping tsuji :pre - -pair_style granular -pair_coeff 1 1 jkr 1000.0 50.0 tangential mindlin 800.0 1.0 0.5 rolling sds 500.0 200.0 0.5 twisting marshall -pair_coeff 2 2 hertz 200.0 20.0 tangential linear_history 300.0 1.0 0.1 rolling sds 200.0 100.0 0.1 twisting marshall :pre - -pair_style granular -pair_coeff 1 1 hertz 1000.0 50.0 tangential mindlin 800.0 0.5 0.5 rolling sds 500.0 200.0 0.5 twisting marshall -pair_coeff 2 2 dmt 1000.0 50.0 0.3 10.0 tangential mindlin 800.0 0.5 0.1 roll sds 500.0 200.0 0.1 twisting marshall -pair_coeff 1 2 dmt 1000.0 50.0 0.3 10.0 tangential mindlin 800.0 0.5 0.1 roll sds 500.0 200.0 0.1 twisting marshall :pre - -[Description:] - -The {granular} styles support a variety of options for the normal, tangential, rolling and twisting -forces resulting from contact between two granular particles. This expands on the options offered -by the "pair gran/*"_pair_gran.html pair styles. The total computed forces and torques are the -sum of various models selected for the normal, tangential, rolling and twisting modes of motion. - -All model choices and parameters are entered in the "pair_coeff"_pair_coeff.html command, as described below. -Unlike e.g. "pair gran/hooke"_pair_gran.html, coefficient values are not global, but can be set to different values for -different combinations of particle types, as determined by the "pair_coeff"_pair_coeff.html command. -If the contact model choice is the same for two particle types, the mixing for the cross-coefficients can be carried out -automatically. This is shown in the second example, where model choices are the same for type 1 - type 1 as for type 2 - type2 -interactions, but coefficients are different. In this case, the coefficients for type 2 - type interactions can be -determined from mixing rules discussed below. -For additional flexibility, coefficients as well as model forms can vary between particle types, -as shown in the third example: -type 1- type 1 interactions are based on a Hertzian normal contact model and 2-2 interactions are based on a DMT cohesive model (see below). -In that example, 1-1 and 2-2 interactions have different model forms, in which case -mixing of coefficients cannot be determined, so 1-2 interactions must be explicitly defined via the -{pair_coeff 1 2} command, otherwise an error would result. - -:line - -The first required keyword for the {pair_coeff} command is the normal contact model. Currently supported options -for normal contact models and their required arguments are: - -{hooke} : \(k_n\), \(\eta_\{n0\}\) (or \(e\)) -{hertz} : \(k_n\), \(\eta_\{n0\}\) (or \(e\)) -{hertz/material} : E, \(\eta_\{n0\}\) (or \(e\)), \(\nu\) -{dmt} : E, \(\eta_\{n0\}\) (or \(e\)), \(\nu\), \(\gamma\) -{jkr} : E, \(\eta_\{n0\}\) (or \(e\)), \(\nu\), \(\gamma\) :ol - -Here, \(k_n\) is spring stiffness (with units that depend on model choice, see below); -\(\eta_\{n0\}\) is a damping prefactor (or, in its place a coefficient of restitution -\(e\), depending on the choice of damping mode, see below); E is Young's modulus -in units of {force}/{length}^2, i.e. {pressure}; \(\nu\) is Poisson's ratio -and \(\gamma\) is a surface energy density, in units of {energy}/{length}^2. - -For the {hooke} model, the normal, elastic component of force acting on particle {i} due to -contact with particle {j} is given by: -\begin\{equation\} -\mathbf\{F\}_\{ne, Hooke\} = k_N \delta_\{ij\} \mathbf\{n\} -\end\{equation\} - -Where \(\delta = R_i + R_j - \|\mathbf\{r\}_\{ij\}\|\) is the particle overlap, -\(R_i, R_j\) are the particle radii, -\(\mathbf\{r\}_\{ij\} = \mathbf\{r\}_i - \mathbf\{r\}_j\) is the vector separating the -two particle centers (note the i-j ordering so that \(F_\{ne\}\) is positive for repulsion), -and \(\mathbf\{n\} = \frac\{\mathbf\{r\}_\{ij\}\}\{\|\mathbf\{r\}_\{ij\}\|\}\). -Therefore, for {hooke}, the units of the spring constant \(k_n\) are {force}/{distance}, -or equivalently {mass}/{time^2}. - -For the {hertz} model, the normal component of force is given by: -\begin\{equation\} -\mathbf\{F\}_\{ne, Hertz\} = k_N R_\{eff\}^\{1/2\}\delta_\{ij\}^\{3/2\} \mathbf\{n\} -\end\{equation\} - -Here, \(R_\{eff\} = \frac\{R_i R_j\}\{R_i + R_j\}\) is the effective radius, denoted for simplicity as {R} from here on. -For {hertz}, the units of the spring constant \(k_n\) are {force}/{length}^2, or equivalently -{pressure}. - -For the {hertz/material} model, the force is given by: -\begin\{equation\} -\mathbf\{F\}_\{ne, Hertz/material\} = \frac\{4\}\{3\} E_\{eff\} R_\{eff\}^\{1/2\}\delta_\{ij\}^\{3/2\} \mathbf\{n\} -\end\{equation\} - -Here, \(E_\{eff\} = E = \left(\frac\{1-\nu_i^2\}\{E_i\} + \frac\{1-\nu_j^2\}\{E_j\}\right)^\{-1\}\) -is the effective Young's modulus, -with \(\nu_i, \nu_j \) the Poisson ratios of the particles of types {i} and {j}. Note that -if the elastic modulus and the shear modulus of the two particles are the same, the {hertz/material} -model is equivalent to the {hertz} model with \(k_N = 4/3 E_\{eff\}\) - -The {dmt} model corresponds to the "(Derjaguin-Muller-Toporov)"_#DMT1975 cohesive model, -where the force is simply Hertz with an additional attractive cohesion term: -\begin\{equation\} -\mathbf\{F\}_\{ne, dmt\} = \left(\frac\{4\}\{3\} E R^\{1/2\}\delta_\{ij\}^\{3/2\} - 4\pi\gamma R\right)\mathbf\{n\} -\end\{equation\} - -The {jkr} model is the "(Johnson-Kendall-Roberts)"_#JKR1971 model, where the force is computed as: -\begin\{equation\} -\label\{eq:force_jkr\} -\mathbf\{F\}_\{ne, jkr\} = \left(\frac\{4Ea^3\}\{3R\} - 2\pi a^2\sqrt\{\frac\{4\gamma E\}\{\pi a\}\}\right)\mathbf\{n\} -\end\{equation\} - -Here, {a} is the radius of the contact zone, related to the overlap \(\delta\) according to: -\begin\{equation\} -\delta = a^2/R - 2\sqrt\{\pi \gamma a/E\} -\end\{equation\} - -LAMMPS internally inverts the equation above to solve for {a} in terms of \(\delta\), then solves for -the force in the previous equation. Additionally, note that the JKR model allows for a tensile force beyond -contact (i.e. for \(\delta < 0\)), up to a maximum of \(3\pi\gamma R\) (also known as -the 'pull-off' force). -Note that this is a hysteretic effect, where particles that are not contacting initially -will not experience force until they come into contact \(\delta \geq 0\); as they move apart -and (\(\delta < 0\)), they experience a tensile force up to \(3\pi\gamma R\), -at which point they lose contact. - -:line - -In addition, the normal force is augmented by a damping term of the following -general form: - -\begin\{equation\} -\mathbf\{F\}_\{n,damp\} = -\eta_n \mathbf\{v\}_\{n,rel\} -\end\{equation\} - -Here, \(\mathbf\{v\}_\{n,rel\} = (\mathbf\{v\}_j - \mathbf\{v\}_i) \cdot \mathbf\{n\}\) -is the component of relative velocity along \(\mathbf\{n\}\). - -The optional {damping} keyword to the {pair_coeff} command followed by a keyword -determines the model form of the damping factor \(\eta_n\), and the interpretation -of the \(\eta_\{n0\}\) or \(e\) coefficients specified as part of the normal contact -model settings. The {damping} keyword and corresponding -model form selection may be appended anywhere in the {pair coeff} command. -Note that the choice of damping model affects both the -normal and tangential damping (and depending on other settings, potentially also the twisting damping). -The options for the damping model currently supported are: - -{velocity} -{viscoelastic} -{tsuji} :ol - -If the {damping} keyword is not specified, the {viscoelastic} model is used by default. - -For {damping velocity}, the normal damping is simply equal to the user-specified damping -coefficient in the {normal} model: - -\begin\{equation\} -\eta_n = \eta_\{n0\}\ -\end\{equation\} - -Here, \(\gamma_n\) is the damping coefficient specified for the normal contact model, in units of {mass}/{time}, - -The {damping viscoelastic} model is based on the viscoelastic treatment of "(Brilliantov et al)"_#Brill1996, -where the normal damping is given by: -\begin\{equation\} -\eta_n = \eta_\{n0\}\ a m_\{eff\} -\end\{equation\} - -Here, \(m_\{eff\} = m_i m_j/(m_i + m_j)\) is the effective mass, {a} is the contact radius, given by \(a =\sqrt\{R\delta\}\) -for all models except {jkr}, for which it is given implicitly according to \(delta = a^2/R - 2\sqrt\{\pi \gamma a/E\}\). -In this case, \eta_\{n0\}\ is in units of 1/({time}*{distance}). - -The {tsuji} model is based on the work of "(Tsuji et al)"_#Tsuji1992. Here, the -damping coefficient specified as part of the normal model is interpreted -as a restitution coefficient \(e\). The damping constant \(\eta_n\) is given by: - -\begin\{equation\} -\eta_n = \alpha (m_\{eff\}k_n)^\{1/2\} -\end\{equation\} - -For normal contact models based on material parameters, \(k_n = 4/3Ea\). -The parameter \(\alpha\) is related to the restitution coefficient {e} according to: - -\begin\{equation\} -\alpha = 1.2728-4.2783e+11.087e^2-22.348e^3+27.467e^4-18.022e^5+4.8218e^6 -\end\{equation\} - -The dimensionless coefficient of restitution \(e\) specified as part of the normal contact model -parameters should be between 0 and 1, but no error check is performed on this. - -The total normal force is computed as the sum of the elastic and damping components: - -\begin\{equation\} -\mathbf\{F\}_n = \mathbf\{F\}_\{ne\} + \mathbf\{F\}_\{n,damp\} -\end\{equation\} - - :line - -The {pair_coeff} command also requires specification -of the tangential contact model. The required keyword {tangential} is expected, followed by the model -choice and associated parameters. Currently supported tangential model choices and their -expected parameters are as follows: - -{linear_nohistory} : \(x_\{\gamma,t\}\), \(\mu_s\) -{linear_history} : \(k_t\), \(x_\{\gamma,t\}\), \(\mu_s\) -{mindlin} : \(k_t\) or NULL, \(x_\{\gamma,t\}\), \(\mu_s\) -{mindlin_rescale} : \(k_t\) or NULL, \(x_\{\gamma,t\}\), \(\mu_s\) :ol - -Here, \(x_\{\gamma,t\}\) is a dimensionless multiplier for the normal damping \(\eta_n\) -that determines the magnitude of the -tangential damping, \(\mu_t\) is the tangential (or sliding) friction -coefficient, and \(k_t\) is the tangential stiffness coefficient. - -For {tangential linear_nohistory}, a simple velocity-dependent Coulomb friction criterion is used, -which mimics the behavior -of the {pair gran/hooke} style. The tangential force (\mathbf\{F\}_t\) is given by: - -\begin\{equation\} -\mathbf\{F\}_t = -min(\mu_t F_\{n0\}, \|\mathbf\{F\}_\mathrm\{t,damp\}\|) \mathbf\{t\} -\end\{equation\} - -The tangential damping force \(\mathbf\{F\}_\mathrm\{t,damp\}\) is given by: - -\begin\{equation\} -\mathbf\{F\}_\mathrm\{t,damp\} = -\eta_t \mathbf\{v\}_\{t,rel\} -\end\{equation\} - -The tangential damping prefactor \(\eta_t\) is calculated by scaling the normal damping \(\eta_n\) (see above): -\begin\{equation\} -\eta_t = -x_\{\gamma,t\} \eta_n -\end\{equation\} - -The normal damping prefactor \(\eta_n\) is determined by the choice of the {damping} keyword, as discussed above. -Thus, the {damping} keyword also affects the tangential damping. -The parameter \(x_\{\gamma,t\}\) is a scaling coefficient. Several works in the literature use -\(x_\{\gamma,t\} = 1\) ("Marshall"_#Marshall2009, "Tsuji et al"_#Tsuji1992, "Silbert et al"_#Silbert2001). -The relative tangential velocity at the point of contact is given by -\(\mathbf\{v\}_\{t, rel\} = \mathbf\{v\}_\{t\} - (R_i\Omega_i + R_j\Omega_j) \times \mathbf\{n\}\), -where \(\mathbf\{v\}_\{t\} = \mathbf\{v\}_r - \mathbf\{v\}_r\cdot\mathbf\{n\}\), -\(\mathbf\{v\}_r = \mathbf\{v\}_j - \mathbf\{v\}_i\). The direction of the applied force is -\(\mathbf\{t\} = \mathbf\{v_\{t,rel\}\}/\|\mathbf\{v_\{t,rel\}\}\|\). - -The normal force value \(F_\{n0\}\) used to compute the critical force -depends on the form of the contact model. For non-cohesive models -({hertz}, {hertz/material}, {hooke}), it is given by the magnitude of the normal force: - -\begin\{equation\} -F_\{n0\} = \|\mathbf\{F\}_n\| -\end\{equation\} - -For cohesive models such as {jkr} and {dmt}, the critical force is adjusted so that the critical tangential -force approaches \(\mu_t F_\{pulloff\}\), see "Marshall"_#Marshall2009, equation 43, and "Thornton"_#Thornton1991. -For both models, \(F_\{n0\}\) takes the form: - -\begin\{equation\} -F_\{n0\} = \|\mathbf\{F\}_ne + 2 F_\{pulloff\}\| -\end\{equation\} - -Where \(F_\{pulloff\} = 3\pi \gamma R \) for {jkr}, and \(F_\{pulloff\} = 4\pi \gamma R \) for {dmt}. - -The remaining tangential options all use accumulated tangential displacement (i.e. contact history). This -is discussed below in the context of the {linear_history} option, but the same treatment of the -accumulated displacement applies to the other options as well. - -For {tangential linear_history}, the tangential force is given by: - -\begin\{equation\} -\mathbf\{F\}_t = -min(\mu_t F_\{n0\}, \|-k_t\mathbf\{\xi\} + \mathbf\{F\}_\mathrm\{t,damp\}\|) \mathbf\{t\} -\end\{equation\} - -Here, \(\mathbf\{\xi\}\) is the tangential displacement accumulated during the entire -duration of the contact: - -\begin\{equation\} -\mathbf\{\xi\} = \int_\{t0\}^t \mathbf\{v\}_\{t,rel\}(\tau) \mathrm\{d\}\tau -\end\{equation\} - -This accumulated tangential displacement must be adjusted to account for changes -in the frame of reference -of the contacting pair of particles during contact. This occurs due to the overall motion of the contacting particles -in a rigid-body-like fashion during the duration of the contact. There are two modes of motion -that are relevant: the 'tumbling' rotation of the contacting pair, which changes the orientation of the -plane in which tangential displacement occurs; and 'spinning' rotation of the contacting pair -about the vector connecting their centers of mass (\(\mathbf\{n\}\)). -Corrections due to the former mode of motion are -made by rotating the accumulated displacement into the plane that is tangential -to the contact vector at each step, -or equivalently removing any component of the tangential displacement -that lies along \(\mathbf\{n\}\), and rescaling to preserve the magnitude. -This follows the discussion in "Luding"_#Luding2008, see equation 17 and -relevant discussion in that work: - -\begin\{equation\} -\mathbf\{\xi\} = \left(\mathbf\{\xi'\} - (\mathbf\{n\} \cdot \mathbf\{\xi'\})\mathbf\{n\}\right) \frac\{\|\mathbf\{\xi'\}\|\}\{\|\mathbf\{\xi'\}\| - \mathbf\{n\}\cdot\mathbf\{\xi'\}\} -\label\{eq:rotate_displacements\} -\end\{equation\} - -Here, \(\mathbf\{\xi'\}\) is the accumulated displacement prior to the current time step and -\(\mathbf\{\xi\}\) is the corrected displacement. Corrections to the displacement -due to the second mode of motion described above (rotations about \(\mathbf\{n\}\)) -are not currently implemented, but are expected to be minor for most simulations. - -Furthermore, when the tangential force exceeds the critical force, -the tangential displacement is re-scaled to match the value for the critical force (see "Luding"_#Luding2008, -equation 20 and related discussion): - -\begin\{equation\} -\mathbf\{\xi\} = -\frac\{1\}\{k_t\}\left(\mu_t F_\{n0\}\mathbf\{t\} + \mathbf\{F\}_\{t,damp\}\right) -\end\{equation\} - -The tangential force is added to the total normal force (elastic plus damping) to produce the total force -on the particle. The tangential force also acts at the contact point (defined as the center of the overlap region) -to induce a torque on each particle according to: - -\begin\{equation\} -\mathbf\{\tau\}_i = -(R_i - 0.5 \delta) \mathbf\{n\} \times \mathbf\{F\}_t -\end\{equation\} - -\begin\{equation\} -\mathbf\{\tau\}_j = -(R_j - 0.5 \delta) \mathbf\{n\} \times \mathbf\{F\}_t -\end\{equation\} - -For {tangential mindlin}, the "Mindlin"_#Mindlin1949 no-slip solution is used, which differs from the {linear_history} -option by an additional factor of {a}, the radius of the contact region. The tangential force is given by: - -\begin\{equation\} -\mathbf\{F\}_t = -min(\mu_t F_\{n0\}, \|-k_t a \mathbf\{\xi\} + \mathbf\{F\}_\mathrm\{t,damp\}\|) \mathbf\{t\} -\end\{equation\} - -Here, {a} is the radius of the contact region, given by \(a = \delta R\) for all normal contact models, -except for {jkr}, where it is given implicitly by \(\delta = a^2/R - 2\sqrt\{\pi \gamma a/E\}\), -see discussion above. To match the Mindlin solution, one should set \(k_t = 8G\), where -\(G\) is the shear modulus, related to Young's modulus \(E\) by \(G = E/(2(1+\nu))\), where \(\nu\) -is Poisson's ratio. This can also be achieved by specifying {NULL} for \(k_t\), in which case -a normal contact model that specifies material parameters \(E\) and \(\nu\) is required (e.g. {hertz/material}, -{dmt} or {jkr}). In this case, mixing of the shear modulus for different particle types {i} and {j} is done according -to: -\begin\{equation\} -1/G = 2(2-\nu_i)(1+\nu_i)/E_i + 2(2-\nu_j)(1+\nu_j)/E_j -\end\{equation\} - -The {mindlin_rescale} option uses the same form as {mindlin}, but the magnitude of the tangential -displacement is re-scaled as the contact unloads, i.e. if \(a < a_\{t_\{n-1\}\}\): -\begin\{equation\} -\mathbf\{\xi\} = \mathbf\{\xi_\{t_\{n-1\}\}\} \frac\{a\}\{a_\{t_\{n-1\}\}\} -\end\{equation\} - -Here, \(t_\{n-1\}\) indicates the value at the previous time step. This rescaling -accounts for the fact that a decrease in the contact area upon unloading leads to the contact -being unable to support the previous tangential loading, and spurious energy is created -without the rescaling above ("Walton"_#WaltonPC ). See also discussion in "Thornton et al, 2013"_#Thornton2013 -, particularly equation 18(b) of that work and associated discussion. - -:line - -The optional {rolling} keyword enables rolling friction, which resists pure rolling -motion of particles. The options currently supported are: - -{none} -{sds} : \(k_\{roll\}\), \(\gamma_\{roll\}\), \(\mu_\{roll\}\) :ol - -If the {rolling} keyword is not specified, the model defaults to {none}. - -For {rolling sds}, rolling friction is computed via a spring-dashpot-slider, using a -'pseudo-force' formulation, as detailed by "Luding"_#Luding2008. Unlike the formulation -in "Marshall"_#Marshall2009, this allows for the required adjustment of -rolling displacement due to changes in the frame of reference of the contacting pair. -The rolling pseudo-force is computed analogously to the tangential force: - -\begin\{equation\} -\mathbf\{F\}_\{roll,0\} = k_\{roll\} \mathbf\{\xi\}_\{roll\} - \gamma_\{roll\} \mathbf\{v\}_\{roll\} -\end\{equation\} - -Here, \(\mathbf\{v\}_\{roll\} = -R(\mathbf\{\Omega\}_i - \mathbf\{\Omega\}_j) \times \mathbf\{n\}\) is the -relative rolling velocity, as given in "Wang et al"_#Wang2015 and "Luding"_#Luding2008. This differs -from the expressions given by "Kuhn and Bagi"_#Kuhn2004 and used in "Marshall"_#Marshall2009; -see "Wang et al"_#Wang2015 for details. The rolling displacement is given by: - -\begin\{equation\} -\mathbf\{\xi\}_\{roll\} = \int_\{t_0\}^t \mathbf\{v\}_\{roll\} (\tau) \mathrm\{d\} \tau -\end\{equation\} - -A Coulomb friction criterion truncates the rolling pseudo-force if it exceeds a critical value: -\begin\{equation\} -\mathbf\{F\}_\{roll\} = min(\mu_\{roll\} F_\{n,0\}, \|\mathbf\{F\}_\{roll,0\}\|)\mathbf\{k\} -\end\{equation\} - -Here, \(\mathbf\{k\} = \mathbf\{v\}_\{roll\}/\|\mathbf\{v\}_\{roll\}\|\) is the direction of the pseudo-force. -As with tangential displacement, the rolling displacement is rescaled when the critical -force is exceeded, so that the spring length corresponds the critical force. Additionally, the -displacement is adjusted to account for rotations of the frame of reference of the two -contacting particles in a manner analogous to the tangential displacement. - -The rolling pseudo-force does not contribute to the total force on either particle (hence 'pseudo'), -but acts only to induce an equal and opposite torque on each particle, according to: - -\begin\{equation\} -\tau_\{roll,i\} = R_\{eff\} \mathbf\{n\} \times \mathbf\{F\}_\{roll\} -\end\{equation\} - -\begin\{equation\} -\tau_\{roll,j\} = -\tau_\{roll,i\} -\end\{equation\} - -:line - -The optional {twisting} keyword enables twisting friction, which resists -rotation of two contacting particles about the vector \(\mathbf\{n\}\) that connects their -centers. The options currently supported are: - -{none} -{sds} : \(k_\{twist\}\), \(\gamma_\{twist\}\), \(\mu_\{twist\}\) -{marshall} :ol - -If the {twisting} keyword is not specified, the model defaults to {none}. - -For both {twisting sds} and {twisting marshall}, a history-dependent spring-dashpot-slider is used to compute the twisting -torque. Because twisting displacement is a scalar, there is no need to adjust for changes -in the frame of reference due to rotations of the particle pair. The formulation in -"Marshall"_#Marshall2009 therefore provides the most straightforward treatment: - -\begin\{equation\} -\tau_\{twist,0\} = -k_\{twist\}\xi_\{twist\} - \gamma_\{twist\}\Omega_\{twist\} -\end\{equation\} - -Here \(\xi_\{twist\} = \int_\{t_0\}^t \Omega_\{twist\} (\tau) \mathrm\{d\}\tau\) is the twisting -angular displacement, and \(\Omega_\{twist\} = (\mathbf\{\Omega\}_i - \mathbf\{\Omega\}_j) \cdot \mathbf\{n\}\) -is the relative twisting angular velocity. The torque is then truncated according to: - -\begin\{equation\} -\tau_\{twist\} = min(\mu_\{twist\} F_\{n,0\}, \tau_\{twist,0\}) -\end\{equation\} - -Similar to the sliding and rolling displacement, the angular displacement is -rescaled so that it corresponds to the critical value if the twisting torque -exceeds this critical value: - -\begin\{equation\} -\xi_\{twist\} = \frac\{1\}\{k_\{twist\}\} (\mu_\{twist\} F_\{n,0\}sgn(\Omega_\{twist\}) - \gamma_\{twist\}\Omega_\{twist\}) -\end\{equation\} - -For {twisting sds}, the coefficients \(k_\{twist\}, \gamma_\{twist\}\) and \(\mu_\{twist\}\) are -simply the user input parameters that follow the {twisting sds} keywords in the {pair_coeff} command. - -For {twisting_marshall}, the coefficients are expressed in terms of sliding friction coefficients, -as discussed in "Marshall"_#Marshall2009 (see equations 32 and 33 of that work): - -\begin\{equation\} -k_\{twist\} = 0.5k_ta^2 -\end\{equation\} - -\begin\{equation\} -\eta_\{twist\} = 0.5\eta_ta^2 -\end\{equation\} - -\begin\{equation\} -\mu_\{twist\} = \frac\{2\}\{3\}a\mu_t -\end\{equation\} - -Finally, the twisting torque on each particle is given by: - -\begin\{equation\} -\mathbf\{\tau\}_\{twist,i\} = \tau_\{twist\}\mathbf\{n\} -\end\{equation\} - -\begin\{equation\} -\mathbf\{\tau\}_\{twist,j\} = -\mathbf\{\tau\}_\{twist,i\} -\end\{equation\} - -:line - -LAMMPS automatically sets pairwise cutoff values for {pair_style granular} based on particle radii (and in the case -of {jkr} pull-off distances). In the vast majority of situations, this is adequate. -However, a cutoff value can optionally be appended to the {pair_style granular} command to specify -a global cutoff (i.e. a cutoff for all atom types). Additionally, the optional {cutoff} keyword -can be passed to the {pair_coeff} command, followed by a cutoff value. -This will set a pairwise cutoff for the atom types in the {pair_coeff} command. -These options may be useful in some rare cases where the automatic cutoff determination is not sufficient, e.g. -if particle diameters are being modified via the {fix adapt} command. In that case, the global cutoff -specified as part of the {pair_style granular} command is applied to all atom types, unless it is -overridden for a given atom type combination by the {cutoff} value specified in the {pair coeff} command. -If {cutoff} is only specified in the {pair coeff} command and no global -cutoff is appended to the {pair_style granular} command, then LAMMPS will use that cutoff for the specified -atom type combination, and automatically set pairwise cutoffs for the remaining atom types. - -:line - -Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are -functionally the same as the corresponding style without the suffix. -They have been optimized to run faster, depending on your available -hardware, as discussed on the "Speed packages"_Speed_packages.html doc -page. The accelerated styles take the same arguments and should -produce the same results, except for round-off and precision issues. - -These accelerated styles are part of the GPU, USER-INTEL, KOKKOS, -USER-OMP and OPT packages, respectively. They are only enabled if -LAMMPS was built with those packages. See the "Build -package"_Build_package.html doc page for more info. - -You can specify the accelerated styles explicitly in your input script -by including their suffix, or you can use the "-suffix command-line -switch"_Run_options.html when you invoke LAMMPS, or you can use the -"suffix"_suffix.html command in your input script. - -See the "Speed packages"_Speed_packages.html doc page for more -instructions on how to use the accelerated styles effectively. - -:line - -[Mixing, shift, table, tail correction, restart, rRESPA info]: - -The "pair_modify"_pair_modify.html mix, shift, table, and tail options -are not relevant for granular pair styles. - -Mixing of coefficients is carried out using geometric averaging for -most quantities, e.g. if friction coefficient for type 1-type 1 interactions -is set to \(\mu_1\), and friction coefficient for type 2-type 2 interactions -is set to \(\mu_2\), the friction coefficient for type1-type2 interactions -is computed as \(\sqrt\{\mu_1\mu_2\}\) (unless explicitly specified to -a different value by a {pair_coeff 1 2 ...} command. The exception to this is -elastic modulus, only applicable to {hertz/material}, {dmt} and {jkr} normal -contact models. In that case, the effective elastic modulus is computed as: - -\begin\{equation\} -E_\{eff,ij\} = \left(\frac\{1-\nu_i^2\}\{E_i\} + \frac\{1-\nu_j^2\}\{E_j\}\right)^\{-1\} -\end\{equation\} - -If the {i-j} coefficients \(E_\{ij\}\) and \(\nu_\{ij\}\) are explicitly specified, -the effective modulus is computed as: - -\begin\{equation\} -E_\{eff,ij\} = \left(\frac\{1-\nu_\{ij\}^2\}\{E_\{ij\}\} + \frac\{1-\nu_\{ij\}^2\}\{E_\{ij\}\}\right)^\{-1\} -\end\{equation\} - -or - -\begin\{equation\} -E_\{eff,ij\} = \frac\{E_\{ij\}\}\{2(1-\nu_\{ij\})\} -\end\{equation\} - -These pair styles write their information to "binary restart -files"_restart.html, so a pair_style command does not need to be -specified in an input script that reads a restart file. - -These pair styles can only be used via the {pair} keyword of the -"run_style respa"_run_style.html command. They do not support the -{inner}, {middle}, {outer} keywords. - -The single() function of these pair styles returns 0.0 for the energy -of a pairwise interaction, since energy is not conserved in these -dissipative potentials. It also returns only the normal component of -the pairwise interaction force. However, the single() function also -calculates 10 extra pairwise quantities. The first 3 are the -components of the tangential force between particles I and J, acting -on particle I. The 4th is the magnitude of this tangential force. -The next 3 (5-7) are the components of the rolling torque acting on -particle I. The next entry (8) is the magnitude of the rolling torque. -The next entry (9) is the magnitude of the twisting torque acting -about the vector connecting the two particle centers. -The last 3 (10-12) are the components of the vector connecting -the centers of the two particles (x_I - x_J). - -These extra quantities can be accessed by the "compute -pair/local"_compute_pair_local.html command, as {p1}, {p2}, ..., -{p12}. - -:line - -[Restrictions:] - -All the granular pair styles are part of the GRANULAR package. It is -only enabled if LAMMPS was built with that package. See the "Build -package"_Build_package.html doc page for more info. - -These pair styles require that atoms store torque and angular velocity -(omega) as defined by the "atom_style"_atom_style.html. They also -require a per-particle radius is stored. The {sphere} atom style does -all of this. - -This pair style requires you to use the "comm_modify vel -yes"_comm_modify.html command so that velocities are stored by ghost -atoms. - -These pair styles will not restart exactly when using the -"read_restart"_read_restart.html command, though they should provide -statistically similar results. This is because the forces they -compute depend on atom velocities. See the -"read_restart"_read_restart.html command for more details. - -[Related commands:] - -"pair_coeff"_pair_coeff.html -"pair gran/*"_pair_gran.html - -[Default:] - -For the {pair_coeff} settings: {damping viscoelastic}, {rolling none}, {twisting none} - -[References:] - -:link(Brill1996) -[(Brilliantov et al, 1996)] Brilliantov, N. V., Spahn, F., Hertzsch, J. M., & Poschel, T. (1996). -Model for collisions in granular gases. Physical review E, 53(5), 5382. - -:link(Tsuji1992) -[(Tsuji et al, 1992)] Tsuji, Y., Tanaka, T., & Ishida, T. (1992). Lagrangian numerical simulation of plug flow of -cohesionless particles in a horizontal pipe. Powder technology, 71(3), 239-250. - -:link(JKR1971) -[(Johnson et al, 1971)] Johnson, K. L., Kendall, K., & Roberts, A. D. (1971). -Surface energy and the contact of elastic solids. Proc. R. Soc. Lond. A, 324(1558), 301-313. - -:link(DMT1975) -[Derjaguin et al, 1975)] Derjaguin, B. V., Muller, V. M., & Toporov, Y. P. (1975). Effect of contact deformations on the -adhesion of particles. Journal of Colloid and interface science, 53(2), 314-326. - -:link(Luding2008) -[(Luding, 2008)] Luding, S. (2008). Cohesive, frictional powders: contact models for tension. Granular matter, 10(4), 235. - -:link(Marshall2009) -[(Marshall, 2009)] Marshall, J. S. (2009). Discrete-element modeling of particulate aerosol flows. -Journal of Computational Physics, 228(5), 1541-1561. - -:link(Silbert2001) -[(Silbert, 2001)] Silbert, L. E., Ertas, D., Grest, G. S., Halsey, T. C., Levine, D., & Plimpton, S. J. (2001). -Granular flow down an inclined plane: Bagnold scaling and rheology. Physical Review E, 64(5), 051302. - -:link(Kuhn2004) -[(Kuhn and Bagi, 2005)] Kuhn, M. R., & Bagi, K. (2004). Contact rolling and deformation in granular media. -International journal of solids and structures, 41(21), 5793-5820. - -:link(Wang2015) -[(Wang et al, 2015)] Wang, Y., Alonso-Marroquin, F., & Guo, W. W. (2015). -Rolling and sliding in 3-D discrete element models. Particuology, 23, 49-55. - -:link(Thornton1991) -[(Thornton, 1991)] Thornton, C. (1991). Interparticle sliding in the presence of adhesion. -J. Phys. D: Appl. Phys. 24 1942 - -:link(Mindlin1949) -[(Mindlin, 1949)] Mindlin, R. D. (1949). Compliance of elastic bodies in contact. -J. Appl. Mech., ASME 16, 259-268. - -:link(Thornton2013) -[(Thornton et al, 2013)] Thornton, C., Cummins, S. J., & Cleary, P. W. (2013). -An investigation of the comparative behaviour of alternative contact force models -during inelastic collisions. Powder Technology, 233, 30-46. - -:link(WaltonPC) -[(Otis R. Walton)] Walton, O.R., Personal Communication + + + +"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c + +:link(lws,http://lammps.sandia.gov) +:link(ld,Manual.html) +:link(lc,Commands_all.html) + +:line + +pair_style granular command :h3 + +[Syntax:] + +pair_style granular cutoff :pre + +cutoff = global cutoff (optional). See discussion below. :l +:ule + +[Examples:] + +pair_style granular +pair_coeff * * hooke 1000.0 50.0 tangential linear_nohistory 1.0 0.4 :pre + +pair_style granular +pair_coeff * * hertz 1000.0 50.0 tangential mindlin NULL 1.0 0.4 :pre + +pair_style granular +pair_coeff * * hertz/material 1e8 0.3 tangential mindlin_rescale NULL 1.0 0.4 damping tsuji :pre + +pair_style granular +pair_coeff 1 1 jkr 1000.0 50.0 tangential mindlin 800.0 1.0 0.5 rolling sds 500.0 200.0 0.5 twisting marshall +pair_coeff 2 2 hertz 200.0 20.0 tangential linear_history 300.0 1.0 0.1 rolling sds 200.0 100.0 0.1 twisting marshall :pre + +pair_style granular +pair_coeff 1 1 hertz 1000.0 50.0 tangential mindlin 800.0 0.5 0.5 rolling sds 500.0 200.0 0.5 twisting marshall +pair_coeff 2 2 dmt 1000.0 50.0 0.3 10.0 tangential mindlin 800.0 0.5 0.1 roll sds 500.0 200.0 0.1 twisting marshall +pair_coeff 1 2 dmt 1000.0 50.0 0.3 10.0 tangential mindlin 800.0 0.5 0.1 roll sds 500.0 200.0 0.1 twisting marshall :pre + +[Description:] + +The {granular} styles support a variety of options for the normal, tangential, rolling and twisting +forces resulting from contact between two granular particles. This expands on the options offered +by the "pair gran/*"_pair_gran.html pair styles. The total computed forces and torques are the +sum of various models selected for the normal, tangential, rolling and twisting modes of motion. + +All model choices and parameters are entered in the "pair_coeff"_pair_coeff.html command, as described below. +Unlike e.g. "pair gran/hooke"_pair_gran.html, coefficient values are not global, but can be set to different values for +different combinations of particle types, as determined by the "pair_coeff"_pair_coeff.html command. +If the contact model choice is the same for two particle types, the mixing for the cross-coefficients can be carried out +automatically. This is shown in the second example, where model choices are the same for type 1 - type 1 as for type 2 - type2 +interactions, but coefficients are different. In this case, the coefficients for type 2 - type interactions can be +determined from mixing rules discussed below. +For additional flexibility, coefficients as well as model forms can vary between particle types, +as shown in the third example: +type 1- type 1 interactions are based on a Hertzian normal contact model and 2-2 interactions are based on a DMT cohesive model (see below). +In that example, 1-1 and 2-2 interactions have different model forms, in which case +mixing of coefficients cannot be determined, so 1-2 interactions must be explicitly defined via the +{pair_coeff 1 2} command, otherwise an error would result. + +:line + +The first required keyword for the {pair_coeff} command is the normal contact model. Currently supported options +for normal contact models and their required arguments are: + +{hooke} : \(k_n\), \(\eta_\{n0\}\) (or \(e\)) +{hertz} : \(k_n\), \(\eta_\{n0\}\) (or \(e\)) +{hertz/material} : E, \(\eta_\{n0\}\) (or \(e\)), \(\nu\) +{dmt} : E, \(\eta_\{n0\}\) (or \(e\)), \(\nu\), \(\gamma\) +{jkr} : E, \(\eta_\{n0\}\) (or \(e\)), \(\nu\), \(\gamma\) :ol + +Here, \(k_n\) is spring stiffness (with units that depend on model choice, see below); +\(\eta_\{n0\}\) is a damping prefactor (or, in its place a coefficient of restitution +\(e\), depending on the choice of damping mode, see below); E is Young's modulus +in units of {force}/{length}^2, i.e. {pressure}; \(\nu\) is Poisson's ratio +and \(\gamma\) is a surface energy density, in units of {energy}/{length}^2. + +For the {hooke} model, the normal, elastic component of force acting on particle {i} due to +contact with particle {j} is given by: +\begin\{equation\} +\mathbf\{F\}_\{ne, Hooke\} = k_N \delta_\{ij\} \mathbf\{n\} +\end\{equation\} + +Where \(\delta = R_i + R_j - \|\mathbf\{r\}_\{ij\}\|\) is the particle overlap, +\(R_i, R_j\) are the particle radii, +\(\mathbf\{r\}_\{ij\} = \mathbf\{r\}_i - \mathbf\{r\}_j\) is the vector separating the +two particle centers (note the i-j ordering so that \(F_\{ne\}\) is positive for repulsion), +and \(\mathbf\{n\} = \frac\{\mathbf\{r\}_\{ij\}\}\{\|\mathbf\{r\}_\{ij\}\|\}\). +Therefore, for {hooke}, the units of the spring constant \(k_n\) are {force}/{distance}, +or equivalently {mass}/{time^2}. + +For the {hertz} model, the normal component of force is given by: +\begin\{equation\} +\mathbf\{F\}_\{ne, Hertz\} = k_N R_\{eff\}^\{1/2\}\delta_\{ij\}^\{3/2\} \mathbf\{n\} +\end\{equation\} + +Here, \(R_\{eff\} = \frac\{R_i R_j\}\{R_i + R_j\}\) is the effective radius, denoted for simplicity as {R} from here on. +For {hertz}, the units of the spring constant \(k_n\) are {force}/{length}^2, or equivalently +{pressure}. + +For the {hertz/material} model, the force is given by: +\begin\{equation\} +\mathbf\{F\}_\{ne, Hertz/material\} = \frac\{4\}\{3\} E_\{eff\} R_\{eff\}^\{1/2\}\delta_\{ij\}^\{3/2\} \mathbf\{n\} +\end\{equation\} + +Here, \(E_\{eff\} = E = \left(\frac\{1-\nu_i^2\}\{E_i\} + \frac\{1-\nu_j^2\}\{E_j\}\right)^\{-1\}\) +is the effective Young's modulus, +with \(\nu_i, \nu_j \) the Poisson ratios of the particles of types {i} and {j}. Note that +if the elastic modulus and the shear modulus of the two particles are the same, the {hertz/material} +model is equivalent to the {hertz} model with \(k_N = 4/3 E_\{eff\}\) + +The {dmt} model corresponds to the "(Derjaguin-Muller-Toporov)"_#DMT1975 cohesive model, +where the force is simply Hertz with an additional attractive cohesion term: +\begin\{equation\} +\mathbf\{F\}_\{ne, dmt\} = \left(\frac\{4\}\{3\} E R^\{1/2\}\delta_\{ij\}^\{3/2\} - 4\pi\gamma R\right)\mathbf\{n\} +\end\{equation\} + +The {jkr} model is the "(Johnson-Kendall-Roberts)"_#JKR1971 model, where the force is computed as: +\begin\{equation\} +\label\{eq:force_jkr\} +\mathbf\{F\}_\{ne, jkr\} = \left(\frac\{4Ea^3\}\{3R\} - 2\pi a^2\sqrt\{\frac\{4\gamma E\}\{\pi a\}\}\right)\mathbf\{n\} +\end\{equation\} + +Here, {a} is the radius of the contact zone, related to the overlap \(\delta\) according to: +\begin\{equation\} +\delta = a^2/R - 2\sqrt\{\pi \gamma a/E\} +\end\{equation\} + +LAMMPS internally inverts the equation above to solve for {a} in terms of \(\delta\), then solves for +the force in the previous equation. Additionally, note that the JKR model allows for a tensile force beyond +contact (i.e. for \(\delta < 0\)), up to a maximum of \(3\pi\gamma R\) (also known as +the 'pull-off' force). +Note that this is a hysteretic effect, where particles that are not contacting initially +will not experience force until they come into contact \(\delta \geq 0\); as they move apart +and (\(\delta < 0\)), they experience a tensile force up to \(3\pi\gamma R\), +at which point they lose contact. + +:line + +In addition, the normal force is augmented by a damping term of the following +general form: + +\begin\{equation\} +\mathbf\{F\}_\{n,damp\} = -\eta_n \mathbf\{v\}_\{n,rel\} +\end\{equation\} + +Here, \(\mathbf\{v\}_\{n,rel\} = (\mathbf\{v\}_j - \mathbf\{v\}_i) \cdot \mathbf\{n\}\) +is the component of relative velocity along \(\mathbf\{n\}\). + +The optional {damping} keyword to the {pair_coeff} command followed by a keyword +determines the model form of the damping factor \(\eta_n\), and the interpretation +of the \(\eta_\{n0\}\) or \(e\) coefficients specified as part of the normal contact +model settings. The {damping} keyword and corresponding +model form selection may be appended anywhere in the {pair coeff} command. +Note that the choice of damping model affects both the +normal and tangential damping (and depending on other settings, potentially also the twisting damping). +The options for the damping model currently supported are: + +{velocity} +{viscoelastic} +{tsuji} :ol + +If the {damping} keyword is not specified, the {viscoelastic} model is used by default. + +For {damping velocity}, the normal damping is simply equal to the user-specified damping +coefficient in the {normal} model: + +\begin\{equation\} +\eta_n = \eta_\{n0\}\ +\end\{equation\} + +Here, \(\gamma_n\) is the damping coefficient specified for the normal contact model, in units of {mass}/{time}, + +The {damping viscoelastic} model is based on the viscoelastic treatment of "(Brilliantov et al)"_#Brill1996, +where the normal damping is given by: +\begin\{equation\} +\eta_n = \eta_\{n0\}\ a m_\{eff\} +\end\{equation\} + +Here, \(m_\{eff\} = m_i m_j/(m_i + m_j)\) is the effective mass, {a} is the contact radius, given by \(a =\sqrt\{R\delta\}\) +for all models except {jkr}, for which it is given implicitly according to \(delta = a^2/R - 2\sqrt\{\pi \gamma a/E\}\). +In this case, \eta_\{n0\}\ is in units of 1/({time}*{distance}). + +The {tsuji} model is based on the work of "(Tsuji et al)"_#Tsuji1992. Here, the +damping coefficient specified as part of the normal model is interpreted +as a restitution coefficient \(e\). The damping constant \(\eta_n\) is given by: + +\begin\{equation\} +\eta_n = \alpha (m_\{eff\}k_n)^\{1/2\} +\end\{equation\} + +For normal contact models based on material parameters, \(k_n = 4/3Ea\). +The parameter \(\alpha\) is related to the restitution coefficient {e} according to: + +\begin\{equation\} +\alpha = 1.2728-4.2783e+11.087e^2-22.348e^3+27.467e^4-18.022e^5+4.8218e^6 +\end\{equation\} + +The dimensionless coefficient of restitution \(e\) specified as part of the normal contact model +parameters should be between 0 and 1, but no error check is performed on this. + +The total normal force is computed as the sum of the elastic and damping components: + +\begin\{equation\} +\mathbf\{F\}_n = \mathbf\{F\}_\{ne\} + \mathbf\{F\}_\{n,damp\} +\end\{equation\} + + :line + +The {pair_coeff} command also requires specification +of the tangential contact model. The required keyword {tangential} is expected, followed by the model +choice and associated parameters. Currently supported tangential model choices and their +expected parameters are as follows: + +{linear_nohistory} : \(x_\{\gamma,t\}\), \(\mu_s\) +{linear_history} : \(k_t\), \(x_\{\gamma,t\}\), \(\mu_s\) +{mindlin} : \(k_t\) or NULL, \(x_\{\gamma,t\}\), \(\mu_s\) +{mindlin_rescale} : \(k_t\) or NULL, \(x_\{\gamma,t\}\), \(\mu_s\) :ol + +Here, \(x_\{\gamma,t\}\) is a dimensionless multiplier for the normal damping \(\eta_n\) +that determines the magnitude of the +tangential damping, \(\mu_t\) is the tangential (or sliding) friction +coefficient, and \(k_t\) is the tangential stiffness coefficient. + +For {tangential linear_nohistory}, a simple velocity-dependent Coulomb friction criterion is used, +which mimics the behavior +of the {pair gran/hooke} style. The tangential force (\mathbf\{F\}_t\) is given by: + +\begin\{equation\} +\mathbf\{F\}_t = -min(\mu_t F_\{n0\}, \|\mathbf\{F\}_\mathrm\{t,damp\}\|) \mathbf\{t\} +\end\{equation\} + +The tangential damping force \(\mathbf\{F\}_\mathrm\{t,damp\}\) is given by: + +\begin\{equation\} +\mathbf\{F\}_\mathrm\{t,damp\} = -\eta_t \mathbf\{v\}_\{t,rel\} +\end\{equation\} + +The tangential damping prefactor \(\eta_t\) is calculated by scaling the normal damping \(\eta_n\) (see above): +\begin\{equation\} +\eta_t = -x_\{\gamma,t\} \eta_n +\end\{equation\} + +The normal damping prefactor \(\eta_n\) is determined by the choice of the {damping} keyword, as discussed above. +Thus, the {damping} keyword also affects the tangential damping. +The parameter \(x_\{\gamma,t\}\) is a scaling coefficient. Several works in the literature use +\(x_\{\gamma,t\} = 1\) ("Marshall"_#Marshall2009, "Tsuji et al"_#Tsuji1992, "Silbert et al"_#Silbert2001). +The relative tangential velocity at the point of contact is given by +\(\mathbf\{v\}_\{t, rel\} = \mathbf\{v\}_\{t\} - (R_i\Omega_i + R_j\Omega_j) \times \mathbf\{n\}\), +where \(\mathbf\{v\}_\{t\} = \mathbf\{v\}_r - \mathbf\{v\}_r\cdot\mathbf\{n\}\), +\(\mathbf\{v\}_r = \mathbf\{v\}_j - \mathbf\{v\}_i\). The direction of the applied force is +\(\mathbf\{t\} = \mathbf\{v_\{t,rel\}\}/\|\mathbf\{v_\{t,rel\}\}\|\). + +The normal force value \(F_\{n0\}\) used to compute the critical force +depends on the form of the contact model. For non-cohesive models +({hertz}, {hertz/material}, {hooke}), it is given by the magnitude of the normal force: + +\begin\{equation\} +F_\{n0\} = \|\mathbf\{F\}_n\| +\end\{equation\} + +For cohesive models such as {jkr} and {dmt}, the critical force is adjusted so that the critical tangential +force approaches \(\mu_t F_\{pulloff\}\), see "Marshall"_#Marshall2009, equation 43, and "Thornton"_#Thornton1991. +For both models, \(F_\{n0\}\) takes the form: + +\begin\{equation\} +F_\{n0\} = \|\mathbf\{F\}_ne + 2 F_\{pulloff\}\| +\end\{equation\} + +Where \(F_\{pulloff\} = 3\pi \gamma R \) for {jkr}, and \(F_\{pulloff\} = 4\pi \gamma R \) for {dmt}. + +The remaining tangential options all use accumulated tangential displacement (i.e. contact history). This +is discussed below in the context of the {linear_history} option, but the same treatment of the +accumulated displacement applies to the other options as well. + +For {tangential linear_history}, the tangential force is given by: + +\begin\{equation\} +\mathbf\{F\}_t = -min(\mu_t F_\{n0\}, \|-k_t\mathbf\{\xi\} + \mathbf\{F\}_\mathrm\{t,damp\}\|) \mathbf\{t\} +\end\{equation\} + +Here, \(\mathbf\{\xi\}\) is the tangential displacement accumulated during the entire +duration of the contact: + +\begin\{equation\} +\mathbf\{\xi\} = \int_\{t0\}^t \mathbf\{v\}_\{t,rel\}(\tau) \mathrm\{d\}\tau +\end\{equation\} + +This accumulated tangential displacement must be adjusted to account for changes +in the frame of reference +of the contacting pair of particles during contact. This occurs due to the overall motion of the contacting particles +in a rigid-body-like fashion during the duration of the contact. There are two modes of motion +that are relevant: the 'tumbling' rotation of the contacting pair, which changes the orientation of the +plane in which tangential displacement occurs; and 'spinning' rotation of the contacting pair +about the vector connecting their centers of mass (\(\mathbf\{n\}\)). +Corrections due to the former mode of motion are +made by rotating the accumulated displacement into the plane that is tangential +to the contact vector at each step, +or equivalently removing any component of the tangential displacement +that lies along \(\mathbf\{n\}\), and rescaling to preserve the magnitude. +This follows the discussion in "Luding"_#Luding2008, see equation 17 and +relevant discussion in that work: + +\begin\{equation\} +\mathbf\{\xi\} = \left(\mathbf\{\xi'\} - (\mathbf\{n\} \cdot \mathbf\{\xi'\})\mathbf\{n\}\right) \frac\{\|\mathbf\{\xi'\}\|\}\{\|\mathbf\{\xi'\}\| - \mathbf\{n\}\cdot\mathbf\{\xi'\}\} +\label\{eq:rotate_displacements\} +\end\{equation\} + +Here, \(\mathbf\{\xi'\}\) is the accumulated displacement prior to the current time step and +\(\mathbf\{\xi\}\) is the corrected displacement. Corrections to the displacement +due to the second mode of motion described above (rotations about \(\mathbf\{n\}\)) +are not currently implemented, but are expected to be minor for most simulations. + +Furthermore, when the tangential force exceeds the critical force, +the tangential displacement is re-scaled to match the value for the critical force (see "Luding"_#Luding2008, +equation 20 and related discussion): + +\begin\{equation\} +\mathbf\{\xi\} = -\frac\{1\}\{k_t\}\left(\mu_t F_\{n0\}\mathbf\{t\} + \mathbf\{F\}_\{t,damp\}\right) +\end\{equation\} + +The tangential force is added to the total normal force (elastic plus damping) to produce the total force +on the particle. The tangential force also acts at the contact point (defined as the center of the overlap region) +to induce a torque on each particle according to: + +\begin\{equation\} +\mathbf\{\tau\}_i = -(R_i - 0.5 \delta) \mathbf\{n\} \times \mathbf\{F\}_t +\end\{equation\} + +\begin\{equation\} +\mathbf\{\tau\}_j = -(R_j - 0.5 \delta) \mathbf\{n\} \times \mathbf\{F\}_t +\end\{equation\} + +For {tangential mindlin}, the "Mindlin"_#Mindlin1949 no-slip solution is used, which differs from the {linear_history} +option by an additional factor of {a}, the radius of the contact region. The tangential force is given by: + +\begin\{equation\} +\mathbf\{F\}_t = -min(\mu_t F_\{n0\}, \|-k_t a \mathbf\{\xi\} + \mathbf\{F\}_\mathrm\{t,damp\}\|) \mathbf\{t\} +\end\{equation\} + +Here, {a} is the radius of the contact region, given by \(a = \delta R\) for all normal contact models, +except for {jkr}, where it is given implicitly by \(\delta = a^2/R - 2\sqrt\{\pi \gamma a/E\}\), +see discussion above. To match the Mindlin solution, one should set \(k_t = 8G\), where +\(G\) is the shear modulus, related to Young's modulus \(E\) by \(G = E/(2(1+\nu))\), where \(\nu\) +is Poisson's ratio. This can also be achieved by specifying {NULL} for \(k_t\), in which case +a normal contact model that specifies material parameters \(E\) and \(\nu\) is required (e.g. {hertz/material}, +{dmt} or {jkr}). In this case, mixing of the shear modulus for different particle types {i} and {j} is done according +to: +\begin\{equation\} +1/G = 2(2-\nu_i)(1+\nu_i)/E_i + 2(2-\nu_j)(1+\nu_j)/E_j +\end\{equation\} + +The {mindlin_rescale} option uses the same form as {mindlin}, but the magnitude of the tangential +displacement is re-scaled as the contact unloads, i.e. if \(a < a_\{t_\{n-1\}\}\): +\begin\{equation\} +\mathbf\{\xi\} = \mathbf\{\xi_\{t_\{n-1\}\}\} \frac\{a\}\{a_\{t_\{n-1\}\}\} +\end\{equation\} + +Here, \(t_\{n-1\}\) indicates the value at the previous time step. This rescaling +accounts for the fact that a decrease in the contact area upon unloading leads to the contact +being unable to support the previous tangential loading, and spurious energy is created +without the rescaling above ("Walton"_#WaltonPC ). See also discussion in "Thornton et al, 2013"_#Thornton2013 +, particularly equation 18(b) of that work and associated discussion. + +:line + +The optional {rolling} keyword enables rolling friction, which resists pure rolling +motion of particles. The options currently supported are: + +{none} +{sds} : \(k_\{roll\}\), \(\gamma_\{roll\}\), \(\mu_\{roll\}\) :ol + +If the {rolling} keyword is not specified, the model defaults to {none}. + +For {rolling sds}, rolling friction is computed via a spring-dashpot-slider, using a +'pseudo-force' formulation, as detailed by "Luding"_#Luding2008. Unlike the formulation +in "Marshall"_#Marshall2009, this allows for the required adjustment of +rolling displacement due to changes in the frame of reference of the contacting pair. +The rolling pseudo-force is computed analogously to the tangential force: + +\begin\{equation\} +\mathbf\{F\}_\{roll,0\} = k_\{roll\} \mathbf\{\xi\}_\{roll\} - \gamma_\{roll\} \mathbf\{v\}_\{roll\} +\end\{equation\} + +Here, \(\mathbf\{v\}_\{roll\} = -R(\mathbf\{\Omega\}_i - \mathbf\{\Omega\}_j) \times \mathbf\{n\}\) is the +relative rolling velocity, as given in "Wang et al"_#Wang2015 and "Luding"_#Luding2008. This differs +from the expressions given by "Kuhn and Bagi"_#Kuhn2004 and used in "Marshall"_#Marshall2009; +see "Wang et al"_#Wang2015 for details. The rolling displacement is given by: + +\begin\{equation\} +\mathbf\{\xi\}_\{roll\} = \int_\{t_0\}^t \mathbf\{v\}_\{roll\} (\tau) \mathrm\{d\} \tau +\end\{equation\} + +A Coulomb friction criterion truncates the rolling pseudo-force if it exceeds a critical value: +\begin\{equation\} +\mathbf\{F\}_\{roll\} = min(\mu_\{roll\} F_\{n,0\}, \|\mathbf\{F\}_\{roll,0\}\|)\mathbf\{k\} +\end\{equation\} + +Here, \(\mathbf\{k\} = \mathbf\{v\}_\{roll\}/\|\mathbf\{v\}_\{roll\}\|\) is the direction of the pseudo-force. +As with tangential displacement, the rolling displacement is rescaled when the critical +force is exceeded, so that the spring length corresponds the critical force. Additionally, the +displacement is adjusted to account for rotations of the frame of reference of the two +contacting particles in a manner analogous to the tangential displacement. + +The rolling pseudo-force does not contribute to the total force on either particle (hence 'pseudo'), +but acts only to induce an equal and opposite torque on each particle, according to: + +\begin\{equation\} +\tau_\{roll,i\} = R_\{eff\} \mathbf\{n\} \times \mathbf\{F\}_\{roll\} +\end\{equation\} + +\begin\{equation\} +\tau_\{roll,j\} = -\tau_\{roll,i\} +\end\{equation\} + +:line + +The optional {twisting} keyword enables twisting friction, which resists +rotation of two contacting particles about the vector \(\mathbf\{n\}\) that connects their +centers. The options currently supported are: + +{none} +{sds} : \(k_\{twist\}\), \(\gamma_\{twist\}\), \(\mu_\{twist\}\) +{marshall} :ol + +If the {twisting} keyword is not specified, the model defaults to {none}. + +For both {twisting sds} and {twisting marshall}, a history-dependent spring-dashpot-slider is used to compute the twisting +torque. Because twisting displacement is a scalar, there is no need to adjust for changes +in the frame of reference due to rotations of the particle pair. The formulation in +"Marshall"_#Marshall2009 therefore provides the most straightforward treatment: + +\begin\{equation\} +\tau_\{twist,0\} = -k_\{twist\}\xi_\{twist\} - \gamma_\{twist\}\Omega_\{twist\} +\end\{equation\} + +Here \(\xi_\{twist\} = \int_\{t_0\}^t \Omega_\{twist\} (\tau) \mathrm\{d\}\tau\) is the twisting +angular displacement, and \(\Omega_\{twist\} = (\mathbf\{\Omega\}_i - \mathbf\{\Omega\}_j) \cdot \mathbf\{n\}\) +is the relative twisting angular velocity. The torque is then truncated according to: + +\begin\{equation\} +\tau_\{twist\} = min(\mu_\{twist\} F_\{n,0\}, \tau_\{twist,0\}) +\end\{equation\} + +Similar to the sliding and rolling displacement, the angular displacement is +rescaled so that it corresponds to the critical value if the twisting torque +exceeds this critical value: + +\begin\{equation\} +\xi_\{twist\} = \frac\{1\}\{k_\{twist\}\} (\mu_\{twist\} F_\{n,0\}sgn(\Omega_\{twist\}) - \gamma_\{twist\}\Omega_\{twist\}) +\end\{equation\} + +For {twisting sds}, the coefficients \(k_\{twist\}, \gamma_\{twist\}\) and \(\mu_\{twist\}\) are +simply the user input parameters that follow the {twisting sds} keywords in the {pair_coeff} command. + +For {twisting_marshall}, the coefficients are expressed in terms of sliding friction coefficients, +as discussed in "Marshall"_#Marshall2009 (see equations 32 and 33 of that work): + +\begin\{equation\} +k_\{twist\} = 0.5k_ta^2 +\end\{equation\} + +\begin\{equation\} +\eta_\{twist\} = 0.5\eta_ta^2 +\end\{equation\} + +\begin\{equation\} +\mu_\{twist\} = \frac\{2\}\{3\}a\mu_t +\end\{equation\} + +Finally, the twisting torque on each particle is given by: + +\begin\{equation\} +\mathbf\{\tau\}_\{twist,i\} = \tau_\{twist\}\mathbf\{n\} +\end\{equation\} + +\begin\{equation\} +\mathbf\{\tau\}_\{twist,j\} = -\mathbf\{\tau\}_\{twist,i\} +\end\{equation\} + +:line + +LAMMPS automatically sets pairwise cutoff values for {pair_style granular} based on particle radii (and in the case +of {jkr} pull-off distances). In the vast majority of situations, this is adequate. +However, a cutoff value can optionally be appended to the {pair_style granular} command to specify +a global cutoff (i.e. a cutoff for all atom types). Additionally, the optional {cutoff} keyword +can be passed to the {pair_coeff} command, followed by a cutoff value. +This will set a pairwise cutoff for the atom types in the {pair_coeff} command. +These options may be useful in some rare cases where the automatic cutoff determination is not sufficient, e.g. +if particle diameters are being modified via the {fix adapt} command. In that case, the global cutoff +specified as part of the {pair_style granular} command is applied to all atom types, unless it is +overridden for a given atom type combination by the {cutoff} value specified in the {pair coeff} command. +If {cutoff} is only specified in the {pair coeff} command and no global +cutoff is appended to the {pair_style granular} command, then LAMMPS will use that cutoff for the specified +atom type combination, and automatically set pairwise cutoffs for the remaining atom types. + +:line + +Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are +functionally the same as the corresponding style without the suffix. +They have been optimized to run faster, depending on your available +hardware, as discussed on the "Speed packages"_Speed_packages.html doc +page. The accelerated styles take the same arguments and should +produce the same results, except for round-off and precision issues. + +These accelerated styles are part of the GPU, USER-INTEL, KOKKOS, +USER-OMP and OPT packages, respectively. They are only enabled if +LAMMPS was built with those packages. See the "Build +package"_Build_package.html doc page for more info. + +You can specify the accelerated styles explicitly in your input script +by including their suffix, or you can use the "-suffix command-line +switch"_Run_options.html when you invoke LAMMPS, or you can use the +"suffix"_suffix.html command in your input script. + +See the "Speed packages"_Speed_packages.html doc page for more +instructions on how to use the accelerated styles effectively. + +:line + +[Mixing, shift, table, tail correction, restart, rRESPA info]: + +The "pair_modify"_pair_modify.html mix, shift, table, and tail options +are not relevant for granular pair styles. + +Mixing of coefficients is carried out using geometric averaging for +most quantities, e.g. if friction coefficient for type 1-type 1 interactions +is set to \(\mu_1\), and friction coefficient for type 2-type 2 interactions +is set to \(\mu_2\), the friction coefficient for type1-type2 interactions +is computed as \(\sqrt\{\mu_1\mu_2\}\) (unless explicitly specified to +a different value by a {pair_coeff 1 2 ...} command. The exception to this is +elastic modulus, only applicable to {hertz/material}, {dmt} and {jkr} normal +contact models. In that case, the effective elastic modulus is computed as: + +\begin\{equation\} +E_\{eff,ij\} = \left(\frac\{1-\nu_i^2\}\{E_i\} + \frac\{1-\nu_j^2\}\{E_j\}\right)^\{-1\} +\end\{equation\} + +If the {i-j} coefficients \(E_\{ij\}\) and \(\nu_\{ij\}\) are explicitly specified, +the effective modulus is computed as: + +\begin\{equation\} +E_\{eff,ij\} = \left(\frac\{1-\nu_\{ij\}^2\}\{E_\{ij\}\} + \frac\{1-\nu_\{ij\}^2\}\{E_\{ij\}\}\right)^\{-1\} +\end\{equation\} + +or + +\begin\{equation\} +E_\{eff,ij\} = \frac\{E_\{ij\}\}\{2(1-\nu_\{ij\})\} +\end\{equation\} + +These pair styles write their information to "binary restart +files"_restart.html, so a pair_style command does not need to be +specified in an input script that reads a restart file. + +These pair styles can only be used via the {pair} keyword of the +"run_style respa"_run_style.html command. They do not support the +{inner}, {middle}, {outer} keywords. + +The single() function of these pair styles returns 0.0 for the energy +of a pairwise interaction, since energy is not conserved in these +dissipative potentials. It also returns only the normal component of +the pairwise interaction force. However, the single() function also +calculates 10 extra pairwise quantities. The first 3 are the +components of the tangential force between particles I and J, acting +on particle I. The 4th is the magnitude of this tangential force. +The next 3 (5-7) are the components of the rolling torque acting on +particle I. The next entry (8) is the magnitude of the rolling torque. +The next entry (9) is the magnitude of the twisting torque acting +about the vector connecting the two particle centers. +The last 3 (10-12) are the components of the vector connecting +the centers of the two particles (x_I - x_J). + +These extra quantities can be accessed by the "compute +pair/local"_compute_pair_local.html command, as {p1}, {p2}, ..., +{p12}. + +:line + +[Restrictions:] + +All the granular pair styles are part of the GRANULAR package. It is +only enabled if LAMMPS was built with that package. See the "Build +package"_Build_package.html doc page for more info. + +These pair styles require that atoms store torque and angular velocity +(omega) as defined by the "atom_style"_atom_style.html. They also +require a per-particle radius is stored. The {sphere} atom style does +all of this. + +This pair style requires you to use the "comm_modify vel +yes"_comm_modify.html command so that velocities are stored by ghost +atoms. + +These pair styles will not restart exactly when using the +"read_restart"_read_restart.html command, though they should provide +statistically similar results. This is because the forces they +compute depend on atom velocities. See the +"read_restart"_read_restart.html command for more details. + +[Related commands:] + +"pair_coeff"_pair_coeff.html +"pair gran/*"_pair_gran.html + +[Default:] + +For the {pair_coeff} settings: {damping viscoelastic}, {rolling none}, {twisting none} + +[References:] + +:link(Brill1996) +[(Brilliantov et al, 1996)] Brilliantov, N. V., Spahn, F., Hertzsch, J. M., & Poschel, T. (1996). +Model for collisions in granular gases. Physical review E, 53(5), 5382. + +:link(Tsuji1992) +[(Tsuji et al, 1992)] Tsuji, Y., Tanaka, T., & Ishida, T. (1992). Lagrangian numerical simulation of plug flow of +cohesionless particles in a horizontal pipe. Powder technology, 71(3), 239-250. + +:link(JKR1971) +[(Johnson et al, 1971)] Johnson, K. L., Kendall, K., & Roberts, A. D. (1971). +Surface energy and the contact of elastic solids. Proc. R. Soc. Lond. A, 324(1558), 301-313. + +:link(DMT1975) +[Derjaguin et al, 1975)] Derjaguin, B. V., Muller, V. M., & Toporov, Y. P. (1975). Effect of contact deformations on the +adhesion of particles. Journal of Colloid and interface science, 53(2), 314-326. + +:link(Luding2008) +[(Luding, 2008)] Luding, S. (2008). Cohesive, frictional powders: contact models for tension. Granular matter, 10(4), 235. + +:link(Marshall2009) +[(Marshall, 2009)] Marshall, J. S. (2009). Discrete-element modeling of particulate aerosol flows. +Journal of Computational Physics, 228(5), 1541-1561. + +:link(Silbert2001) +[(Silbert, 2001)] Silbert, L. E., Ertas, D., Grest, G. S., Halsey, T. C., Levine, D., & Plimpton, S. J. (2001). +Granular flow down an inclined plane: Bagnold scaling and rheology. Physical Review E, 64(5), 051302. + +:link(Kuhn2004) +[(Kuhn and Bagi, 2005)] Kuhn, M. R., & Bagi, K. (2004). Contact rolling and deformation in granular media. +International journal of solids and structures, 41(21), 5793-5820. + +:link(Wang2015) +[(Wang et al, 2015)] Wang, Y., Alonso-Marroquin, F., & Guo, W. W. (2015). +Rolling and sliding in 3-D discrete element models. Particuology, 23, 49-55. + +:link(Thornton1991) +[(Thornton, 1991)] Thornton, C. (1991). Interparticle sliding in the presence of adhesion. +J. Phys. D: Appl. Phys. 24 1942 + +:link(Mindlin1949) +[(Mindlin, 1949)] Mindlin, R. D. (1949). Compliance of elastic bodies in contact. +J. Appl. Mech., ASME 16, 259-268. + +:link(Thornton2013) +[(Thornton et al, 2013)] Thornton, C., Cummins, S. J., & Cleary, P. W. (2013). +An investigation of the comparative behaviour of alternative contact force models +during inelastic collisions. Powder Technology, 233, 30-46. + +:link(WaltonPC) +[(Otis R. Walton)] Walton, O.R., Personal Communication From c26068a57ab28093623a0cd571064b531969b0b6 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 15 Mar 2019 14:24:45 -0400 Subject: [PATCH 31/44] use LAMMPS style indentation for class definitions --- src/GRANULAR/pair_granular.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/GRANULAR/pair_granular.h b/src/GRANULAR/pair_granular.h index ebddc17ade..d85fb5ede9 100644 --- a/src/GRANULAR/pair_granular.h +++ b/src/GRANULAR/pair_granular.h @@ -25,8 +25,8 @@ PairStyle(granular,PairGranular) namespace LAMMPS_NS { -class PairGranular : public Pair{ -public: +class PairGranular : public Pair { + public: PairGranular(class LAMMPS *); ~PairGranular(); void compute(int, int); @@ -63,7 +63,7 @@ public: void allocate(); void transfer_history(double*, double*); -private: + private: int size_history; int *history_transfer_factors; From 28607f156ecb77dd0049d03c9fd18e4113fc3726 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 15 Mar 2019 14:25:14 -0400 Subject: [PATCH 32/44] use C++ style include headers for accessing C library functions --- src/GRANULAR/pair_granular.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/GRANULAR/pair_granular.cpp b/src/GRANULAR/pair_granular.cpp index 97cf02676f..5bddd89ea8 100644 --- a/src/GRANULAR/pair_granular.cpp +++ b/src/GRANULAR/pair_granular.cpp @@ -16,10 +16,10 @@ Dan Bolintineanu (SNL), Ishan Srivastava (SNL), Jeremy Lechman(SNL) Leo Silbert (SNL), Gary Grest (SNL) ----------------------------------------------------------------------- */ -#include -#include -#include -#include +#include +#include +#include +#include #include "pair_granular.h" #include "atom.h" #include "atom_vec.h" From d278cfe230d58959dd89c77e7360d3d819db6486 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 15 Mar 2019 15:10:44 -0400 Subject: [PATCH 33/44] remove pointless recursive self-include --- src/GRANULAR/pair_granular.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/GRANULAR/pair_granular.h b/src/GRANULAR/pair_granular.h index d85fb5ede9..4743d271f5 100644 --- a/src/GRANULAR/pair_granular.h +++ b/src/GRANULAR/pair_granular.h @@ -21,7 +21,6 @@ PairStyle(granular,PairGranular) #define LMP_PAIR_GRANULAR_H #include "pair.h" -#include "pair_granular.h" namespace LAMMPS_NS { From 27510f313c1669c0c03105c7e26fcff6eb9b888a Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 15 Mar 2019 15:24:16 -0400 Subject: [PATCH 34/44] change formatting to closer resemble LAMMPS common source code format style --- src/GRANULAR/fix_wall_gran.cpp | 186 +++++++++++++++------------------ src/GRANULAR/fix_wall_gran.h | 18 ++-- 2 files changed, 91 insertions(+), 113 deletions(-) diff --git a/src/GRANULAR/fix_wall_gran.cpp b/src/GRANULAR/fix_wall_gran.cpp index 3a929771e9..c63a2c0ba8 100644 --- a/src/GRANULAR/fix_wall_gran.cpp +++ b/src/GRANULAR/fix_wall_gran.cpp @@ -54,7 +54,8 @@ enum{NONE,CONSTANT,EQUAL}; enum {NORMAL_HOOKE, NORMAL_HERTZ, HERTZ_MATERIAL, DMT, JKR}; enum {VELOCITY, VISCOELASTIC, TSUJI}; -enum {TANGENTIAL_NOHISTORY, TANGENTIAL_HISTORY, TANGENTIAL_MINDLIN, TANGENTIAL_MINDLIN_RESCALE}; +enum {TANGENTIAL_NOHISTORY, TANGENTIAL_HISTORY, + TANGENTIAL_MINDLIN, TANGENTIAL_MINDLIN_RESCALE}; enum {TWIST_NONE, TWIST_SDS, TWIST_MARSHALL}; enum {ROLL_NONE, ROLL_SDS}; @@ -64,7 +65,8 @@ enum {ROLL_NONE, ROLL_SDS}; /* ---------------------------------------------------------------------- */ FixWallGran::FixWallGran(LAMMPS *lmp, int narg, char **arg) : - Fix(lmp, narg, arg), idregion(NULL), history_one(NULL), fix_rigid(NULL), mass_rigid(NULL) + Fix(lmp, narg, arg), idregion(NULL), history_one(NULL), + fix_rigid(NULL), mass_rigid(NULL) { if (narg < 4) error->all(FLERR,"Illegal fix wall/gran command"); @@ -116,28 +118,25 @@ FixWallGran::FixWallGran(LAMMPS *lmp, int narg, char **arg) : kt /= force->nktv2p; } iarg = 10; - } - else { + } else { iarg = 4; damping_model = VISCOELASTIC; roll_model = twist_model = NONE; - while (iarg < narg){ - if (strcmp(arg[iarg], "hooke") == 0){ + while (iarg < narg) { + if (strcmp(arg[iarg], "hooke") == 0) { if (iarg + 2 >= narg) error->all(FLERR,"Illegal fix wall/gran command, not enough parameters provided for Hooke option"); normal_model = NORMAL_HOOKE; normal_coeffs[0] = force->numeric(FLERR,arg[iarg+1]); //kn normal_coeffs[1] = force->numeric(FLERR,arg[iarg+2]); //damping iarg += 3; - } - else if (strcmp(arg[iarg], "hertz") == 0){ + } else if (strcmp(arg[iarg], "hertz") == 0) { int num_coeffs = 2; if (iarg + num_coeffs >= narg) error->all(FLERR,"Illegal fix wall/gran command, not enough parameters provided for Hertz option"); normal_model = NORMAL_HERTZ; normal_coeffs[0] = force->numeric(FLERR,arg[iarg+1]); //kn normal_coeffs[1] = force->numeric(FLERR,arg[iarg+2]); //damping iarg += num_coeffs+1; - } - else if (strcmp(arg[iarg], "hertz/material") == 0){ + } else if (strcmp(arg[iarg], "hertz/material") == 0) { int num_coeffs = 3; if (iarg + num_coeffs >= narg) error->all(FLERR,"Illegal fix wall/gran command, not enough parameters provided for Hertz option"); normal_model = HERTZ_MATERIAL; @@ -147,8 +146,7 @@ FixWallGran::FixWallGran(LAMMPS *lmp, int narg, char **arg) : normal_coeffs[0] = Emod/(2*(1-poiss))*FOURTHIRDS; normal_coeffs[2] = poiss; iarg += num_coeffs+1; - } - else if (strcmp(arg[iarg], "dmt") == 0){ + } else if (strcmp(arg[iarg], "dmt") == 0) { if (iarg + 4 >= narg) error->all(FLERR,"Illegal fix wall/gran command, not enough parameters provided for Hertz option"); normal_model = DMT; Emod = force->numeric(FLERR,arg[iarg+1]); //E @@ -158,8 +156,7 @@ FixWallGran::FixWallGran(LAMMPS *lmp, int narg, char **arg) : normal_coeffs[2] = poiss; normal_coeffs[3] = force->numeric(FLERR,arg[iarg+4]); //cohesion iarg += 5; - } - else if (strcmp(arg[iarg], "jkr") == 0){ + } else if (strcmp(arg[iarg], "jkr") == 0) { if (iarg + 4 >= narg) error->all(FLERR,"Illegal wall/gran command, not enough parameters provided for JKR option"); beyond_contact = 1; normal_model = JKR; @@ -170,67 +167,57 @@ FixWallGran::FixWallGran(LAMMPS *lmp, int narg, char **arg) : normal_coeffs[2] = poiss; normal_coeffs[3] = force->numeric(FLERR,arg[iarg+4]); //cohesion iarg += 5; - } - else if (strcmp(arg[iarg], "damping") == 0){ + } else if (strcmp(arg[iarg], "damping") == 0) { if (iarg+1 >= narg) error->all(FLERR, "Illegal wall/gran command, not enough parameters provided for damping model"); - if (strcmp(arg[iarg+1], "velocity") == 0){ + if (strcmp(arg[iarg+1], "velocity") == 0) { damping_model = VELOCITY; iarg += 1; - } - else if (strcmp(arg[iarg+1], "viscoelastic") == 0){ + } else if (strcmp(arg[iarg+1], "viscoelastic") == 0) { damping_model = VISCOELASTIC; iarg += 1; - } - else if (strcmp(arg[iarg+1], "tsuji") == 0){ + } else if (strcmp(arg[iarg+1], "tsuji") == 0) { damping_model = TSUJI; iarg += 1; - } - else error->all(FLERR, "Illegal wall/gran command, unrecognized damping model"); + } else error->all(FLERR, "Illegal wall/gran command, unrecognized damping model"); iarg += 1; - } - else if (strcmp(arg[iarg], "tangential") == 0){ + } else if (strcmp(arg[iarg], "tangential") == 0) { if (iarg + 1 >= narg) error->all(FLERR,"Illegal pair_coeff command, must specify tangential model after 'tangential' keyword"); - if (strcmp(arg[iarg+1], "linear_nohistory") == 0){ + if (strcmp(arg[iarg+1], "linear_nohistory") == 0) { if (iarg + 3 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for tangential model"); tangential_model = TANGENTIAL_NOHISTORY; tangential_coeffs[0] = 0; tangential_coeffs[1] = force->numeric(FLERR,arg[iarg+2]); //gammat tangential_coeffs[2] = force->numeric(FLERR,arg[iarg+3]); //friction coeff. iarg += 4; - } - else if ((strcmp(arg[iarg+1], "linear_history") == 0) || + } else if ((strcmp(arg[iarg+1], "linear_history") == 0) || (strcmp(arg[iarg+1], "mindlin") == 0) || - (strcmp(arg[iarg+1], "mindlin_rescale") == 0)){ + (strcmp(arg[iarg+1], "mindlin_rescale") == 0)) { if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for tangential model"); if (strcmp(arg[iarg+1], "linear_history") == 0) tangential_model = TANGENTIAL_HISTORY; else if (strcmp(arg[iarg+1], "mindlin") == 0) tangential_model = TANGENTIAL_MINDLIN; else if (strcmp(arg[iarg+1], "mindlin_rescale") == 0) tangential_model = TANGENTIAL_MINDLIN_RESCALE; if ((tangential_model == TANGENTIAL_MINDLIN || tangential_model == TANGENTIAL_MINDLIN_RESCALE) && - (strcmp(arg[iarg+2], "NULL") == 0)){ - if (normal_model == NORMAL_HERTZ || normal_model == NORMAL_HOOKE){ + (strcmp(arg[iarg+2], "NULL") == 0)) { + if (normal_model == NORMAL_HERTZ || normal_model == NORMAL_HOOKE) { error->all(FLERR, "NULL setting for Mindlin tangential stiffness requires a normal contact model that specifies material properties"); } tangential_coeffs[0] = 4*(2-poiss)*(1+poiss)/Emod; - } - else{ + } else { tangential_coeffs[0] = force->numeric(FLERR,arg[iarg+2]); //kt } tangential_history = 1; tangential_coeffs[1] = force->numeric(FLERR,arg[iarg+3]); //gammat tangential_coeffs[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. iarg += 5; - } - else{ + } else { error->all(FLERR, "Illegal pair_coeff command, tangential model not recognized"); } - } - else if (strcmp(arg[iarg], "rolling") == 0){ + } else if (strcmp(arg[iarg], "rolling") == 0) { if (iarg + 1 >= narg) error->all(FLERR, "Illegal wall/gran command, not enough parameters"); - if (strcmp(arg[iarg+1], "none") == 0){ + if (strcmp(arg[iarg+1], "none") == 0) { roll_model = ROLL_NONE; iarg += 2; - } - else if (strcmp(arg[iarg+1], "sds") == 0){ + } else if (strcmp(arg[iarg+1], "sds") == 0) { if (iarg + 4 >= narg) error->all(FLERR,"Illegal wall/gran command, not enough parameters provided for rolling model"); roll_model = ROLL_SDS; roll_history = 1; @@ -238,23 +225,19 @@ FixWallGran::FixWallGran(LAMMPS *lmp, int narg, char **arg) : roll_coeffs[1] = force->numeric(FLERR,arg[iarg+3]); //gammaR roll_coeffs[2] = force->numeric(FLERR,arg[iarg+4]); //rolling friction coeff. iarg += 5; - } - else{ + } else { error->all(FLERR, "Illegal wall/gran command, rolling friction model not recognized"); } - } - else if (strcmp(arg[iarg], "twisting") == 0){ + } else if (strcmp(arg[iarg], "twisting") == 0) { if (iarg + 1 >= narg) error->all(FLERR, "Illegal wall/gran command, not enough parameters"); - if (strcmp(arg[iarg+1], "none") == 0){ + if (strcmp(arg[iarg+1], "none") == 0) { twist_model = TWIST_NONE; iarg += 2; - } - else if (strcmp(arg[iarg+1], "marshall") == 0){ + } else if (strcmp(arg[iarg+1], "marshall") == 0) { twist_model = TWIST_MARSHALL; twist_history = 1; iarg += 2; - } - else if (strcmp(arg[iarg+1], "sds") == 0){ + } else if (strcmp(arg[iarg+1], "sds") == 0) { if (iarg + 4 >= narg) error->all(FLERR,"Illegal wall/gran command, not enough parameters provided for twist model"); twist_model = TWIST_SDS; twist_history = 1; @@ -262,19 +245,16 @@ FixWallGran::FixWallGran(LAMMPS *lmp, int narg, char **arg) : twist_coeffs[1] = force->numeric(FLERR,arg[iarg+3]); //gammat twist_coeffs[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. iarg += 5; - } - else{ + } else { error->all(FLERR, "Illegal wall/gran command, twisting friction model not recognized"); } - } - else if (strcmp(arg[iarg], "xplane") == 0 || + } else if (strcmp(arg[iarg], "xplane") == 0 || strcmp(arg[iarg], "yplane") == 0 || strcmp(arg[iarg], "zplane") == 0 || strcmp(arg[iarg], "zcylinder") == 0 || - strcmp(arg[iarg], "region") == 0){ + strcmp(arg[iarg], "region") == 0) { break; - } - else{ + } else { error->all(FLERR, "Illegal fix wall/gran command"); } } @@ -352,7 +332,7 @@ FixWallGran::FixWallGran(LAMMPS *lmp, int narg, char **arg) : vshear = force->numeric(FLERR,arg[iarg+2]); wshear = 1; iarg += 3; - } else if (strcmp(arg[iarg],"store_contacts") == 0){ + } else if (strcmp(arg[iarg],"store_contacts") == 0) { peratom_flag = 1; size_peratom_cols = 8; peratom_freq = 1; @@ -407,7 +387,7 @@ FixWallGran::FixWallGran(LAMMPS *lmp, int narg, char **arg) : history_one[i][j] = 0.0; } - if (peratom_flag){ + if (peratom_flag) { int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) for (int m = 0; m < size_peratom_cols; m++) @@ -462,12 +442,12 @@ void FixWallGran::init() if (i < modify->nfix) fix_rigid = modify->fix[i]; tangential_history_index = 0; - if (roll_history){ + if (roll_history) { if (tangential_history) roll_history_index = 3; else roll_history_index = 0; } - if (twist_history){ - if (tangential_history){ + if (twist_history) { + if (tangential_history) { if (roll_history) twist_history_index = 6; else twist_history_index = 3; } @@ -476,17 +456,17 @@ void FixWallGran::init() else twist_history_index = 0; } } - if (normal_model == JKR){ + if (normal_model == JKR) { tangential_history_index += 1; roll_history_index += 1; twist_history_index += 1; } - if (tangential_model == TANGENTIAL_MINDLIN_RESCALE){ + if (tangential_model == TANGENTIAL_MINDLIN_RESCALE) { roll_history_index += 1; twist_history_index += 1; } - if (damping_model == TSUJI){ + if (damping_model == TSUJI) { double cor = normal_coeffs[1]; normal_coeffs[1] = 1.2728-4.2783*cor+11.087*pow(cor,2)-22.348*pow(cor,3)+ 27.467*pow(cor,4)-18.022*pow(cor,5)+ @@ -622,7 +602,7 @@ void FixWallGran::post_force(int /*vflag*/) rsq = dx*dx + dy*dy + dz*dz; double rad; - if (pairstyle == GRANULAR && normal_model == JKR){ + if (pairstyle == GRANULAR && normal_model == JKR) { rad = radius[i] + pulloff_distance(radius[i]); } else @@ -634,8 +614,8 @@ void FixWallGran::post_force(int /*vflag*/) history_one[i][j] = 0.0; } else { - if (pairstyle == GRANULAR && normal_model == JKR && use_history){ - if ((history_one[i][0] == 0) && (rsq > radius[i]*radius[i])){ + if (pairstyle == GRANULAR && normal_model == JKR && use_history) { + if ((history_one[i][0] == 0) && (rsq > radius[i]*radius[i])) { // Particles have not contacted yet, and are outside of contact distance for (j = 0; j < size_history; j++) history_one[i][j] = 0.0; @@ -650,7 +630,7 @@ void FixWallGran::post_force(int /*vflag*/) if (fix_rigid && mass_rigid[i] > 0.0) meff = mass_rigid[i]; // store contact info - if (peratom_flag){ + if (peratom_flag) { array_atom[i][0] = (double)atom->tag[i]; array_atom[i][4] = x[i][0] - dx; array_atom[i][5] = x[i][1] - dy; @@ -764,7 +744,7 @@ void FixWallGran::hooke(double rsq, double dx, double dy, double dz, fy = dy*ccel + fs2; fz = dz*ccel + fs3; - if (peratom_flag){ + if (peratom_flag) { contact[1] = fx; contact[2] = fy; contact[3] = fz; @@ -891,7 +871,7 @@ void FixWallGran::hooke_history(double rsq, double dx, double dy, double dz, f[1] += fy; f[2] += fz; - if (peratom_flag){ + if (peratom_flag) { contact[1] = fx; contact[2] = fy; contact[3] = fz; @@ -1017,7 +997,7 @@ void FixWallGran::hertz_history(double rsq, double dx, double dy, double dz, fy = dy*ccel + fs2; fz = dz*ccel + fs3; - if (peratom_flag){ + if (peratom_flag) { contact[1] = fx; contact[2] = fy; contact[3] = fz; @@ -1056,7 +1036,7 @@ void FixWallGran::granular(double rsq, double dx, double dy, double dz, double fs, fs1, fs2, fs3; double tor1,tor2,tor3; - double relrot1,relrot2,relrot3,vrl1,vrl2,vrl3,vrlmag,vrlmaginv; + double relrot1,relrot2,relrot3,vrl1,vrl2,vrl3; //For JKR double R2, coh, F_pulloff, a, a2, E; @@ -1106,7 +1086,7 @@ void FixWallGran::granular(double rsq, double dx, double dy, double dz, delta = radsum - r; dR = delta*Reff; - if (normal_model == JKR){ + if (normal_model == JKR) { history[0] = 1.0; E *= THREEQUARTERS; R2=Reff*Reff; @@ -1130,7 +1110,7 @@ void FixWallGran::granular(double rsq, double dx, double dy, double dz, else{ knfac = E; //Hooke a = sqrt(dR); - if (normal_model != HOOKE){ + if (normal_model != HOOKE) { Fne *= a; knfac *= a; } @@ -1139,13 +1119,13 @@ void FixWallGran::granular(double rsq, double dx, double dy, double dz, Fne -= 4*MY_PI*normal_coeffs[3]*Reff; } - if (damping_model == VELOCITY){ + if (damping_model == VELOCITY) { damp_normal = 1; } - else if (damping_model == VISCOELASTIC){ + else if (damping_model == VISCOELASTIC) { damp_normal = a*meff; } - else if (damping_model == TSUJI){ + else if (damping_model == TSUJI) { damp_normal = sqrt(meff*knfac); } @@ -1175,11 +1155,11 @@ void FixWallGran::granular(double rsq, double dx, double dy, double dz, vrel = vtr1*vtr1 + vtr2*vtr2 + vtr3*vtr3; vrel = sqrt(vrel); - if (normal_model == JKR){ + if (normal_model == JKR) { F_pulloff = 3*M_PI*coh*Reff; Fncrit = fabs(Fne + 2*F_pulloff); } - else if (normal_model == DMT){ + else if (normal_model == DMT) { F_pulloff = 4*M_PI*coh*Reff; Fncrit = fabs(Fne + 2*F_pulloff); } @@ -1197,13 +1177,13 @@ void FixWallGran::granular(double rsq, double dx, double dy, double dz, int thist1 = thist0 + 1; int thist2 = thist1 + 1; - if (tangential_history){ - if (tangential_model == TANGENTIAL_MINDLIN){ + if (tangential_history) { + if (tangential_model == TANGENTIAL_MINDLIN) { k_tangential *= a; } - else if (tangential_model == TANGENTIAL_MINDLIN_RESCALE){ + else if (tangential_model == TANGENTIAL_MINDLIN_RESCALE) { k_tangential *= a; - if (a < history[3]){ //On unloading, rescale the shear displacements + if (a < history[3]) { //On unloading, rescale the shear displacements double factor = a/history[thist2+1]; history[thist0] *= factor; history[thist1] *= factor; @@ -1218,7 +1198,7 @@ void FixWallGran::granular(double rsq, double dx, double dy, double dz, if (history_update) { rsht = history[thist0]*nx + history[thist1]*ny + history[thist2]*nz; if (fabs(rsht) < EPSILON) rsht = 0; - if (rsht > 0){ + if (rsht > 0) { scalefac = shrmag/(shrmag - rsht); //if rhst == shrmag, contacting pair has rotated 90 deg. in one step, in which case you deserve a crash! history[thist0] -= rsht*nx; history[thist1] -= rsht*ny; @@ -1266,7 +1246,7 @@ void FixWallGran::granular(double rsq, double dx, double dy, double dz, // Rolling resistance //**************************************** - if (roll_model != ROLL_NONE){ + if (roll_model != ROLL_NONE) { relrot1 = omega[0]; relrot2 = omega[1]; relrot3 = omega[2]; @@ -1277,9 +1257,6 @@ void FixWallGran::granular(double rsq, double dx, double dy, double dz, vrl1 = Reff*(relrot2*nz - relrot3*ny); //- 0.5*((radj-radi)/radsum)*vtr1; vrl2 = Reff*(relrot3*nx - relrot1*nz); //- 0.5*((radj-radi)/radsum)*vtr2; vrl3 = Reff*(relrot1*ny - relrot2*nx); //- 0.5*((radj-radi)/radsum)*vtr3; - vrlmag = sqrt(vrl1*vrl1+vrl2*vrl2+vrl3*vrl3); - if (vrlmag != 0.0) vrlmaginv = 1.0/vrlmag; - else vrlmaginv = 0.0; int rhist0 = roll_history_index; int rhist1 = rhist0 + 1; @@ -1292,9 +1269,9 @@ void FixWallGran::granular(double rsq, double dx, double dy, double dz, rolldotn = history[rhist0]*nx + history[rhist1]*ny + history[rhist2]*nz; - if (history_update){ + if (history_update) { if (fabs(rolldotn) < EPSILON) rolldotn = 0; - if (rolldotn > 0){ //Rotate into tangential plane + if (rolldotn > 0) { //Rotate into tangential plane scalefac = rollmag/(rollmag - rolldotn); history[rhist0] -= rolldotn*nx; history[rhist1] -= rolldotn*ny; @@ -1334,9 +1311,9 @@ void FixWallGran::granular(double rsq, double dx, double dy, double dz, //**************************************** // Twisting torque, including history effects //**************************************** - if (twist_model != TWIST_NONE){ + if (twist_model != TWIST_NONE) { magtwist = relrot1*nx + relrot2*ny + relrot3*nz; //Omega_T (eq 29 of Marshall) - if (twist_model == TWIST_MARSHALL){ + if (twist_model == TWIST_MARSHALL) { k_twist = 0.5*k_tangential*a*a;; //eq 32 of Marshall paper damp_twist = 0.5*damp_tangential*a*a; mu_twist = TWOTHIRDS*a*tangential_coeffs[2]; @@ -1346,7 +1323,7 @@ void FixWallGran::granular(double rsq, double dx, double dy, double dz, damp_twist = twist_coeffs[1]; mu_twist = twist_coeffs[2]; } - if (history_update){ + if (history_update) { history[twist_history_index] += magtwist*dt; } magtortwist = -k_twist*history[twist_history_index] - damp_twist*magtwist;//M_t torque (eq 30) @@ -1363,7 +1340,7 @@ void FixWallGran::granular(double rsq, double dx, double dy, double dz, fy = ny*Fntot + fs2; fz = nz*Fntot + fs3; - if (peratom_flag){ + if (peratom_flag) { contact[1] = fx; contact[2] = fy; contact[3] = fz; @@ -1381,7 +1358,7 @@ void FixWallGran::granular(double rsq, double dx, double dy, double dz, torque[1] -= radius*tor2; torque[2] -= radius*tor3; - if (twist_model != TWIST_NONE){ + if (twist_model != TWIST_NONE) { tortwist1 = magtortwist * nx; tortwist2 = magtortwist * ny; tortwist3 = magtortwist * nz; @@ -1391,7 +1368,7 @@ void FixWallGran::granular(double rsq, double dx, double dy, double dz, torque[2] += tortwist3; } - if (roll_model != ROLL_NONE){ + if (roll_model != ROLL_NONE) { torroll1 = Reff*(ny*fr3 - nz*fr2); //n cross fr torroll2 = Reff*(nz*fr1 - nx*fr3); torroll3 = Reff*(nx*fr2 - ny*fr1); @@ -1425,7 +1402,7 @@ double FixWallGran::memory_usage() void FixWallGran::grow_arrays(int nmax) { if (use_history) memory->grow(history_one,nmax,size_history,"fix_wall_gran:history_one"); - if (peratom_flag){ + if (peratom_flag) { memory->grow(array_atom,nmax,size_peratom_cols,"fix_wall_gran:array_atom"); } } @@ -1439,7 +1416,7 @@ void FixWallGran::copy_arrays(int i, int j, int /*delflag*/) if (use_history) for (int m = 0; m < size_history; m++) history_one[j][m] = history_one[i][m]; - if (peratom_flag){ + if (peratom_flag) { for (int m = 0; m < size_peratom_cols; m++) array_atom[j][m] = array_atom[i][m]; } @@ -1454,7 +1431,7 @@ void FixWallGran::set_arrays(int i) if (use_history) for (int m = 0; m < size_history; m++) history_one[i][m] = 0; - if (peratom_flag){ + if (peratom_flag) { for (int m = 0; m < size_peratom_cols; m++) array_atom[i][m] = 0; } @@ -1467,11 +1444,11 @@ void FixWallGran::set_arrays(int i) int FixWallGran::pack_exchange(int i, double *buf) { int n = 0; - if (use_history){ + if (use_history) { for (int m = 0; m < size_history; m++) buf[n++] = history_one[i][m]; } - if (peratom_flag){ + if (peratom_flag) { for (int m = 0; m < size_peratom_cols; m++) buf[n++] = array_atom[i][m]; } @@ -1485,11 +1462,11 @@ int FixWallGran::pack_exchange(int i, double *buf) int FixWallGran::unpack_exchange(int nlocal, double *buf) { int n = 0; - if (use_history){ + if (use_history) { for (int m = 0; m < size_history; m++) history_one[nlocal][m] = buf[n++]; } - if (peratom_flag){ + if (peratom_flag) { for (int m = 0; m < size_peratom_cols; m++) array_atom[nlocal][m] = buf[n++]; } @@ -1558,7 +1535,8 @@ void FixWallGran::reset_dt() dt = update->dt; } -double FixWallGran::pulloff_distance(double radius){ +double FixWallGran::pulloff_distance(double radius) +{ double coh, E, a, dist; coh = normal_coeffs[3]; E = normal_coeffs[0]*THREEQUARTERS; diff --git a/src/GRANULAR/fix_wall_gran.h b/src/GRANULAR/fix_wall_gran.h index 07c6c131cf..a81cdcb6c8 100644 --- a/src/GRANULAR/fix_wall_gran.h +++ b/src/GRANULAR/fix_wall_gran.h @@ -46,17 +46,17 @@ class FixWallGran : public Fix { virtual int maxsize_restart(); void reset_dt(); - void hooke(double, double, double, double, double *, - double *, double *, double *, double *, double, double, double*); + void hooke(double, double, double, double, double *, double *, + double *, double *, double *, double, double, double*); void hooke_history(double, double, double, double, double *, - double *, double *, double *, double *, double, double, - double *, double *); - void hertz_history(double, double, double, double, double *, double, - double *, double *, double *, double *, double, double, - double *, double *); + double *, double *, double *, double *, double, + double, double *, double *); + void hertz_history(double, double, double, double, double *, + double, double *, double *, double *, double *, + double, double, double *, double *); void granular(double, double, double, double, double *, double, - double *, double *, double *, double *, double, double, - double *, double *); + double *, double *, double *, double *, double, + double, double *, double *); double pulloff_distance(double); From 05a5ecd4d4cd17f624835602b9b221d70bdf42f6 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 15 Mar 2019 15:24:41 -0400 Subject: [PATCH 35/44] silence compiler warnings about unused parameters --- src/GRANULAR/pair_granular.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/GRANULAR/pair_granular.cpp b/src/GRANULAR/pair_granular.cpp index 5bddd89ea8..427bbbd7fa 100644 --- a/src/GRANULAR/pair_granular.cpp +++ b/src/GRANULAR/pair_granular.cpp @@ -1241,7 +1241,8 @@ void PairGranular::reset_dt() /* ---------------------------------------------------------------------- */ double PairGranular::single(int i, int j, int itype, int jtype, - double rsq, double factor_coul, double factor_lj, double &fforce) + double rsq, double /* factor_coul */, + double /* factor_lj */, double &fforce) { double radi,radj,radsum; double r,rinv,delx,dely,delz, nx, ny, nz, Reff; @@ -1604,7 +1605,7 @@ double PairGranular::single(int i, int j, int itype, int jtype, /* ---------------------------------------------------------------------- */ int PairGranular::pack_forward_comm(int n, int *list, double *buf, - int pbc_flag, int *pbc) + int /* pbc_flag */, int * /* pbc */) { int i,j,m; From 4cd0ea61f24012477e58f2a315f7f280cb245af3 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 15 Mar 2019 15:33:15 -0400 Subject: [PATCH 36/44] change source code format style to be more like other LAMMPS sources --- src/GRANULAR/pair_granular.cpp | 296 ++++++++++++++------------------- 1 file changed, 122 insertions(+), 174 deletions(-) diff --git a/src/GRANULAR/pair_granular.cpp b/src/GRANULAR/pair_granular.cpp index 427bbbd7fa..b3046788e0 100644 --- a/src/GRANULAR/pair_granular.cpp +++ b/src/GRANULAR/pair_granular.cpp @@ -147,18 +147,18 @@ void PairGranular::compute(int eflag, int vflag) double mi,mj,meff; double relrot1,relrot2,relrot3,vrl1,vrl2,vrl3; - //For JKR + // For JKR double R2, coh, F_pulloff, delta_pulloff, dist_pulloff, a, a2, E; double t0, t1, t2, t3, t4, t5, t6; double sqrt1, sqrt2, sqrt3; - //Rolling + // Rolling double k_roll, damp_roll; double torroll1, torroll2, torroll3; double rollmag, rolldotn, scalefac; double fr, fr1, fr2, fr3; - //Twisting + // Twisting double k_twist, damp_twist, mu_twist; double signtwist, magtwist, magtortwist, Mtcrit; double tortwist1, tortwist2, tortwist3; @@ -180,7 +180,7 @@ void PairGranular::compute(int eflag, int vflag) // body[i] = which body atom I is in, -1 if none // mass_body = mass of each rigid body - if (fix_rigid && neighbor->ago == 0){ + if (fix_rigid && neighbor->ago == 0) { int tmp; int *body = (int *) fix_rigid->extract("body",tmp); double *mass_body = (double *) fix_rigid->extract("masstotal",tmp); @@ -211,7 +211,7 @@ void PairGranular::compute(int eflag, int vflag) ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; - if (use_history){ + if (use_history) { firsttouch = fix_history->firstflag; firsthistory = fix_history->firstvalue; } @@ -224,14 +224,14 @@ void PairGranular::compute(int eflag, int vflag) ztmp = x[i][2]; itype = type[i]; radi = radius[i]; - if (use_history){ + if (use_history) { touch = firsttouch[i]; allhistory = firsthistory[i]; } jlist = firstneigh[i]; jnum = numneigh[i]; - for (jj = 0; jj < jnum; jj++){ + for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; j &= NEIGHMASK; @@ -247,33 +247,30 @@ void PairGranular::compute(int eflag, int vflag) Reff = radi*radj/radsum; touchflag = false; - if (normal_model[itype][jtype] == JKR){ + if (normal_model[itype][jtype] == JKR) { E *= THREEQUARTERS; - if (touch[jj]){ + if (touch[jj]) { R2 = Reff*Reff; coh = normal_coeffs[itype][jtype][3]; a = cbrt(9.0*M_PI*coh*R2/(4*E)); delta_pulloff = a*a/Reff - 2*sqrt(M_PI*coh*a/E); dist_pulloff = radsum-delta_pulloff; touchflag = (rsq < dist_pulloff*dist_pulloff); - } - else{ + } else { touchflag = (rsq < radsum*radsum); } - } - else{ + } else { touchflag = (rsq < radsum*radsum); } - if (!touchflag){ + if (!touchflag) { // unset non-touching neighbors - if (use_history){ + if (use_history) { touch[jj] = 0; history = &allhistory[size_history*jj]; for (int k = 0; k < size_history; k++) history[k] = 0.0; } - } - else{ + } else { r = sqrt(rsq); rinv = 1.0/r; @@ -311,7 +308,7 @@ void PairGranular::compute(int eflag, int vflag) delta = radsum - r; dR = delta*Reff; - if (normal_model[itype][jtype] == JKR){ + if (normal_model[itype][jtype] == JKR) { touch[jj] = 1; R2=Reff*Reff; coh = normal_coeffs[itype][jtype][3]; @@ -330,12 +327,11 @@ void PairGranular::compute(int eflag, int vflag) a2 = a*a; knfac = normal_coeffs[itype][jtype][0]*a; Fne = knfac*a2/Reff - TWOPI*a2*sqrt(4*coh*E/(M_PI*a)); - } - else{ + } else { knfac = E; //Hooke Fne = knfac*delta; a = sqrt(dR); - if (normal_model[itype][jtype] != HOOKE){ + if (normal_model[itype][jtype] != HOOKE) { Fne *= a; knfac *= a; } @@ -344,13 +340,11 @@ void PairGranular::compute(int eflag, int vflag) } //Consider restricting Hooke to only have 'velocity' as an option for damping? - if (damping_model[itype][jtype] == VELOCITY){ + if (damping_model[itype][jtype] == VELOCITY) { damp_normal = 1; - } - else if (damping_model[itype][jtype] == VISCOELASTIC){ + } else if (damping_model[itype][jtype] == VISCOELASTIC) { damp_normal = a*meff; - } - else if (damping_model[itype][jtype] == TSUJI){ + } else if (damping_model[itype][jtype] == TSUJI) { damp_normal = sqrt(meff*knfac); } @@ -381,20 +375,18 @@ void PairGranular::compute(int eflag, int vflag) vrel = sqrt(vrel); // If any history is needed: - if (use_history){ + if (use_history) { touch[jj] = 1; history = &allhistory[size_history*jj]; } - if (normal_model[itype][jtype] == JKR){ + if (normal_model[itype][jtype] == JKR) { F_pulloff = 3*M_PI*coh*Reff; Fncrit = fabs(Fne + 2*F_pulloff); - } - else if (normal_model[itype][jtype] == DMT){ + } else if (normal_model[itype][jtype] == DMT) { F_pulloff = 4*M_PI*coh*Reff; Fncrit = fabs(Fne + 2*F_pulloff); - } - else{ + } else { Fncrit = fabs(Fntot); } @@ -404,13 +396,12 @@ void PairGranular::compute(int eflag, int vflag) k_tangential = tangential_coeffs[itype][jtype][0]; damp_tangential = tangential_coeffs[itype][jtype][1]*damp_normal_prefactor; - if (tangential_history){ - if (tangential_model[itype][jtype] == TANGENTIAL_MINDLIN){ + if (tangential_history) { + if (tangential_model[itype][jtype] == TANGENTIAL_MINDLIN) { k_tangential *= a; - } - else if (tangential_model[itype][jtype] == TANGENTIAL_MINDLIN_RESCALE){ + } else if (tangential_model[itype][jtype] == TANGENTIAL_MINDLIN_RESCALE) { k_tangential *= a; - if (a < history[3]){ //On unloading, rescale the shear displacements + if (a < history[3]) { //On unloading, rescale the shear displacements double factor = a/history[3]; history[0] *= factor; history[1] *= factor; @@ -422,7 +413,7 @@ void PairGranular::compute(int eflag, int vflag) if (historyupdate) { rsht = history[0]*nx + history[1]*ny + history[2]*nz; if (fabs(rsht) < EPSILON) rsht = 0; - if (rsht > 0){ + if (rsht > 0) { shrmag = sqrt(history[0]*history[0] + history[1]*history[1] + history[2]*history[2]); scalefac = shrmag/(shrmag - rsht); //if rsht == shrmag, contacting pair has rotated 90 deg. in one step, in which case you deserve a crash! @@ -461,8 +452,7 @@ void PairGranular::compute(int eflag, int vflag) fs3 *= Fscrit/fs; } else fs1 = fs2 = fs3 = 0.0; } - } - else{ //Classic pair gran/hooke (no history) + } else{ //Classic pair gran/hooke (no history) fs = meff*damp_tangential*vrel; if (vrel != 0.0) Ft = MIN(Fne,fs) / vrel; else Ft = 0.0; @@ -475,7 +465,7 @@ void PairGranular::compute(int eflag, int vflag) // Rolling resistance //**************************************** - if (roll_model[itype][jtype] != ROLL_NONE){ + if (roll_model[itype][jtype] != ROLL_NONE) { relrot1 = omega[i][0] - omega[j][0]; relrot2 = omega[i][1] - omega[j][1]; relrot3 = omega[i][2] - omega[j][2]; @@ -492,9 +482,9 @@ void PairGranular::compute(int eflag, int vflag) int rhist2 = rhist1 + 1; rolldotn = history[rhist0]*nx + history[rhist1]*ny + history[rhist2]*nz; - if (historyupdate){ + if (historyupdate) { if (fabs(rolldotn) < EPSILON) rolldotn = 0; - if (rolldotn > 0){ //Rotate into tangential plane + if (rolldotn > 0) { //Rotate into tangential plane rollmag = sqrt(history[rhist0]*history[rhist0] + history[rhist1]*history[rhist1] + history[rhist2]*history[rhist2]); @@ -540,19 +530,18 @@ void PairGranular::compute(int eflag, int vflag) //**************************************** // Twisting torque, including history effects //**************************************** - if (twist_model[itype][jtype] != TWIST_NONE){ + if (twist_model[itype][jtype] != TWIST_NONE) { magtwist = relrot1*nx + relrot2*ny + relrot3*nz; //Omega_T (eq 29 of Marshall) - if (twist_model[itype][jtype] == TWIST_MARSHALL){ + if (twist_model[itype][jtype] == TWIST_MARSHALL) { k_twist = 0.5*k_tangential*a*a;; //eq 32 of Marshall paper damp_twist = 0.5*damp_tangential*a*a; mu_twist = TWOTHIRDS*a*tangential_coeffs[itype][jtype][2]; - } - else{ + } else { k_twist = twist_coeffs[itype][jtype][0]; damp_twist = twist_coeffs[itype][jtype][1]; mu_twist = twist_coeffs[itype][jtype][2]; } - if (historyupdate){ + if (historyupdate) { history[twist_history_index] += magtwist*dt; } magtortwist = -k_twist*history[twist_history_index] - damp_twist*magtwist;//M_t torque (eq 30) @@ -582,7 +571,7 @@ void PairGranular::compute(int eflag, int vflag) torque[i][1] -= dist_to_contact*tor2; torque[i][2] -= dist_to_contact*tor3; - if (twist_model[itype][jtype] != TWIST_NONE){ + if (twist_model[itype][jtype] != TWIST_NONE) { tortwist1 = magtortwist * nx; tortwist2 = magtortwist * ny; tortwist3 = magtortwist * nz; @@ -592,7 +581,7 @@ void PairGranular::compute(int eflag, int vflag) torque[i][2] += tortwist3; } - if (roll_model[itype][jtype] != ROLL_NONE){ + if (roll_model[itype][jtype] != ROLL_NONE) { torroll1 = Reff*(ny*fr3 - nz*fr2); //n cross fr torroll2 = Reff*(nz*fr1 - nx*fr3); torroll3 = Reff*(nx*fr2 - ny*fr1); @@ -612,12 +601,12 @@ void PairGranular::compute(int eflag, int vflag) torque[j][1] -= dist_to_contact*tor2; torque[j][2] -= dist_to_contact*tor3; - if (twist_model[itype][jtype] != TWIST_NONE){ + if (twist_model[itype][jtype] != TWIST_NONE) { torque[j][0] -= tortwist1; torque[j][1] -= tortwist2; torque[j][2] -= tortwist3; } - if (roll_model[itype][jtype] != ROLL_NONE){ + if (roll_model[itype][jtype] != ROLL_NONE) { torque[j][0] -= torroll1; torque[j][1] -= torroll2; torque[j][2] -= torroll3; @@ -673,10 +662,9 @@ void PairGranular::allocate() void PairGranular::settings(int narg, char **arg) { - if (narg == 1){ + if (narg == 1) { cutoff_global = force->numeric(FLERR,arg[0]); - } - else{ + } else { cutoff_global = -1; //Will be set based on particle sizes, model choice } @@ -715,23 +703,21 @@ void PairGranular::coeff(int narg, char **arg) damping_model_one = VISCOELASTIC; int iarg = 2; - while (iarg < narg){ - if (strcmp(arg[iarg], "hooke") == 0){ + while (iarg < narg) { + if (strcmp(arg[iarg], "hooke") == 0) { if (iarg + 2 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hooke option"); normal_model_one = HOOKE; normal_coeffs_one[0] = force->numeric(FLERR,arg[iarg+1]); //kn normal_coeffs_one[1] = force->numeric(FLERR,arg[iarg+2]); //damping iarg += 3; - } - else if (strcmp(arg[iarg], "hertz") == 0){ + } else if (strcmp(arg[iarg], "hertz") == 0) { int num_coeffs = 2; if (iarg + num_coeffs >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hertz option"); normal_model_one = HERTZ; normal_coeffs_one[0] = force->numeric(FLERR,arg[iarg+1]); //kn normal_coeffs_one[1] = force->numeric(FLERR,arg[iarg+2]); //damping iarg += num_coeffs+1; - } - else if (strcmp(arg[iarg], "hertz/material") == 0){ + } else if (strcmp(arg[iarg], "hertz/material") == 0) { int num_coeffs = 3; if (iarg + num_coeffs >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hertz/material option"); normal_model_one = HERTZ_MATERIAL; @@ -739,8 +725,7 @@ void PairGranular::coeff(int narg, char **arg) normal_coeffs_one[1] = force->numeric(FLERR,arg[iarg+2]); //damping normal_coeffs_one[2] = force->numeric(FLERR,arg[iarg+3]); //Poisson's ratio iarg += num_coeffs+1; - } - else if (strcmp(arg[iarg], "dmt") == 0){ + } else if (strcmp(arg[iarg], "dmt") == 0) { if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hertz option"); normal_model_one = DMT; normal_coeffs_one[0] = force->numeric(FLERR,arg[iarg+1]); //E @@ -748,8 +733,7 @@ void PairGranular::coeff(int narg, char **arg) normal_coeffs_one[2] = force->numeric(FLERR,arg[iarg+3]); //Poisson's ratio normal_coeffs_one[3] = force->numeric(FLERR,arg[iarg+4]); //cohesion iarg += 5; - } - else if (strcmp(arg[iarg], "jkr") == 0){ + } else if (strcmp(arg[iarg], "jkr") == 0) { if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for JKR option"); beyond_contact = 1; normal_model_one = JKR; @@ -758,67 +742,57 @@ void PairGranular::coeff(int narg, char **arg) normal_coeffs_one[2] = force->numeric(FLERR,arg[iarg+3]); //Poisson's ratio normal_coeffs_one[3] = force->numeric(FLERR,arg[iarg+4]); //cohesion iarg += 5; - } - else if (strcmp(arg[iarg], "damping") == 0){ + } else if (strcmp(arg[iarg], "damping") == 0) { if (iarg+1 >= narg) error->all(FLERR, "Illegal pair_coeff command, not enough parameters provided for damping model"); - if (strcmp(arg[iarg+1], "velocity") == 0){ + if (strcmp(arg[iarg+1], "velocity") == 0) { damping_model_one = VELOCITY; iarg += 1; - } - else if (strcmp(arg[iarg+1], "viscoelastic") == 0){ + } else if (strcmp(arg[iarg+1], "viscoelastic") == 0) { damping_model_one = VISCOELASTIC; iarg += 1; - } - else if (strcmp(arg[iarg+1], "tsuji") == 0){ + } else if (strcmp(arg[iarg+1], "tsuji") == 0) { damping_model_one = TSUJI; iarg += 1; - } - else error->all(FLERR, "Illegal pair_coeff command, unrecognized damping model"); + } else error->all(FLERR, "Illegal pair_coeff command, unrecognized damping model"); iarg += 1; - } - else if (strcmp(arg[iarg], "tangential") == 0){ + } else if (strcmp(arg[iarg], "tangential") == 0) { if (iarg + 1 >= narg) error->all(FLERR,"Illegal pair_coeff command, must specify tangential model after 'tangential' keyword"); - if (strcmp(arg[iarg+1], "linear_nohistory") == 0){ + if (strcmp(arg[iarg+1], "linear_nohistory") == 0) { if (iarg + 3 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for tangential model"); tangential_model_one = TANGENTIAL_NOHISTORY; tangential_coeffs_one[0] = 0; tangential_coeffs_one[1] = force->numeric(FLERR,arg[iarg+2]); //gammat tangential_coeffs_one[2] = force->numeric(FLERR,arg[iarg+3]); //friction coeff. iarg += 4; - } - else if ((strcmp(arg[iarg+1], "linear_history") == 0) || + } else if ((strcmp(arg[iarg+1], "linear_history") == 0) || (strcmp(arg[iarg+1], "mindlin") == 0) || - (strcmp(arg[iarg+1], "mindlin_rescale") == 0)){ + (strcmp(arg[iarg+1], "mindlin_rescale") == 0)) { if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for tangential model"); if (strcmp(arg[iarg+1], "linear_history") == 0) tangential_model_one = TANGENTIAL_HISTORY; else if (strcmp(arg[iarg+1], "mindlin") == 0) tangential_model_one = TANGENTIAL_MINDLIN; else if (strcmp(arg[iarg+1], "mindlin_rescale") == 0) tangential_model_one = TANGENTIAL_MINDLIN_RESCALE; tangential_history = 1; if ((tangential_model_one == TANGENTIAL_MINDLIN || tangential_model_one == TANGENTIAL_MINDLIN_RESCALE) && - (strcmp(arg[iarg+2], "NULL") == 0)){ - if (normal_model_one == HERTZ || normal_model_one == HOOKE){ + (strcmp(arg[iarg+2], "NULL") == 0)) { + if (normal_model_one == HERTZ || normal_model_one == HOOKE) { error->all(FLERR, "NULL setting for Mindlin tangential stiffness requires a normal contact model that specifies material properties"); } tangential_coeffs_one[0] = -1; - } - else{ + } else { tangential_coeffs_one[0] = force->numeric(FLERR,arg[iarg+2]); //kt } tangential_coeffs_one[1] = force->numeric(FLERR,arg[iarg+3]); //gammat tangential_coeffs_one[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. iarg += 5; - } - else{ + } else { error->all(FLERR, "Illegal pair_coeff command, tangential model not recognized"); } - } - else if (strcmp(arg[iarg], "rolling") == 0){ + } else if (strcmp(arg[iarg], "rolling") == 0) { if (iarg + 1 >= narg) error->all(FLERR, "Illegal pair_coeff command, not enough parameters"); - if (strcmp(arg[iarg+1], "none") == 0){ + if (strcmp(arg[iarg+1], "none") == 0) { roll_model_one = ROLL_NONE; iarg += 2; - } - else if (strcmp(arg[iarg+1], "sds") == 0){ + } else if (strcmp(arg[iarg+1], "sds") == 0) { if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for rolling model"); roll_model_one = ROLL_SDS; roll_history = 1; @@ -826,23 +800,19 @@ void PairGranular::coeff(int narg, char **arg) roll_coeffs_one[1] = force->numeric(FLERR,arg[iarg+3]); //gammaR roll_coeffs_one[2] = force->numeric(FLERR,arg[iarg+4]); //rolling friction coeff. iarg += 5; - } - else{ + } else { error->all(FLERR, "Illegal pair_coeff command, rolling friction model not recognized"); } - } - else if (strcmp(arg[iarg], "twisting") == 0){ + } else if (strcmp(arg[iarg], "twisting") == 0) { if (iarg + 1 >= narg) error->all(FLERR, "Illegal pair_coeff command, not enough parameters"); - if (strcmp(arg[iarg+1], "none") == 0){ + if (strcmp(arg[iarg+1], "none") == 0) { twist_model_one = TWIST_NONE; iarg += 2; - } - else if (strcmp(arg[iarg+1], "marshall") == 0){ + } else if (strcmp(arg[iarg+1], "marshall") == 0) { twist_model_one = TWIST_MARSHALL; twist_history = 1; iarg += 2; - } - else if (strcmp(arg[iarg+1], "sds") == 0){ + } else if (strcmp(arg[iarg+1], "sds") == 0) { if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for twist model"); twist_model_one = TWIST_SDS; twist_history = 1; @@ -850,16 +820,13 @@ void PairGranular::coeff(int narg, char **arg) twist_coeffs_one[1] = force->numeric(FLERR,arg[iarg+3]); //gammat twist_coeffs_one[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. iarg += 5; - } - else{ + } else { error->all(FLERR, "Illegal pair_coeff command, twisting friction model not recognized"); } - } - else if (strcmp(arg[iarg], "cutoff") == 0){ + } else if (strcmp(arg[iarg], "cutoff") == 0) { if (iarg + 1 >= narg) error->all(FLERR, "Illegal pair_coeff command, not enough parameters"); cutoff_one = force->numeric(FLERR,arg[iarg+1]); - } - else error->all(FLERR, "Illegal pair coeff command"); + } else error->all(FLERR, "Illegal pair coeff command"); } //It is an error not to specify normal or tangential model @@ -867,25 +834,23 @@ void PairGranular::coeff(int narg, char **arg) int count = 0; double damp; - if (damping_model_one == TSUJI){ + if (damping_model_one == TSUJI) { double cor; cor = normal_coeffs_one[1]; damp = 1.2728-4.2783*cor+11.087*pow(cor,2)-22.348*pow(cor,3)+ 27.467*pow(cor,4)-18.022*pow(cor,5)+ 4.8218*pow(cor,6); - } - else damp = normal_coeffs_one[1]; + } else damp = normal_coeffs_one[1]; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { normal_model[i][j] = normal_model[j][i] = normal_model_one; normal_coeffs[i][j][1] = normal_coeffs[j][i][1] = damp; - if (normal_model_one != HERTZ && normal_model_one != HOOKE){ + if (normal_model_one != HERTZ && normal_model_one != HOOKE) { Emod[i][j] = Emod[j][i] = normal_coeffs_one[0]; poiss[i][j] = poiss[j][i] = normal_coeffs_one[2]; normal_coeffs[i][j][0] = normal_coeffs[j][i][0] = FOURTHIRDS*mix_stiffnessE(Emod[i][j], Emod[i][j], poiss[i][j], poiss[i][j]); - } - else{ + } else { normal_coeffs[i][j][0] = normal_coeffs[j][i][0] = normal_coeffs_one[0]; } if ((normal_model_one == JKR) || (normal_model_one == DMT)) @@ -894,10 +859,9 @@ void PairGranular::coeff(int narg, char **arg) damping_model[i][j] = damping_model[j][i] = damping_model_one; tangential_model[i][j] = tangential_model[j][i] = tangential_model_one; - if (tangential_coeffs_one[0] == -1){ + if (tangential_coeffs_one[0] == -1) { tangential_coeffs[i][j][0] = tangential_coeffs[j][i][0] = 8*mix_stiffnessG(Emod[i][j], Emod[i][j], poiss[i][j], poiss[i][j]); - } - else{ + } else { tangential_coeffs[i][j][0] = tangential_coeffs[j][i][0] = tangential_coeffs_one[0]; } for (int k = 1; k < 3; k++) @@ -949,23 +913,22 @@ void PairGranular::init_style() size_history = 3*tangential_history + 3*roll_history + twist_history; //Determine location of tangential/roll/twist histories in array - if (roll_history){ + if (roll_history) { if (tangential_history) roll_history_index = 3; else roll_history_index = 0; } - if (twist_history){ - if (tangential_history){ + if (twist_history) { + if (tangential_history) { if (roll_history) twist_history_index = 6; else twist_history_index = 3; - } - else{ + } else { if (roll_history) twist_history_index = 3; else twist_history_index = 0; } } for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) - if (tangential_model[i][j] == TANGENTIAL_MINDLIN_RESCALE){ + if (tangential_model[i][j] == TANGENTIAL_MINDLIN_RESCALE) { size_history += 1; roll_history_index += 1; twist_history_index += 1; @@ -1049,24 +1012,23 @@ void PairGranular::init_style() int *type = atom->type; int nlocal = atom->nlocal; - for (i = 0; i < nlocal; i++){ + for (i = 0; i < nlocal; i++) { double radius_cut = radius[i]; - if (mask[i] & freeze_group_bit){ + if (mask[i] & freeze_group_bit) { onerad_frozen[type[i]] = MAX(onerad_frozen[type[i]],radius_cut); - } - else{ + } else { onerad_dynamic[type[i]] = MAX(onerad_dynamic[type[i]],radius_cut); } } MPI_Allreduce(&onerad_dynamic[1],&maxrad_dynamic[1],atom->ntypes, - MPI_DOUBLE,MPI_MAX,world); + MPI_DOUBLE,MPI_MAX,world); MPI_Allreduce(&onerad_frozen[1],&maxrad_frozen[1],atom->ntypes, - MPI_DOUBLE,MPI_MAX,world); + MPI_DOUBLE,MPI_MAX,world); // set fix which stores history info - if (size_history > 0){ + if (size_history > 0) { int ifix = modify->find_fix("NEIGH_HISTORY"); if (ifix < 0) error->all(FLERR,"Could not find pair fix neigh history ID"); fix_history = (FixNeighHistory *) modify->fix[ifix]; @@ -1081,12 +1043,12 @@ double PairGranular::init_one(int i, int j) { double cutoff; - if (setflag[i][j] == 0){ + if (setflag[i][j] == 0) { if ((normal_model[i][i] != normal_model[j][j]) || (damping_model[i][i] != damping_model[j][j]) || (tangential_model[i][i] != tangential_model[j][j]) || (roll_model[i][i] != roll_model[j][j]) || - (twist_model[i][i] != twist_model[j][j])){ + (twist_model[i][i] != twist_model[j][j])) { char str[512]; sprintf(str,"Granular pair style functional forms are different, cannot mix coefficients for types %d and %d. \nThis combination must be set explicitly via pair_coeff command.",i,j); @@ -1105,12 +1067,12 @@ double PairGranular::init_one(int i, int j) for (int k = 0; k < 3; k++) tangential_coeffs[i][j][k] = tangential_coeffs[j][i][k] = mix_geom(tangential_coeffs[i][i][k], tangential_coeffs[j][j][k]); - if (roll_model[i][j] != ROLL_NONE){ + if (roll_model[i][j] != ROLL_NONE) { for (int k = 0; k < 3; k++) roll_coeffs[i][j][k] = roll_coeffs[j][i][k] = mix_geom(roll_coeffs[i][i][k], roll_coeffs[j][j][k]); } - if (twist_model[i][j] != TWIST_NONE && twist_model[i][j] != TWIST_MARSHALL){ + if (twist_model[i][j] != TWIST_NONE && twist_model[i][j] != TWIST_MARSHALL) { for (int k = 0; k < 3; k++) twist_coeffs[i][j][k] = twist_coeffs[j][i][k] = mix_geom(twist_coeffs[i][i][k], twist_coeffs[j][j][k]); } @@ -1124,14 +1086,14 @@ double PairGranular::init_one(int i, int j) // we assign cutoff = max(cut[i][j]) for i,j such that cut[i][j] > 0.0. double pulloff; - if (cutoff_type[i][j] < 0 && cutoff_global < 0){ + if (cutoff_type[i][j] < 0 && cutoff_global < 0) { if (((maxrad_dynamic[i] > 0.0) && (maxrad_dynamic[j] > 0.0)) || ((maxrad_dynamic[i] > 0.0) && (maxrad_frozen[j] > 0.0)) || ((maxrad_frozen[i] > 0.0) && (maxrad_dynamic[j] > 0.0))) { // radius info about both i and j exist cutoff = maxrad_dynamic[i]+maxrad_dynamic[j]; pulloff = 0.0; - if (normal_model[i][j] == JKR){ + if (normal_model[i][j] == JKR) { pulloff = pulloff_distance(maxrad_dynamic[i], maxrad_dynamic[j], i, j); cutoff += pulloff; } @@ -1143,8 +1105,7 @@ double PairGranular::init_one(int i, int j) if (normal_model[i][j] == JKR) pulloff = pulloff_distance(maxrad_dynamic[i], maxrad_frozen[j], i, j); cutoff = MAX(cutoff,maxrad_dynamic[i]+maxrad_frozen[j]+pulloff); - } - else { // radius info about either i or j does not exist (i.e. not present and not about to get poured; set to largest value to not interfere with neighbor list) + } else { // radius info about either i or j does not exist (i.e. not present and not about to get poured; set to largest value to not interfere with neighbor list) double cutmax = 0.0; for (int k = 1; k <= atom->ntypes; k++) { cutmax = MAX(cutmax,2.0*maxrad_dynamic[k]); @@ -1152,11 +1113,9 @@ double PairGranular::init_one(int i, int j) } cutoff = cutmax; } - } - else if (cutoff_type[i][j] > 0){ + } else if (cutoff_type[i][j] > 0) { cutoff = cutoff_type[i][j]; - } - else if (cutoff_global > 0){ + } else if (cutoff_global > 0) { cutoff = cutoff_global; } @@ -1285,7 +1244,7 @@ double PairGranular::single(int i, int j, int itype, int jtype, bool touchflag; E = normal_coeffs[itype][jtype][0]; - if (normal_model[itype][jtype] == JKR){ + if (normal_model[itype][jtype] == JKR) { E *= THREEQUARTERS; R2 = Reff*Reff; coh = normal_coeffs[itype][jtype][3]; @@ -1293,12 +1252,9 @@ double PairGranular::single(int i, int j, int itype, int jtype, delta_pulloff = a*a/Reff - 2*sqrt(M_PI*coh*a/E); dist_pulloff = radsum+delta_pulloff; touchflag = (rsq <= dist_pulloff*dist_pulloff); - } - else{ - touchflag = (rsq <= radsum*radsum); - } + } else touchflag = (rsq <= radsum*radsum); - if (!touchflag){ + if (!touchflag) { fforce = 0.0; for (int m = 0; m < single_extra; m++) svector[m] = 0.0; return 0.0; @@ -1376,7 +1332,7 @@ double PairGranular::single(int i, int j, int itype, int jtype, delta = radsum - r; dR = delta*Reff; - if (normal_model[itype][jtype] == JKR){ + if (normal_model[itype][jtype] == JKR) { dR2 = dR*dR; t0 = coh*coh*R2*R2*E; t1 = PI27SQ*t0; @@ -1392,12 +1348,11 @@ double PairGranular::single(int i, int j, int itype, int jtype, a2 = a*a; knfac = normal_coeffs[itype][jtype][0]*a; Fne = knfac*a2/Reff - TWOPI*a2*sqrt(4*coh*E/(M_PI*a)); - } - else{ + } else { knfac = E; Fne = knfac*delta; a = sqrt(dR); - if (normal_model[itype][jtype] != HOOKE){ + if (normal_model[itype][jtype] != HOOKE) { Fne *= a; knfac *= a; } @@ -1405,13 +1360,11 @@ double PairGranular::single(int i, int j, int itype, int jtype, Fne -= 4*MY_PI*normal_coeffs[itype][jtype][3]*Reff; } - if (damping_model[itype][jtype] == VELOCITY){ + if (damping_model[itype][jtype] == VELOCITY) { damp_normal = normal_coeffs[itype][jtype][1]; - } - else if (damping_model[itype][jtype] == VISCOELASTIC){ + } else if (damping_model[itype][jtype] == VISCOELASTIC) { damp_normal = normal_coeffs[itype][jtype][1]*a*meff; - } - else if (damping_model[itype][jtype] == TSUJI){ + } else if (damping_model[itype][jtype] == TSUJI) { damp_normal = normal_coeffs[itype][jtype][1]*sqrt(meff*knfac); } @@ -1423,7 +1376,7 @@ double PairGranular::single(int i, int j, int itype, int jtype, jnum = list->numneigh[i]; jlist = list->firstneigh[i]; - if (use_history){ + if (use_history) { allhistory = fix_history->firstvalue[i]; for (int jj = 0; jj < jnum; jj++) { neighprev++; @@ -1454,15 +1407,13 @@ double PairGranular::single(int i, int j, int itype, int jtype, vrel = vtr1*vtr1 + vtr2*vtr2 + vtr3*vtr3; vrel = sqrt(vrel); - if (normal_model[itype][jtype] == JKR){ + if (normal_model[itype][jtype] == JKR) { F_pulloff = 3*M_PI*coh*Reff; Fncrit = fabs(Fne + 2*F_pulloff); - } - else if (normal_model[itype][jtype] == DMT){ + } else if (normal_model[itype][jtype] == DMT) { F_pulloff = 4*M_PI*coh*Reff; Fncrit = fabs(Fne + 2*F_pulloff); - } - else{ + } else { Fncrit = fabs(Fntot); } @@ -1472,13 +1423,12 @@ double PairGranular::single(int i, int j, int itype, int jtype, k_tangential = tangential_coeffs[itype][jtype][0]; damp_tangential = tangential_coeffs[itype][jtype][1]*damp_normal_prefactor; - if (tangential_history){ - if (tangential_model[itype][jtype] == TANGENTIAL_MINDLIN){ + if (tangential_history) { + if (tangential_model[itype][jtype] == TANGENTIAL_MINDLIN) { k_tangential *= a; - } - else if (tangential_model[itype][jtype] == TANGENTIAL_MINDLIN_RESCALE){ + } else if (tangential_model[itype][jtype] == TANGENTIAL_MINDLIN_RESCALE) { k_tangential *= a; - if (a < history[3]){ //On unloading, rescale the shear displacements + if (a < history[3]) { //On unloading, rescale the shear displacements double factor = a/history[3]; history[0] *= factor; history[1] *= factor; @@ -1507,8 +1457,7 @@ double PairGranular::single(int i, int j, int itype, int jtype, fs3 *= Fscrit/fs; } else fs1 = fs2 = fs3 = 0.0; } - } - else{ //Classic pair gran/hooke (no history) + } else { //Classic pair gran/hooke (no history) fs = meff*damp_tangential*vrel; if (vrel != 0.0) Ft = MIN(Fne,fs) / vrel; else Ft = 0.0; @@ -1521,7 +1470,7 @@ double PairGranular::single(int i, int j, int itype, int jtype, // Rolling resistance //**************************************** - if (roll_model[itype][jtype] != ROLL_NONE){ + if (roll_model[itype][jtype] != ROLL_NONE) { relrot1 = omega[i][0] - omega[j][0]; relrot2 = omega[i][1] - omega[j][1]; relrot3 = omega[i][2] - omega[j][2]; @@ -1565,14 +1514,13 @@ double PairGranular::single(int i, int j, int itype, int jtype, //**************************************** // Twisting torque, including history effects //**************************************** - if (twist_model[itype][jtype] != TWIST_NONE){ + if (twist_model[itype][jtype] != TWIST_NONE) { magtwist = relrot1*nx + relrot2*ny + relrot3*nz; //Omega_T (eq 29 of Marshall) - if (twist_model[itype][jtype] == TWIST_MARSHALL){ + if (twist_model[itype][jtype] == TWIST_MARSHALL) { k_twist = 0.5*k_tangential*a*a;; //eq 32 damp_twist = 0.5*damp_tangential*a*a; mu_twist = TWOTHIRDS*a*tangential_coeffs[itype][jtype][2];; - } - else{ + } else { k_twist = twist_coeffs[itype][jtype][0]; damp_twist = twist_coeffs[itype][jtype][1]; mu_twist = twist_coeffs[itype][jtype][2]; @@ -1686,7 +1634,7 @@ double PairGranular::pulloff_distance(double radi, double radj, int itype, int j Transfer history during fix/neigh/history exchange Only needed if any history entries i-j are not just negative of j-i entries ------------------------------------------------------------------------- */ -void PairGranular::transfer_history(double* source, double* target){ +void PairGranular::transfer_history(double* source, double* target) { for (int i = 0; i < size_history; i++) target[i] = history_transfer_factors[i]*source[i]; } From a7a1fd4ee583be6bbd77ba82e194672c02e973a8 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 15 Mar 2019 15:50:44 -0400 Subject: [PATCH 37/44] remove reference to USER-OMP version of fix wall/gran --- doc/src/Commands_fix.txt | 2 +- doc/src/fix_wall_gran.txt | 23 ----------------------- 2 files changed, 1 insertion(+), 24 deletions(-) diff --git a/doc/src/Commands_fix.txt b/doc/src/Commands_fix.txt index 678cc9ba0d..c8b3ef8991 100644 --- a/doc/src/Commands_fix.txt +++ b/doc/src/Commands_fix.txt @@ -224,7 +224,7 @@ OPT. "wall/body/polyhedron"_fix_wall_body_polyhedron.html, "wall/colloid"_fix_wall.html, "wall/ees"_fix_wall_ees.html, -"wall/gran (o)"_fix_wall_gran.html, +"wall/gran"_fix_wall_gran.html, "wall/gran/region"_fix_wall_gran_region.html, "wall/harmonic"_fix_wall.html, "wall/lj1043"_fix_wall.html, diff --git a/doc/src/fix_wall_gran.txt b/doc/src/fix_wall_gran.txt index e8c2247594..198b22aa3f 100644 --- a/doc/src/fix_wall_gran.txt +++ b/doc/src/fix_wall_gran.txt @@ -7,7 +7,6 @@ :line fix wall/gran command :h3 -fix wall/gran/omp command :h3 [Syntax:] @@ -151,28 +150,6 @@ the clockwise direction for {vshear} > 0 or counter-clockwise for {vshear} < 0. In this case, {vshear} is the tangential velocity of the wall at whatever {radius} has been defined. -:line - -Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are -functionally the same as the corresponding style without the suffix. -They have been optimized to run faster, depending on your available -hardware, as discussed on the "Speed packages"_Speed_packages.html doc -page. The accelerated styles take the same arguments and should -produce the same results, except for round-off and precision issues. - -These accelerated styles are part of the GPU, USER-INTEL, KOKKOS, -USER-OMP and OPT packages, respectively. They are only enabled if -LAMMPS was built with those packages. See the "Build -package"_Build_package.html doc page for more info. - -You can specify the accelerated styles explicitly in your input script -by including their suffix, or you can use the "-suffix command-line -switch"_Run_options.html when you invoke LAMMPS, or you can use the -"suffix"_suffix.html command in your input script. - -See the "Speed packages"_Speed_packages.html doc page for more -instructions on how to use the accelerated styles effectively. - [Restart, fix_modify, output, run start/stop, minimize info:] This fix writes the shear friction state of atoms interacting with the From 2bac3650811d5b30fc04e61fe85abdab195a7d90 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 15 Mar 2019 15:51:08 -0400 Subject: [PATCH 38/44] support old style PDF build for new pair style granular --- doc/src/lammps.book | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/src/lammps.book b/doc/src/lammps.book index 198e234f0c..8165c9d743 100644 --- a/doc/src/lammps.book +++ b/doc/src/lammps.book @@ -578,6 +578,7 @@ pair_extep.html pair_gauss.html pair_gayberne.html pair_gran.html +pair_granular.html pair_gromacs.html pair_gw.html pair_ilp_graphene_hbn.html From 5210c4c3a4e21e63036ca51554fc8f49ceb88274 Mon Sep 17 00:00:00 2001 From: Steve Plimpton Date: Wed, 27 Mar 2019 16:58:14 -0600 Subject: [PATCH 39/44] cosmetic reformatting of new GRANULAR files --- doc/src/fix_wall_gran.txt | 53 +- doc/src/fix_wall_gran_region.txt | 59 +- doc/src/pair_granular.txt | 571 ++++++++++------- src/GRANULAR/fix_wall_gran.cpp | 746 ++++++++++++----------- src/GRANULAR/fix_wall_gran.h | 17 +- src/GRANULAR/fix_wall_gran_region.cpp | 19 +- src/GRANULAR/pair_gran_hooke_history.cpp | 4 +- src/GRANULAR/pair_gran_hooke_history.h | 3 +- src/GRANULAR/pair_granular.cpp | 419 ++++++++----- src/GRANULAR/pair_granular.h | 12 +- src/fix_neigh_history.cpp | 6 +- src/pair.h | 2 +- 12 files changed, 1086 insertions(+), 825 deletions(-) diff --git a/doc/src/fix_wall_gran.txt b/doc/src/fix_wall_gran.txt index 198b22aa3f..b517d48cca 100644 --- a/doc/src/fix_wall_gran.txt +++ b/doc/src/fix_wall_gran.txt @@ -59,31 +59,32 @@ close enough to touch it. The nature of the wall/particle interactions are determined by the {fstyle} setting. It can be any of the styles defined by the -"pair_style gran/*"_pair_gran.html or the more general "pair_style granular"_pair_granular.html" -commands. Currently the options are {hooke}, {hooke/history}, or {hertz/history} for the former, -and {granular} with all the possible options of the associated {pair_coeff} command -for the latter. The equation for the -force between the wall and particles touching it is the same as the -corresponding equation on the "pair_style gran/*"_pair_gran.html -and "pair_style_granular"_pair_granular.html doc -pages, in the limit of one of the two particles going to infinite -radius and mass (flat wall). Specifically, delta = radius - r = -overlap of particle with wall, m_eff = mass of particle, and the -effective radius of contact = RiRj/Ri+Rj is set to the radius -of the particle. +"pair_style gran/*"_pair_gran.html or the more general "pair_style +granular"_pair_granular.html" commands. Currently the options are +{hooke}, {hooke/history}, or {hertz/history} for the former, and +{granular} with all the possible options of the associated +{pair_coeff} command for the latter. The equation for the force +between the wall and particles touching it is the same as the +corresponding equation on the "pair_style gran/*"_pair_gran.html and +"pair_style_granular"_pair_granular.html doc pages, in the limit of +one of the two particles going to infinite radius and mass (flat +wall). Specifically, delta = radius - r = overlap of particle with +wall, m_eff = mass of particle, and the effective radius of contact = +RiRj/Ri+Rj is set to the radius of the particle. The parameters {Kn}, {Kt}, {gamma_n}, {gamma_t}, {xmu} and {dampflag} have the same meaning and units as those specified with the -"pair_style gran/*"_pair_gran.html commands. This means a NULL can -be used for either {Kt} or {gamma_t} as described on that page. If a +"pair_style gran/*"_pair_gran.html commands. This means a NULL can be +used for either {Kt} or {gamma_t} as described on that page. If a NULL is used for {Kt}, then a default value is used where {Kt} = 2/7 {Kn}. If a NULL is used for {gamma_t}, then a default value is used where {gamma_t} = 1/2 {gamma_n}. -All the model choices for cohesion, tangential friction, rolling friction -and twisting friction supported by the "pair_style granular"_pair_granular.html -through its {pair_coeff} command are also supported for walls. These are discussed -in greater detail on the doc page for "pair_style granular"_pair_granular.html. +All the model choices for cohesion, tangential friction, rolling +friction and twisting friction supported by the "pair_style +granular"_pair_granular.html through its {pair_coeff} command are also +supported for walls. These are discussed in greater detail on the doc +page for "pair_style granular"_pair_granular.html. Note that you can choose a different force styles and/or different values for the wall/particle coefficients than for particle/particle @@ -121,14 +122,14 @@ Optionally, the wall can be moving, if the {wiggle} or {shear} keywords are appended. Both keywords cannot be used together. For the {wiggle} keyword, the wall oscillates sinusoidally, similar to -the oscillations of particles which can be specified by the -"fix move"_fix_move.html command. This is useful in packing -simulations of granular particles. The arguments to the {wiggle} -keyword specify a dimension for the motion, as well as it's -{amplitude} and {period}. Note that if the dimension is in the plane -of the wall, this is effectively a shearing motion. If the dimension -is perpendicular to the wall, it is more of a shaking motion. A -{zcylinder} wall can only be wiggled in the z dimension. +the oscillations of particles which can be specified by the "fix +move"_fix_move.html command. This is useful in packing simulations of +granular particles. The arguments to the {wiggle} keyword specify a +dimension for the motion, as well as it's {amplitude} and {period}. +Note that if the dimension is in the plane of the wall, this is +effectively a shearing motion. If the dimension is perpendicular to +the wall, it is more of a shaking motion. A {zcylinder} wall can only +be wiggled in the z dimension. Each timestep, the position of a wiggled wall in the appropriate {dim} is set according to this equation: diff --git a/doc/src/fix_wall_gran_region.txt b/doc/src/fix_wall_gran_region.txt index d54b3dc009..8a39d6b642 100644 --- a/doc/src/fix_wall_gran_region.txt +++ b/doc/src/fix_wall_gran_region.txt @@ -48,8 +48,8 @@ Here are snapshots of example models using this command. Corresponding input scripts can be found in examples/granregion. Click on the images to see a bigger picture. Movies of these simulations are "here on the Movies -page"_http://lammps.sandia.gov/movies.html#granregion of the -LAMMPS web site. +page"_http://lammps.sandia.gov/movies.html#granregion of the LAMMPS +web site. :image(JPG/gran_funnel_small.jpg,JPG/gran_funnel.png) :image(JPG/gran_mixer_small.jpg,JPG/gran_mixer.png) @@ -129,15 +129,16 @@ to make the two faces differ by epsilon in their position. The nature of the wall/particle interactions are determined by the {fstyle} setting. It can be any of the styles defined by the -"pair_style gran/*"_pair_gran.html or the more general "pair_style granular"_pair_granular.html" -commands. Currently the options are {hooke}, {hooke/history}, or {hertz/history} for the former, -and {granular} with all the possible options of the associated {pair_coeff} command -for the latter. The equation for the -force between the wall and particles touching it is the same as the -corresponding equation on the "pair_style gran/*"_pair_gran.html -and "pair_style_granular"_pair_granular.html doc -pages, but the effective radius is calculated using the radius of the -particle and the radius of curvature of the wall at the contact point. +"pair_style gran/*"_pair_gran.html or the more general "pair_style +granular"_pair_granular.html" commands. Currently the options are +{hooke}, {hooke/history}, or {hertz/history} for the former, and +{granular} with all the possible options of the associated +{pair_coeff} command for the latter. The equation for the force +between the wall and particles touching it is the same as the +corresponding equation on the "pair_style gran/*"_pair_gran.html and +"pair_style_granular"_pair_granular.html doc pages, but the effective +radius is calculated using the radius of the particle and the radius +of curvature of the wall at the contact point. Specifically, delta = radius - r = overlap of particle with wall, m_eff = mass of particle, and RiRj/Ri+Rj is the effective radius, with @@ -150,17 +151,17 @@ particle. The parameters {Kn}, {Kt}, {gamma_n}, {gamma_t}, {xmu} and {dampflag} have the same meaning and units as those specified with the -"pair_style gran/*"_pair_gran.html commands. This means a NULL can -be used for either {Kt} or {gamma_t} as described on that page. If a +"pair_style gran/*"_pair_gran.html commands. This means a NULL can be +used for either {Kt} or {gamma_t} as described on that page. If a NULL is used for {Kt}, then a default value is used where {Kt} = 2/7 {Kn}. If a NULL is used for {gamma_t}, then a default value is used where {gamma_t} = 1/2 {gamma_n}. - -All the model choices for cohesion, tangential friction, rolling friction -and twisting friction supported by the "pair_style granular"_pair_granular.html -through its {pair_coeff} command are also supported for walls. These are discussed -in greater detail on the doc page for "pair_style granular"_pair_granular.html. +All the model choices for cohesion, tangential friction, rolling +friction and twisting friction supported by the "pair_style +granular"_pair_granular.html through its {pair_coeff} command are also +supported for walls. These are discussed in greater detail on the doc +page for "pair_style granular"_pair_granular.html. Note that you can choose a different force styles and/or different values for the 6 wall/particle coefficients than for particle/particle @@ -169,9 +170,9 @@ material. [Restart, fix_modify, output, run start/stop, minimize info:] -Similar to "fix wall/gran"_fix_wall_gran.html command, this fix -writes the shear friction state of atoms interacting with the wall to -"binary restart files"_restart.html, so that a simulation can continue +Similar to "fix wall/gran"_fix_wall_gran.html command, this fix writes +the shear friction state of atoms interacting with the wall to "binary +restart files"_restart.html, so that a simulation can continue correctly if granular potentials with shear "history" effects are being used. This fix also includes info about a moving region in the restart file. See the "read_restart"_read_restart.html command for @@ -185,14 +186,14 @@ So you must re-define your region and if it is a moving region, define its motion attributes in a way that is consistent with the simulation that wrote the restart file. In particular, if you want to change the region motion attributes (e.g. its velocity), then you should ensure -the position/orientation of the region at the initial restart -timestep is the same as it was on the timestep the restart file was -written. If this is not possible, you may need to ignore info in the -restart file by defining a new fix wall/gran/region command in your -restart script, e.g. with a different fix ID. Or if you want to keep -the shear history info but discard the region motion information, you -can use the same fix ID for fix wall/gran/region, but assign it a -region with a different region ID. +the position/orientation of the region at the initial restart timestep +is the same as it was on the timestep the restart file was written. +If this is not possible, you may need to ignore info in the restart +file by defining a new fix wall/gran/region command in your restart +script, e.g. with a different fix ID. Or if you want to keep the +shear history info but discard the region motion information, you can +use the same fix ID for fix wall/gran/region, but assign it a region +with a different region ID. None of the "fix_modify"_fix_modify.html options are relevant to this fix. No global or per-atom quantities are stored by this fix for diff --git a/doc/src/pair_granular.txt b/doc/src/pair_granular.txt index 73c2bbdd3b..e4b9bb3250 100644 --- a/doc/src/pair_granular.txt +++ b/doc/src/pair_granular.txt @@ -19,8 +19,7 @@ pair_style granular command :h3 pair_style granular cutoff :pre -cutoff = global cutoff (optional). See discussion below. :l -:ule +cutoff = global cutoff (optional). See discussion below. :l [Examples:] @@ -44,29 +43,39 @@ pair_coeff 1 2 dmt 1000.0 50.0 0.3 10.0 tangential mindlin 800.0 0.5 0.1 roll sd [Description:] -The {granular} styles support a variety of options for the normal, tangential, rolling and twisting -forces resulting from contact between two granular particles. This expands on the options offered -by the "pair gran/*"_pair_gran.html pair styles. The total computed forces and torques are the -sum of various models selected for the normal, tangential, rolling and twisting modes of motion. +The {granular} styles support a variety of options for the normal, +tangential, rolling and twisting forces resulting from contact between +two granular particles. This expands on the options offered by the +"pair gran/*"_pair_gran.html pair styles. The total computed forces +and torques are the sum of various models selected for the normal, +tangential, rolling and twisting modes of motion. -All model choices and parameters are entered in the "pair_coeff"_pair_coeff.html command, as described below. -Unlike e.g. "pair gran/hooke"_pair_gran.html, coefficient values are not global, but can be set to different values for -different combinations of particle types, as determined by the "pair_coeff"_pair_coeff.html command. -If the contact model choice is the same for two particle types, the mixing for the cross-coefficients can be carried out -automatically. This is shown in the second example, where model choices are the same for type 1 - type 1 as for type 2 - type2 -interactions, but coefficients are different. In this case, the coefficients for type 2 - type interactions can be -determined from mixing rules discussed below. -For additional flexibility, coefficients as well as model forms can vary between particle types, -as shown in the third example: -type 1- type 1 interactions are based on a Hertzian normal contact model and 2-2 interactions are based on a DMT cohesive model (see below). -In that example, 1-1 and 2-2 interactions have different model forms, in which case -mixing of coefficients cannot be determined, so 1-2 interactions must be explicitly defined via the -{pair_coeff 1 2} command, otherwise an error would result. +All model choices and parameters are entered in the +"pair_coeff"_pair_coeff.html command, as described below. Unlike +e.g. "pair gran/hooke"_pair_gran.html, coefficient values are not +global, but can be set to different values for different combinations +of particle types, as determined by the "pair_coeff"_pair_coeff.html +command. If the contact model choice is the same for two particle +types, the mixing for the cross-coefficients can be carried out +automatically. This is shown in the second example, where model +choices are the same for type 1 - type 1 as for type 2 - type2 +interactions, but coefficients are different. In this case, the +coefficients for type 2 - type interactions can be determined from +mixing rules discussed below. For additional flexibility, +coefficients as well as model forms can vary between particle types, +as shown in the third example: type 1- type 1 interactions are based +on a Hertzian normal contact model and 2-2 interactions are based on a +DMT cohesive model (see below). In that example, 1-1 and 2-2 +interactions have different model forms, in which case mixing of +coefficients cannot be determined, so 1-2 interactions must be +explicitly defined via the {pair_coeff 1 2} command, otherwise an +error would result. :line -The first required keyword for the {pair_coeff} command is the normal contact model. Currently supported options -for normal contact models and their required arguments are: +The first required keyword for the {pair_coeff} command is the normal +contact model. Currently supported options for normal contact models +and their required arguments are: {hooke} : \(k_n\), \(\eta_\{n0\}\) (or \(e\)) {hertz} : \(k_n\), \(\eta_\{n0\}\) (or \(e\)) @@ -74,137 +83,165 @@ for normal contact models and their required arguments are: {dmt} : E, \(\eta_\{n0\}\) (or \(e\)), \(\nu\), \(\gamma\) {jkr} : E, \(\eta_\{n0\}\) (or \(e\)), \(\nu\), \(\gamma\) :ol -Here, \(k_n\) is spring stiffness (with units that depend on model choice, see below); -\(\eta_\{n0\}\) is a damping prefactor (or, in its place a coefficient of restitution -\(e\), depending on the choice of damping mode, see below); E is Young's modulus -in units of {force}/{length}^2, i.e. {pressure}; \(\nu\) is Poisson's ratio -and \(\gamma\) is a surface energy density, in units of {energy}/{length}^2. +Here, \(k_n\) is spring stiffness (with units that depend on model +choice, see below); \(\eta_\{n0\}\) is a damping prefactor (or, in its +place a coefficient of restitution \(e\), depending on the choice of +damping mode, see below); E is Young's modulus in units of +{force}/{length}^2, i.e. {pressure}; \(\nu\) is Poisson's ratio and +\(\gamma\) is a surface energy density, in units of +{energy}/{length}^2. + +For the {hooke} model, the normal, elastic component of force acting +on particle {i} due to contact with particle {j} is given by: -For the {hooke} model, the normal, elastic component of force acting on particle {i} due to -contact with particle {j} is given by: \begin\{equation\} \mathbf\{F\}_\{ne, Hooke\} = k_N \delta_\{ij\} \mathbf\{n\} \end\{equation\} -Where \(\delta = R_i + R_j - \|\mathbf\{r\}_\{ij\}\|\) is the particle overlap, -\(R_i, R_j\) are the particle radii, -\(\mathbf\{r\}_\{ij\} = \mathbf\{r\}_i - \mathbf\{r\}_j\) is the vector separating the -two particle centers (note the i-j ordering so that \(F_\{ne\}\) is positive for repulsion), -and \(\mathbf\{n\} = \frac\{\mathbf\{r\}_\{ij\}\}\{\|\mathbf\{r\}_\{ij\}\|\}\). -Therefore, for {hooke}, the units of the spring constant \(k_n\) are {force}/{distance}, -or equivalently {mass}/{time^2}. +Where \(\delta = R_i + R_j - \|\mathbf\{r\}_\{ij\}\|\) is the particle +overlap, \(R_i, R_j\) are the particle radii, \(\mathbf\{r\}_\{ij\} = +\mathbf\{r\}_i - \mathbf\{r\}_j\) is the vector separating the two +particle centers (note the i-j ordering so that \(F_\{ne\}\) is +positive for repulsion), and \(\mathbf\{n\} = +\frac\{\mathbf\{r\}_\{ij\}\}\{\|\mathbf\{r\}_\{ij\}\|\}\). Therefore, +for {hooke}, the units of the spring constant \(k_n\) are +{force}/{distance}, or equivalently {mass}/{time^2}. For the {hertz} model, the normal component of force is given by: + \begin\{equation\} \mathbf\{F\}_\{ne, Hertz\} = k_N R_\{eff\}^\{1/2\}\delta_\{ij\}^\{3/2\} \mathbf\{n\} \end\{equation\} -Here, \(R_\{eff\} = \frac\{R_i R_j\}\{R_i + R_j\}\) is the effective radius, denoted for simplicity as {R} from here on. -For {hertz}, the units of the spring constant \(k_n\) are {force}/{length}^2, or equivalently -{pressure}. +Here, \(R_\{eff\} = \frac\{R_i R_j\}\{R_i + R_j\}\) is the effective +radius, denoted for simplicity as {R} from here on. For {hertz}, the +units of the spring constant \(k_n\) are {force}/{length}^2, or +equivalently {pressure}. For the {hertz/material} model, the force is given by: + \begin\{equation\} \mathbf\{F\}_\{ne, Hertz/material\} = \frac\{4\}\{3\} E_\{eff\} R_\{eff\}^\{1/2\}\delta_\{ij\}^\{3/2\} \mathbf\{n\} \end\{equation\} -Here, \(E_\{eff\} = E = \left(\frac\{1-\nu_i^2\}\{E_i\} + \frac\{1-\nu_j^2\}\{E_j\}\right)^\{-1\}\) -is the effective Young's modulus, -with \(\nu_i, \nu_j \) the Poisson ratios of the particles of types {i} and {j}. Note that -if the elastic modulus and the shear modulus of the two particles are the same, the {hertz/material} -model is equivalent to the {hertz} model with \(k_N = 4/3 E_\{eff\}\) +Here, \(E_\{eff\} = E = \left(\frac\{1-\nu_i^2\}\{E_i\} + +\frac\{1-\nu_j^2\}\{E_j\}\right)^\{-1\}\) is the effective Young's +modulus, with \(\nu_i, \nu_j \) the Poisson ratios of the particles of +types {i} and {j}. Note that if the elastic modulus and the shear +modulus of the two particles are the same, the {hertz/material} model +is equivalent to the {hertz} model with \(k_N = 4/3 E_\{eff\}\) + +The {dmt} model corresponds to the +"(Derjaguin-Muller-Toporov)"_#DMT1975 cohesive model, where the force +is simply Hertz with an additional attractive cohesion term: -The {dmt} model corresponds to the "(Derjaguin-Muller-Toporov)"_#DMT1975 cohesive model, -where the force is simply Hertz with an additional attractive cohesion term: \begin\{equation\} \mathbf\{F\}_\{ne, dmt\} = \left(\frac\{4\}\{3\} E R^\{1/2\}\delta_\{ij\}^\{3/2\} - 4\pi\gamma R\right)\mathbf\{n\} \end\{equation\} -The {jkr} model is the "(Johnson-Kendall-Roberts)"_#JKR1971 model, where the force is computed as: +The {jkr} model is the "(Johnson-Kendall-Roberts)"_#JKR1971 model, +where the force is computed as: + \begin\{equation\} \label\{eq:force_jkr\} \mathbf\{F\}_\{ne, jkr\} = \left(\frac\{4Ea^3\}\{3R\} - 2\pi a^2\sqrt\{\frac\{4\gamma E\}\{\pi a\}\}\right)\mathbf\{n\} \end\{equation\} -Here, {a} is the radius of the contact zone, related to the overlap \(\delta\) according to: +Here, {a} is the radius of the contact zone, related to the overlap +\(\delta\) according to: + \begin\{equation\} \delta = a^2/R - 2\sqrt\{\pi \gamma a/E\} \end\{equation\} -LAMMPS internally inverts the equation above to solve for {a} in terms of \(\delta\), then solves for -the force in the previous equation. Additionally, note that the JKR model allows for a tensile force beyond -contact (i.e. for \(\delta < 0\)), up to a maximum of \(3\pi\gamma R\) (also known as -the 'pull-off' force). -Note that this is a hysteretic effect, where particles that are not contacting initially -will not experience force until they come into contact \(\delta \geq 0\); as they move apart -and (\(\delta < 0\)), they experience a tensile force up to \(3\pi\gamma R\), -at which point they lose contact. +LAMMPS internally inverts the equation above to solve for {a} in terms +of \(\delta\), then solves for the force in the previous +equation. Additionally, note that the JKR model allows for a tensile +force beyond contact (i.e. for \(\delta < 0\)), up to a maximum of +\(3\pi\gamma R\) (also known as the 'pull-off' force). Note that this +is a hysteretic effect, where particles that are not contacting +initially will not experience force until they come into contact +\(\delta \geq 0\); as they move apart and (\(\delta < 0\)), they +experience a tensile force up to \(3\pi\gamma R\), at which point they +lose contact. :line -In addition, the normal force is augmented by a damping term of the following -general form: +In addition, the normal force is augmented by a damping term of the +following general form: \begin\{equation\} \mathbf\{F\}_\{n,damp\} = -\eta_n \mathbf\{v\}_\{n,rel\} \end\{equation\} -Here, \(\mathbf\{v\}_\{n,rel\} = (\mathbf\{v\}_j - \mathbf\{v\}_i) \cdot \mathbf\{n\}\) -is the component of relative velocity along \(\mathbf\{n\}\). +Here, \(\mathbf\{v\}_\{n,rel\} = (\mathbf\{v\}_j - \mathbf\{v\}_i) +\cdot \mathbf\{n\}\) is the component of relative velocity along +\(\mathbf\{n\}\). -The optional {damping} keyword to the {pair_coeff} command followed by a keyword -determines the model form of the damping factor \(\eta_n\), and the interpretation -of the \(\eta_\{n0\}\) or \(e\) coefficients specified as part of the normal contact -model settings. The {damping} keyword and corresponding -model form selection may be appended anywhere in the {pair coeff} command. -Note that the choice of damping model affects both the -normal and tangential damping (and depending on other settings, potentially also the twisting damping). -The options for the damping model currently supported are: +The optional {damping} keyword to the {pair_coeff} command followed by +a keyword determines the model form of the damping factor \(\eta_n\), +and the interpretation of the \(\eta_\{n0\}\) or \(e\) coefficients +specified as part of the normal contact model settings. The {damping} +keyword and corresponding model form selection may be appended +anywhere in the {pair coeff} command. Note that the choice of damping +model affects both the normal and tangential damping (and depending on +other settings, potentially also the twisting damping). The options +for the damping model currently supported are: {velocity} {viscoelastic} {tsuji} :ol -If the {damping} keyword is not specified, the {viscoelastic} model is used by default. +If the {damping} keyword is not specified, the {viscoelastic} model is +used by default. -For {damping velocity}, the normal damping is simply equal to the user-specified damping -coefficient in the {normal} model: +For {damping velocity}, the normal damping is simply equal to the +user-specified damping coefficient in the {normal} model: \begin\{equation\} \eta_n = \eta_\{n0\}\ \end\{equation\} -Here, \(\gamma_n\) is the damping coefficient specified for the normal contact model, in units of {mass}/{time}, +Here, \(\gamma_n\) is the damping coefficient specified for the normal +contact model, in units of {mass}/{time}, + +The {damping viscoelastic} model is based on the viscoelastic +treatment of "(Brilliantov et al)"_#Brill1996, where the normal +damping is given by: -The {damping viscoelastic} model is based on the viscoelastic treatment of "(Brilliantov et al)"_#Brill1996, -where the normal damping is given by: \begin\{equation\} \eta_n = \eta_\{n0\}\ a m_\{eff\} \end\{equation\} -Here, \(m_\{eff\} = m_i m_j/(m_i + m_j)\) is the effective mass, {a} is the contact radius, given by \(a =\sqrt\{R\delta\}\) -for all models except {jkr}, for which it is given implicitly according to \(delta = a^2/R - 2\sqrt\{\pi \gamma a/E\}\). -In this case, \eta_\{n0\}\ is in units of 1/({time}*{distance}). +Here, \(m_\{eff\} = m_i m_j/(m_i + m_j)\) is the effective mass, {a} +is the contact radius, given by \(a =\sqrt\{R\delta\}\) for all models +except {jkr}, for which it is given implicitly according to \(delta = +a^2/R - 2\sqrt\{\pi \gamma a/E\}\). In this case, \eta_\{n0\}\ is in +units of 1/({time}*{distance}). -The {tsuji} model is based on the work of "(Tsuji et al)"_#Tsuji1992. Here, the -damping coefficient specified as part of the normal model is interpreted -as a restitution coefficient \(e\). The damping constant \(\eta_n\) is given by: +The {tsuji} model is based on the work of "(Tsuji et +al)"_#Tsuji1992. Here, the damping coefficient specified as part of +the normal model is interpreted as a restitution coefficient +\(e\). The damping constant \(\eta_n\) is given by: \begin\{equation\} \eta_n = \alpha (m_\{eff\}k_n)^\{1/2\} \end\{equation\} -For normal contact models based on material parameters, \(k_n = 4/3Ea\). -The parameter \(\alpha\) is related to the restitution coefficient {e} according to: +For normal contact models based on material parameters, \(k_n = +4/3Ea\). The parameter \(\alpha\) is related to the restitution +coefficient {e} according to: \begin\{equation\} \alpha = 1.2728-4.2783e+11.087e^2-22.348e^3+27.467e^4-18.022e^5+4.8218e^6 \end\{equation\} -The dimensionless coefficient of restitution \(e\) specified as part of the normal contact model -parameters should be between 0 and 1, but no error check is performed on this. +The dimensionless coefficient of restitution \(e\) specified as part +of the normal contact model parameters should be between 0 and 1, but +no error check is performed on this. -The total normal force is computed as the sum of the elastic and damping components: +The total normal force is computed as the sum of the elastic and +damping components: \begin\{equation\} \mathbf\{F\}_n = \mathbf\{F\}_\{ne\} + \mathbf\{F\}_\{n,damp\} @@ -212,24 +249,24 @@ The total normal force is computed as the sum of the elastic and damping compone :line -The {pair_coeff} command also requires specification -of the tangential contact model. The required keyword {tangential} is expected, followed by the model -choice and associated parameters. Currently supported tangential model choices and their -expected parameters are as follows: +The {pair_coeff} command also requires specification of the tangential +contact model. The required keyword {tangential} is expected, followed +by the model choice and associated parameters. Currently supported +tangential model choices and their expected parameters are as follows: {linear_nohistory} : \(x_\{\gamma,t\}\), \(\mu_s\) {linear_history} : \(k_t\), \(x_\{\gamma,t\}\), \(\mu_s\) {mindlin} : \(k_t\) or NULL, \(x_\{\gamma,t\}\), \(\mu_s\) {mindlin_rescale} : \(k_t\) or NULL, \(x_\{\gamma,t\}\), \(\mu_s\) :ol -Here, \(x_\{\gamma,t\}\) is a dimensionless multiplier for the normal damping \(\eta_n\) -that determines the magnitude of the -tangential damping, \(\mu_t\) is the tangential (or sliding) friction +Here, \(x_\{\gamma,t\}\) is a dimensionless multiplier for the normal +damping \(\eta_n\) that determines the magnitude of the tangential +damping, \(\mu_t\) is the tangential (or sliding) friction coefficient, and \(k_t\) is the tangential stiffness coefficient. -For {tangential linear_nohistory}, a simple velocity-dependent Coulomb friction criterion is used, -which mimics the behavior -of the {pair gran/hooke} style. The tangential force (\mathbf\{F\}_t\) is given by: +For {tangential linear_nohistory}, a simple velocity-dependent Coulomb +friction criterion is used, which mimics the behavior of the {pair +gran/hooke} style. The tangential force (\mathbf\{F\}_t\) is given by: \begin\{equation\} \mathbf\{F\}_t = -min(\mu_t F_\{n0\}, \|\mathbf\{F\}_\mathrm\{t,damp\}\|) \mathbf\{t\} @@ -241,41 +278,52 @@ The tangential damping force \(\mathbf\{F\}_\mathrm\{t,damp\}\) is given by: \mathbf\{F\}_\mathrm\{t,damp\} = -\eta_t \mathbf\{v\}_\{t,rel\} \end\{equation\} -The tangential damping prefactor \(\eta_t\) is calculated by scaling the normal damping \(\eta_n\) (see above): +The tangential damping prefactor \(\eta_t\) is calculated by scaling +the normal damping \(\eta_n\) (see above): + \begin\{equation\} \eta_t = -x_\{\gamma,t\} \eta_n \end\{equation\} -The normal damping prefactor \(\eta_n\) is determined by the choice of the {damping} keyword, as discussed above. -Thus, the {damping} keyword also affects the tangential damping. -The parameter \(x_\{\gamma,t\}\) is a scaling coefficient. Several works in the literature use -\(x_\{\gamma,t\} = 1\) ("Marshall"_#Marshall2009, "Tsuji et al"_#Tsuji1992, "Silbert et al"_#Silbert2001). -The relative tangential velocity at the point of contact is given by -\(\mathbf\{v\}_\{t, rel\} = \mathbf\{v\}_\{t\} - (R_i\Omega_i + R_j\Omega_j) \times \mathbf\{n\}\), -where \(\mathbf\{v\}_\{t\} = \mathbf\{v\}_r - \mathbf\{v\}_r\cdot\mathbf\{n\}\), -\(\mathbf\{v\}_r = \mathbf\{v\}_j - \mathbf\{v\}_i\). The direction of the applied force is -\(\mathbf\{t\} = \mathbf\{v_\{t,rel\}\}/\|\mathbf\{v_\{t,rel\}\}\|\). +The normal damping prefactor \(\eta_n\) is determined by the choice of +the {damping} keyword, as discussed above. Thus, the {damping} +keyword also affects the tangential damping. The parameter +\(x_\{\gamma,t\}\) is a scaling coefficient. Several works in the +literature use \(x_\{\gamma,t\} = 1\) ("Marshall"_#Marshall2009, +"Tsuji et al"_#Tsuji1992, "Silbert et al"_#Silbert2001). The relative +tangential velocity at the point of contact is given by +\(\mathbf\{v\}_\{t, rel\} = \mathbf\{v\}_\{t\} - (R_i\Omega_i + +R_j\Omega_j) \times \mathbf\{n\}\), where \(\mathbf\{v\}_\{t\} = +\mathbf\{v\}_r - \mathbf\{v\}_r\cdot\mathbf\{n\}\), \(\mathbf\{v\}_r = +\mathbf\{v\}_j - \mathbf\{v\}_i\). The direction of the applied force +is \(\mathbf\{t\} = +\mathbf\{v_\{t,rel\}\}/\|\mathbf\{v_\{t,rel\}\}\|\). The normal force value \(F_\{n0\}\) used to compute the critical force depends on the form of the contact model. For non-cohesive models -({hertz}, {hertz/material}, {hooke}), it is given by the magnitude of the normal force: +({hertz}, {hertz/material}, {hooke}), it is given by the magnitude of +the normal force: \begin\{equation\} F_\{n0\} = \|\mathbf\{F\}_n\| \end\{equation\} -For cohesive models such as {jkr} and {dmt}, the critical force is adjusted so that the critical tangential -force approaches \(\mu_t F_\{pulloff\}\), see "Marshall"_#Marshall2009, equation 43, and "Thornton"_#Thornton1991. -For both models, \(F_\{n0\}\) takes the form: +For cohesive models such as {jkr} and {dmt}, the critical force is +adjusted so that the critical tangential force approaches \(\mu_t +F_\{pulloff\}\), see "Marshall"_#Marshall2009, equation 43, and +"Thornton"_#Thornton1991. For both models, \(F_\{n0\}\) takes the +form: \begin\{equation\} F_\{n0\} = \|\mathbf\{F\}_ne + 2 F_\{pulloff\}\| \end\{equation\} -Where \(F_\{pulloff\} = 3\pi \gamma R \) for {jkr}, and \(F_\{pulloff\} = 4\pi \gamma R \) for {dmt}. +Where \(F_\{pulloff\} = 3\pi \gamma R \) for {jkr}, and +\(F_\{pulloff\} = 4\pi \gamma R \) for {dmt}. -The remaining tangential options all use accumulated tangential displacement (i.e. contact history). This -is discussed below in the context of the {linear_history} option, but the same treatment of the +The remaining tangential options all use accumulated tangential +displacement (i.e. contact history). This is discussed below in the +context of the {linear_history} option, but the same treatment of the accumulated displacement applies to the other options as well. For {tangential linear_history}, the tangential force is given by: @@ -284,49 +332,55 @@ For {tangential linear_history}, the tangential force is given by: \mathbf\{F\}_t = -min(\mu_t F_\{n0\}, \|-k_t\mathbf\{\xi\} + \mathbf\{F\}_\mathrm\{t,damp\}\|) \mathbf\{t\} \end\{equation\} -Here, \(\mathbf\{\xi\}\) is the tangential displacement accumulated during the entire -duration of the contact: +Here, \(\mathbf\{\xi\}\) is the tangential displacement accumulated +during the entire duration of the contact: \begin\{equation\} \mathbf\{\xi\} = \int_\{t0\}^t \mathbf\{v\}_\{t,rel\}(\tau) \mathrm\{d\}\tau \end\{equation\} -This accumulated tangential displacement must be adjusted to account for changes -in the frame of reference -of the contacting pair of particles during contact. This occurs due to the overall motion of the contacting particles -in a rigid-body-like fashion during the duration of the contact. There are two modes of motion -that are relevant: the 'tumbling' rotation of the contacting pair, which changes the orientation of the -plane in which tangential displacement occurs; and 'spinning' rotation of the contacting pair -about the vector connecting their centers of mass (\(\mathbf\{n\}\)). -Corrections due to the former mode of motion are -made by rotating the accumulated displacement into the plane that is tangential -to the contact vector at each step, -or equivalently removing any component of the tangential displacement -that lies along \(\mathbf\{n\}\), and rescaling to preserve the magnitude. -This follows the discussion in "Luding"_#Luding2008, see equation 17 and -relevant discussion in that work: +This accumulated tangential displacement must be adjusted to account +for changes in the frame of reference of the contacting pair of +particles during contact. This occurs due to the overall motion of the +contacting particles in a rigid-body-like fashion during the duration +of the contact. There are two modes of motion that are relevant: the +'tumbling' rotation of the contacting pair, which changes the +orientation of the plane in which tangential displacement occurs; and +'spinning' rotation of the contacting pair about the vector connecting +their centers of mass (\(\mathbf\{n\}\)). Corrections due to the +former mode of motion are made by rotating the accumulated +displacement into the plane that is tangential to the contact vector +at each step, or equivalently removing any component of the tangential +displacement that lies along \(\mathbf\{n\}\), and rescaling to +preserve the magnitude. This follows the discussion in +"Luding"_#Luding2008, see equation 17 and relevant discussion in that +work: \begin\{equation\} \mathbf\{\xi\} = \left(\mathbf\{\xi'\} - (\mathbf\{n\} \cdot \mathbf\{\xi'\})\mathbf\{n\}\right) \frac\{\|\mathbf\{\xi'\}\|\}\{\|\mathbf\{\xi'\}\| - \mathbf\{n\}\cdot\mathbf\{\xi'\}\} \label\{eq:rotate_displacements\} \end\{equation\} -Here, \(\mathbf\{\xi'\}\) is the accumulated displacement prior to the current time step and -\(\mathbf\{\xi\}\) is the corrected displacement. Corrections to the displacement -due to the second mode of motion described above (rotations about \(\mathbf\{n\}\)) -are not currently implemented, but are expected to be minor for most simulations. +Here, \(\mathbf\{\xi'\}\) is the accumulated displacement prior to the +current time step and \(\mathbf\{\xi\}\) is the corrected +displacement. Corrections to the displacement due to the second mode +of motion described above (rotations about \(\mathbf\{n\}\)) are not +currently implemented, but are expected to be minor for most +simulations. -Furthermore, when the tangential force exceeds the critical force, -the tangential displacement is re-scaled to match the value for the critical force (see "Luding"_#Luding2008, -equation 20 and related discussion): +Furthermore, when the tangential force exceeds the critical force, the +tangential displacement is re-scaled to match the value for the +critical force (see "Luding"_#Luding2008, equation 20 and related +discussion): \begin\{equation\} \mathbf\{\xi\} = -\frac\{1\}\{k_t\}\left(\mu_t F_\{n0\}\mathbf\{t\} + \mathbf\{F\}_\{t,damp\}\right) \end\{equation\} -The tangential force is added to the total normal force (elastic plus damping) to produce the total force -on the particle. The tangential force also acts at the contact point (defined as the center of the overlap region) -to induce a torque on each particle according to: +The tangential force is added to the total normal force (elastic plus +damping) to produce the total force on the particle. The tangential +force also acts at the contact point (defined as the center of the +overlap region) to induce a torque on each particle according to: \begin\{equation\} \mathbf\{\tau\}_i = -(R_i - 0.5 \delta) \mathbf\{n\} \times \mathbf\{F\}_t @@ -343,72 +397,90 @@ option by an additional factor of {a}, the radius of the contact region. The tan \mathbf\{F\}_t = -min(\mu_t F_\{n0\}, \|-k_t a \mathbf\{\xi\} + \mathbf\{F\}_\mathrm\{t,damp\}\|) \mathbf\{t\} \end\{equation\} -Here, {a} is the radius of the contact region, given by \(a = \delta R\) for all normal contact models, -except for {jkr}, where it is given implicitly by \(\delta = a^2/R - 2\sqrt\{\pi \gamma a/E\}\), -see discussion above. To match the Mindlin solution, one should set \(k_t = 8G\), where -\(G\) is the shear modulus, related to Young's modulus \(E\) by \(G = E/(2(1+\nu))\), where \(\nu\) -is Poisson's ratio. This can also be achieved by specifying {NULL} for \(k_t\), in which case -a normal contact model that specifies material parameters \(E\) and \(\nu\) is required (e.g. {hertz/material}, -{dmt} or {jkr}). In this case, mixing of the shear modulus for different particle types {i} and {j} is done according -to: +Here, {a} is the radius of the contact region, given by \(a = \delta +R\) for all normal contact models, except for {jkr}, where it is given +implicitly by \(\delta = a^2/R - 2\sqrt\{\pi \gamma a/E\}\), see +discussion above. To match the Mindlin solution, one should set \(k_t += 8G\), where \(G\) is the shear modulus, related to Young's modulus +\(E\) by \(G = E/(2(1+\nu))\), where \(\nu\) is Poisson's ratio. This +can also be achieved by specifying {NULL} for \(k_t\), in which case a +normal contact model that specifies material parameters \(E\) and +\(\nu\) is required (e.g. {hertz/material}, {dmt} or {jkr}). In this +case, mixing of the shear modulus for different particle types {i} and +{j} is done according to: + \begin\{equation\} 1/G = 2(2-\nu_i)(1+\nu_i)/E_i + 2(2-\nu_j)(1+\nu_j)/E_j \end\{equation\} -The {mindlin_rescale} option uses the same form as {mindlin}, but the magnitude of the tangential -displacement is re-scaled as the contact unloads, i.e. if \(a < a_\{t_\{n-1\}\}\): +The {mindlin_rescale} option uses the same form as {mindlin}, but the +magnitude of the tangential displacement is re-scaled as the contact +unloads, i.e. if \(a < a_\{t_\{n-1\}\}\): + \begin\{equation\} \mathbf\{\xi\} = \mathbf\{\xi_\{t_\{n-1\}\}\} \frac\{a\}\{a_\{t_\{n-1\}\}\} \end\{equation\} -Here, \(t_\{n-1\}\) indicates the value at the previous time step. This rescaling -accounts for the fact that a decrease in the contact area upon unloading leads to the contact -being unable to support the previous tangential loading, and spurious energy is created -without the rescaling above ("Walton"_#WaltonPC ). See also discussion in "Thornton et al, 2013"_#Thornton2013 -, particularly equation 18(b) of that work and associated discussion. +Here, \(t_\{n-1\}\) indicates the value at the previous time +step. This rescaling accounts for the fact that a decrease in the +contact area upon unloading leads to the contact being unable to +support the previous tangential loading, and spurious energy is +created without the rescaling above ("Walton"_#WaltonPC ). See also +discussion in "Thornton et al, 2013"_#Thornton2013 , particularly +equation 18(b) of that work and associated discussion. :line -The optional {rolling} keyword enables rolling friction, which resists pure rolling -motion of particles. The options currently supported are: +The optional {rolling} keyword enables rolling friction, which resists +pure rolling motion of particles. The options currently supported are: {none} {sds} : \(k_\{roll\}\), \(\gamma_\{roll\}\), \(\mu_\{roll\}\) :ol If the {rolling} keyword is not specified, the model defaults to {none}. -For {rolling sds}, rolling friction is computed via a spring-dashpot-slider, using a -'pseudo-force' formulation, as detailed by "Luding"_#Luding2008. Unlike the formulation -in "Marshall"_#Marshall2009, this allows for the required adjustment of -rolling displacement due to changes in the frame of reference of the contacting pair. -The rolling pseudo-force is computed analogously to the tangential force: +For {rolling sds}, rolling friction is computed via a +spring-dashpot-slider, using a 'pseudo-force' formulation, as detailed +by "Luding"_#Luding2008. Unlike the formulation in +"Marshall"_#Marshall2009, this allows for the required adjustment of +rolling displacement due to changes in the frame of reference of the +contacting pair. The rolling pseudo-force is computed analogously to +the tangential force: \begin\{equation\} \mathbf\{F\}_\{roll,0\} = k_\{roll\} \mathbf\{\xi\}_\{roll\} - \gamma_\{roll\} \mathbf\{v\}_\{roll\} \end\{equation\} -Here, \(\mathbf\{v\}_\{roll\} = -R(\mathbf\{\Omega\}_i - \mathbf\{\Omega\}_j) \times \mathbf\{n\}\) is the -relative rolling velocity, as given in "Wang et al"_#Wang2015 and "Luding"_#Luding2008. This differs -from the expressions given by "Kuhn and Bagi"_#Kuhn2004 and used in "Marshall"_#Marshall2009; -see "Wang et al"_#Wang2015 for details. The rolling displacement is given by: +Here, \(\mathbf\{v\}_\{roll\} = -R(\mathbf\{\Omega\}_i - +\mathbf\{\Omega\}_j) \times \mathbf\{n\}\) is the relative rolling +velocity, as given in "Wang et al"_#Wang2015 and +"Luding"_#Luding2008. This differs from the expressions given by "Kuhn +and Bagi"_#Kuhn2004 and used in "Marshall"_#Marshall2009; see "Wang et +al"_#Wang2015 for details. The rolling displacement is given by: \begin\{equation\} \mathbf\{\xi\}_\{roll\} = \int_\{t_0\}^t \mathbf\{v\}_\{roll\} (\tau) \mathrm\{d\} \tau \end\{equation\} -A Coulomb friction criterion truncates the rolling pseudo-force if it exceeds a critical value: +A Coulomb friction criterion truncates the rolling pseudo-force if it +exceeds a critical value: + \begin\{equation\} \mathbf\{F\}_\{roll\} = min(\mu_\{roll\} F_\{n,0\}, \|\mathbf\{F\}_\{roll,0\}\|)\mathbf\{k\} \end\{equation\} -Here, \(\mathbf\{k\} = \mathbf\{v\}_\{roll\}/\|\mathbf\{v\}_\{roll\}\|\) is the direction of the pseudo-force. -As with tangential displacement, the rolling displacement is rescaled when the critical -force is exceeded, so that the spring length corresponds the critical force. Additionally, the -displacement is adjusted to account for rotations of the frame of reference of the two -contacting particles in a manner analogous to the tangential displacement. +Here, \(\mathbf\{k\} = +\mathbf\{v\}_\{roll\}/\|\mathbf\{v\}_\{roll\}\|\) is the direction of +the pseudo-force. As with tangential displacement, the rolling +displacement is rescaled when the critical force is exceeded, so that +the spring length corresponds the critical force. Additionally, the +displacement is adjusted to account for rotations of the frame of +reference of the two contacting particles in a manner analogous to the +tangential displacement. -The rolling pseudo-force does not contribute to the total force on either particle (hence 'pseudo'), -but acts only to induce an equal and opposite torque on each particle, according to: +The rolling pseudo-force does not contribute to the total force on +either particle (hence 'pseudo'), but acts only to induce an equal and +opposite torque on each particle, according to: \begin\{equation\} \tau_\{roll,i\} = R_\{eff\} \mathbf\{n\} \times \mathbf\{F\}_\{roll\} @@ -420,9 +492,10 @@ but acts only to induce an equal and opposite torque on each particle, according :line -The optional {twisting} keyword enables twisting friction, which resists -rotation of two contacting particles about the vector \(\mathbf\{n\}\) that connects their -centers. The options currently supported are: +The optional {twisting} keyword enables twisting friction, which +resists rotation of two contacting particles about the vector +\(\mathbf\{n\}\) that connects their centers. The options currently +supported are: {none} {sds} : \(k_\{twist\}\), \(\gamma_\{twist\}\), \(\mu_\{twist\}\) @@ -430,36 +503,42 @@ centers. The options currently supported are: If the {twisting} keyword is not specified, the model defaults to {none}. -For both {twisting sds} and {twisting marshall}, a history-dependent spring-dashpot-slider is used to compute the twisting -torque. Because twisting displacement is a scalar, there is no need to adjust for changes -in the frame of reference due to rotations of the particle pair. The formulation in -"Marshall"_#Marshall2009 therefore provides the most straightforward treatment: +For both {twisting sds} and {twisting marshall}, a history-dependent +spring-dashpot-slider is used to compute the twisting torque. Because +twisting displacement is a scalar, there is no need to adjust for +changes in the frame of reference due to rotations of the particle +pair. The formulation in "Marshall"_#Marshall2009 therefore provides +the most straightforward treatment: \begin\{equation\} \tau_\{twist,0\} = -k_\{twist\}\xi_\{twist\} - \gamma_\{twist\}\Omega_\{twist\} \end\{equation\} -Here \(\xi_\{twist\} = \int_\{t_0\}^t \Omega_\{twist\} (\tau) \mathrm\{d\}\tau\) is the twisting -angular displacement, and \(\Omega_\{twist\} = (\mathbf\{\Omega\}_i - \mathbf\{\Omega\}_j) \cdot \mathbf\{n\}\) -is the relative twisting angular velocity. The torque is then truncated according to: +Here \(\xi_\{twist\} = \int_\{t_0\}^t \Omega_\{twist\} (\tau) +\mathrm\{d\}\tau\) is the twisting angular displacement, and +\(\Omega_\{twist\} = (\mathbf\{\Omega\}_i - \mathbf\{\Omega\}_j) \cdot +\mathbf\{n\}\) is the relative twisting angular velocity. The torque +is then truncated according to: \begin\{equation\} \tau_\{twist\} = min(\mu_\{twist\} F_\{n,0\}, \tau_\{twist,0\}) \end\{equation\} -Similar to the sliding and rolling displacement, the angular displacement is -rescaled so that it corresponds to the critical value if the twisting torque -exceeds this critical value: +Similar to the sliding and rolling displacement, the angular +displacement is rescaled so that it corresponds to the critical value +if the twisting torque exceeds this critical value: \begin\{equation\} \xi_\{twist\} = \frac\{1\}\{k_\{twist\}\} (\mu_\{twist\} F_\{n,0\}sgn(\Omega_\{twist\}) - \gamma_\{twist\}\Omega_\{twist\}) \end\{equation\} -For {twisting sds}, the coefficients \(k_\{twist\}, \gamma_\{twist\}\) and \(\mu_\{twist\}\) are -simply the user input parameters that follow the {twisting sds} keywords in the {pair_coeff} command. +For {twisting sds}, the coefficients \(k_\{twist\}, \gamma_\{twist\}\) +and \(\mu_\{twist\}\) are simply the user input parameters that follow +the {twisting sds} keywords in the {pair_coeff} command. -For {twisting_marshall}, the coefficients are expressed in terms of sliding friction coefficients, -as discussed in "Marshall"_#Marshall2009 (see equations 32 and 33 of that work): +For {twisting_marshall}, the coefficients are expressed in terms of +sliding friction coefficients, as discussed in +"Marshall"_#Marshall2009 (see equations 32 and 33 of that work): \begin\{equation\} k_\{twist\} = 0.5k_ta^2 @@ -485,19 +564,25 @@ Finally, the twisting torque on each particle is given by: :line -LAMMPS automatically sets pairwise cutoff values for {pair_style granular} based on particle radii (and in the case -of {jkr} pull-off distances). In the vast majority of situations, this is adequate. -However, a cutoff value can optionally be appended to the {pair_style granular} command to specify -a global cutoff (i.e. a cutoff for all atom types). Additionally, the optional {cutoff} keyword -can be passed to the {pair_coeff} command, followed by a cutoff value. -This will set a pairwise cutoff for the atom types in the {pair_coeff} command. -These options may be useful in some rare cases where the automatic cutoff determination is not sufficient, e.g. -if particle diameters are being modified via the {fix adapt} command. In that case, the global cutoff -specified as part of the {pair_style granular} command is applied to all atom types, unless it is -overridden for a given atom type combination by the {cutoff} value specified in the {pair coeff} command. -If {cutoff} is only specified in the {pair coeff} command and no global -cutoff is appended to the {pair_style granular} command, then LAMMPS will use that cutoff for the specified -atom type combination, and automatically set pairwise cutoffs for the remaining atom types. +LAMMPS automatically sets pairwise cutoff values for {pair_style +granular} based on particle radii (and in the case of {jkr} pull-off +distances). In the vast majority of situations, this is adequate. +However, a cutoff value can optionally be appended to the {pair_style +granular} command to specify a global cutoff (i.e. a cutoff for all +atom types). Additionally, the optional {cutoff} keyword can be passed +to the {pair_coeff} command, followed by a cutoff value. This will +set a pairwise cutoff for the atom types in the {pair_coeff} command. +These options may be useful in some rare cases where the automatic +cutoff determination is not sufficient, e.g. if particle diameters +are being modified via the {fix adapt} command. In that case, the +global cutoff specified as part of the {pair_style granular} command +is applied to all atom types, unless it is overridden for a given atom +type combination by the {cutoff} value specified in the {pair coeff} +command. If {cutoff} is only specified in the {pair coeff} command +and no global cutoff is appended to the {pair_style granular} command, +then LAMMPS will use that cutoff for the specified atom type +combination, and automatically set pairwise cutoffs for the remaining +atom types. :line @@ -529,20 +614,21 @@ The "pair_modify"_pair_modify.html mix, shift, table, and tail options are not relevant for granular pair styles. Mixing of coefficients is carried out using geometric averaging for -most quantities, e.g. if friction coefficient for type 1-type 1 interactions -is set to \(\mu_1\), and friction coefficient for type 2-type 2 interactions -is set to \(\mu_2\), the friction coefficient for type1-type2 interactions -is computed as \(\sqrt\{\mu_1\mu_2\}\) (unless explicitly specified to -a different value by a {pair_coeff 1 2 ...} command. The exception to this is -elastic modulus, only applicable to {hertz/material}, {dmt} and {jkr} normal -contact models. In that case, the effective elastic modulus is computed as: +most quantities, e.g. if friction coefficient for type 1-type 1 +interactions is set to \(\mu_1\), and friction coefficient for type +2-type 2 interactions is set to \(\mu_2\), the friction coefficient +for type1-type2 interactions is computed as \(\sqrt\{\mu_1\mu_2\}\) +(unless explicitly specified to a different value by a {pair_coeff 1 2 +...} command. The exception to this is elastic modulus, only +applicable to {hertz/material}, {dmt} and {jkr} normal contact +models. In that case, the effective elastic modulus is computed as: \begin\{equation\} E_\{eff,ij\} = \left(\frac\{1-\nu_i^2\}\{E_i\} + \frac\{1-\nu_j^2\}\{E_j\}\right)^\{-1\} \end\{equation\} -If the {i-j} coefficients \(E_\{ij\}\) and \(\nu_\{ij\}\) are explicitly specified, -the effective modulus is computed as: +If the {i-j} coefficients \(E_\{ij\}\) and \(\nu_\{ij\}\) are +explicitly specified, the effective modulus is computed as: \begin\{equation\} E_\{eff,ij\} = \left(\frac\{1-\nu_\{ij\}^2\}\{E_\{ij\}\} + \frac\{1-\nu_\{ij\}^2\}\{E_\{ij\}\}\right)^\{-1\} @@ -610,57 +696,70 @@ compute depend on atom velocities. See the [Default:] -For the {pair_coeff} settings: {damping viscoelastic}, {rolling none}, {twisting none} +For the {pair_coeff} settings: {damping viscoelastic}, {rolling none}, +{twisting none}. [References:] :link(Brill1996) -[(Brilliantov et al, 1996)] Brilliantov, N. V., Spahn, F., Hertzsch, J. M., & Poschel, T. (1996). -Model for collisions in granular gases. Physical review E, 53(5), 5382. +[(Brilliantov et al, 1996)] Brilliantov, N. V., Spahn, F., Hertzsch, +J. M., & Poschel, T. (1996). Model for collisions in granular +gases. Physical review E, 53(5), 5382. -:link(Tsuji1992) -[(Tsuji et al, 1992)] Tsuji, Y., Tanaka, T., & Ishida, T. (1992). Lagrangian numerical simulation of plug flow of -cohesionless particles in a horizontal pipe. Powder technology, 71(3), 239-250. +:link(Tsuji1992) +[(Tsuji et al, 1992)] Tsuji, Y., Tanaka, T., & Ishida, +T. (1992). Lagrangian numerical simulation of plug flow of +cohesionless particles in a horizontal pipe. Powder technology, 71(3), +239-250. :link(JKR1971) -[(Johnson et al, 1971)] Johnson, K. L., Kendall, K., & Roberts, A. D. (1971). -Surface energy and the contact of elastic solids. Proc. R. Soc. Lond. A, 324(1558), 301-313. +[(Johnson et al, 1971)] Johnson, K. L., Kendall, K., & Roberts, +A. D. (1971). Surface energy and the contact of elastic +solids. Proc. R. Soc. Lond. A, 324(1558), 301-313. :link(DMT1975) -[Derjaguin et al, 1975)] Derjaguin, B. V., Muller, V. M., & Toporov, Y. P. (1975). Effect of contact deformations on the -adhesion of particles. Journal of Colloid and interface science, 53(2), 314-326. +[Derjaguin et al, 1975)] Derjaguin, B. V., Muller, V. M., & Toporov, +Y. P. (1975). Effect of contact deformations on the adhesion of +particles. Journal of Colloid and interface science, 53(2), 314-326. :link(Luding2008) -[(Luding, 2008)] Luding, S. (2008). Cohesive, frictional powders: contact models for tension. Granular matter, 10(4), 235. +[(Luding, 2008)] Luding, S. (2008). Cohesive, frictional powders: +contact models for tension. Granular matter, 10(4), 235. :link(Marshall2009) -[(Marshall, 2009)] Marshall, J. S. (2009). Discrete-element modeling of particulate aerosol flows. -Journal of Computational Physics, 228(5), 1541-1561. +[(Marshall, 2009)] Marshall, J. S. (2009). Discrete-element modeling +of particulate aerosol flows. Journal of Computational Physics, +228(5), 1541-1561. :link(Silbert2001) -[(Silbert, 2001)] Silbert, L. E., Ertas, D., Grest, G. S., Halsey, T. C., Levine, D., & Plimpton, S. J. (2001). -Granular flow down an inclined plane: Bagnold scaling and rheology. Physical Review E, 64(5), 051302. +[(Silbert, 2001)] Silbert, L. E., Ertas, D., Grest, G. S., Halsey, +T. C., Levine, D., & Plimpton, S. J. (2001). Granular flow down an +inclined plane: Bagnold scaling and rheology. Physical Review E, +64(5), 051302. :link(Kuhn2004) -[(Kuhn and Bagi, 2005)] Kuhn, M. R., & Bagi, K. (2004). Contact rolling and deformation in granular media. -International journal of solids and structures, 41(21), 5793-5820. +[(Kuhn and Bagi, 2005)] Kuhn, M. R., & Bagi, K. (2004). Contact +rolling and deformation in granular media. International journal of +solids and structures, 41(21), 5793-5820. :link(Wang2015) -[(Wang et al, 2015)] Wang, Y., Alonso-Marroquin, F., & Guo, W. W. (2015). -Rolling and sliding in 3-D discrete element models. Particuology, 23, 49-55. +[(Wang et al, 2015)] Wang, Y., Alonso-Marroquin, F., & Guo, +W. W. (2015). Rolling and sliding in 3-D discrete element +models. Particuology, 23, 49-55. :link(Thornton1991) -[(Thornton, 1991)] Thornton, C. (1991). Interparticle sliding in the presence of adhesion. -J. Phys. D: Appl. Phys. 24 1942 +[(Thornton, 1991)] Thornton, C. (1991). Interparticle sliding in the +presence of adhesion. J. Phys. D: Appl. Phys. 24 1942 :link(Mindlin1949) -[(Mindlin, 1949)] Mindlin, R. D. (1949). Compliance of elastic bodies in contact. -J. Appl. Mech., ASME 16, 259-268. +[(Mindlin, 1949)] Mindlin, R. D. (1949). Compliance of elastic bodies +in contact. J. Appl. Mech., ASME 16, 259-268. :link(Thornton2013) -[(Thornton et al, 2013)] Thornton, C., Cummins, S. J., & Cleary, P. W. (2013). -An investigation of the comparative behaviour of alternative contact force models -during inelastic collisions. Powder Technology, 233, 30-46. +[(Thornton et al, 2013)] Thornton, C., Cummins, S. J., & Cleary, +P. W. (2013). An investigation of the comparative behaviour of +alternative contact force models during inelastic collisions. Powder +Technology, 233, 30-46. :link(WaltonPC) [(Otis R. Walton)] Walton, O.R., Personal Communication diff --git a/src/GRANULAR/fix_wall_gran.cpp b/src/GRANULAR/fix_wall_gran.cpp index c63a2c0ba8..9925c37e4b 100644 --- a/src/GRANULAR/fix_wall_gran.cpp +++ b/src/GRANULAR/fix_wall_gran.cpp @@ -124,21 +124,27 @@ FixWallGran::FixWallGran(LAMMPS *lmp, int narg, char **arg) : roll_model = twist_model = NONE; while (iarg < narg) { if (strcmp(arg[iarg], "hooke") == 0) { - if (iarg + 2 >= narg) error->all(FLERR,"Illegal fix wall/gran command, not enough parameters provided for Hooke option"); + if (iarg + 2 >= narg) + error->all(FLERR,"Illegal fix wall/gran command, " + "not enough parameters provided for Hooke option"); normal_model = NORMAL_HOOKE; normal_coeffs[0] = force->numeric(FLERR,arg[iarg+1]); //kn normal_coeffs[1] = force->numeric(FLERR,arg[iarg+2]); //damping iarg += 3; } else if (strcmp(arg[iarg], "hertz") == 0) { int num_coeffs = 2; - if (iarg + num_coeffs >= narg) error->all(FLERR,"Illegal fix wall/gran command, not enough parameters provided for Hertz option"); + if (iarg + num_coeffs >= narg) + error->all(FLERR,"Illegal fix wall/gran command, " + "not enough parameters provided for Hertz option"); normal_model = NORMAL_HERTZ; normal_coeffs[0] = force->numeric(FLERR,arg[iarg+1]); //kn normal_coeffs[1] = force->numeric(FLERR,arg[iarg+2]); //damping iarg += num_coeffs+1; } else if (strcmp(arg[iarg], "hertz/material") == 0) { int num_coeffs = 3; - if (iarg + num_coeffs >= narg) error->all(FLERR,"Illegal fix wall/gran command, not enough parameters provided for Hertz option"); + if (iarg + num_coeffs >= narg) + error->all(FLERR,"Illegal fix wall/gran command, " + "not enough parameters provided for Hertz option"); normal_model = HERTZ_MATERIAL; Emod = force->numeric(FLERR,arg[iarg+1]); //E normal_coeffs[1] = force->numeric(FLERR,arg[iarg+2]); //damping @@ -147,7 +153,9 @@ FixWallGran::FixWallGran(LAMMPS *lmp, int narg, char **arg) : normal_coeffs[2] = poiss; iarg += num_coeffs+1; } else if (strcmp(arg[iarg], "dmt") == 0) { - if (iarg + 4 >= narg) error->all(FLERR,"Illegal fix wall/gran command, not enough parameters provided for Hertz option"); + if (iarg + 4 >= narg) + error->all(FLERR,"Illegal fix wall/gran command, " + "not enough parameters provided for Hertz option"); normal_model = DMT; Emod = force->numeric(FLERR,arg[iarg+1]); //E normal_coeffs[1] = force->numeric(FLERR,arg[iarg+2]); //damping @@ -157,7 +165,9 @@ FixWallGran::FixWallGran(LAMMPS *lmp, int narg, char **arg) : normal_coeffs[3] = force->numeric(FLERR,arg[iarg+4]); //cohesion iarg += 5; } else if (strcmp(arg[iarg], "jkr") == 0) { - if (iarg + 4 >= narg) error->all(FLERR,"Illegal wall/gran command, not enough parameters provided for JKR option"); + if (iarg + 4 >= narg) + error->all(FLERR,"Illegal wall/gran command, " + "not enough parameters provided for JKR option"); beyond_contact = 1; normal_model = JKR; Emod = force->numeric(FLERR,arg[iarg+1]); //E @@ -168,7 +178,9 @@ FixWallGran::FixWallGran(LAMMPS *lmp, int narg, char **arg) : normal_coeffs[3] = force->numeric(FLERR,arg[iarg+4]); //cohesion iarg += 5; } else if (strcmp(arg[iarg], "damping") == 0) { - if (iarg+1 >= narg) error->all(FLERR, "Illegal wall/gran command, not enough parameters provided for damping model"); + if (iarg+1 >= narg) + error->all(FLERR, "Illegal wall/gran command, " + "not enough parameters provided for damping model"); if (strcmp(arg[iarg+1], "velocity") == 0) { damping_model = VELOCITY; iarg += 1; @@ -178,58 +190,80 @@ FixWallGran::FixWallGran(LAMMPS *lmp, int narg, char **arg) : } else if (strcmp(arg[iarg+1], "tsuji") == 0) { damping_model = TSUJI; iarg += 1; - } else error->all(FLERR, "Illegal wall/gran command, unrecognized damping model"); + } else error->all(FLERR, "Illegal wall/gran command, " + "unrecognized damping model"); iarg += 1; } else if (strcmp(arg[iarg], "tangential") == 0) { - if (iarg + 1 >= narg) error->all(FLERR,"Illegal pair_coeff command, must specify tangential model after 'tangential' keyword"); + if (iarg + 1 >= narg) + error->all(FLERR,"Illegal pair_coeff command, " + "must specify tangential model after tangential keyword"); if (strcmp(arg[iarg+1], "linear_nohistory") == 0) { - if (iarg + 3 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for tangential model"); + if (iarg + 3 >= narg) + error->all(FLERR,"Illegal pair_coeff command, " + "not enough parameters provided for tangential model"); tangential_model = TANGENTIAL_NOHISTORY; tangential_coeffs[0] = 0; - tangential_coeffs[1] = force->numeric(FLERR,arg[iarg+2]); //gammat - tangential_coeffs[2] = force->numeric(FLERR,arg[iarg+3]); //friction coeff. + // gammat and friction coeff + tangential_coeffs[1] = force->numeric(FLERR,arg[iarg+2]); + tangential_coeffs[2] = force->numeric(FLERR,arg[iarg+3]); iarg += 4; } else if ((strcmp(arg[iarg+1], "linear_history") == 0) || (strcmp(arg[iarg+1], "mindlin") == 0) || (strcmp(arg[iarg+1], "mindlin_rescale") == 0)) { - if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for tangential model"); - if (strcmp(arg[iarg+1], "linear_history") == 0) tangential_model = TANGENTIAL_HISTORY; - else if (strcmp(arg[iarg+1], "mindlin") == 0) tangential_model = TANGENTIAL_MINDLIN; - else if (strcmp(arg[iarg+1], "mindlin_rescale") == 0) tangential_model = TANGENTIAL_MINDLIN_RESCALE; - if ((tangential_model == TANGENTIAL_MINDLIN || tangential_model == TANGENTIAL_MINDLIN_RESCALE) && + if (iarg + 4 >= narg) + error->all(FLERR,"Illegal pair_coeff command, " + "not enough parameters provided for tangential model"); + if (strcmp(arg[iarg+1], "linear_history") == 0) + tangential_model = TANGENTIAL_HISTORY; + else if (strcmp(arg[iarg+1], "mindlin") == 0) + tangential_model = TANGENTIAL_MINDLIN; + else if (strcmp(arg[iarg+1], "mindlin_rescale") == 0) + tangential_model = TANGENTIAL_MINDLIN_RESCALE; + if ((tangential_model == TANGENTIAL_MINDLIN || + tangential_model == TANGENTIAL_MINDLIN_RESCALE) && (strcmp(arg[iarg+2], "NULL") == 0)) { if (normal_model == NORMAL_HERTZ || normal_model == NORMAL_HOOKE) { - error->all(FLERR, "NULL setting for Mindlin tangential stiffness requires a normal contact model that specifies material properties"); + error->all(FLERR, "NULL setting for Mindlin tangential " + "stiffness requires a normal contact model " + "that specifies material properties"); } tangential_coeffs[0] = 4*(2-poiss)*(1+poiss)/Emod; } else { tangential_coeffs[0] = force->numeric(FLERR,arg[iarg+2]); //kt } tangential_history = 1; - tangential_coeffs[1] = force->numeric(FLERR,arg[iarg+3]); //gammat - tangential_coeffs[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. + // gammat and friction coeff + tangential_coeffs[1] = force->numeric(FLERR,arg[iarg+3]); + tangential_coeffs[2] = force->numeric(FLERR,arg[iarg+4]); iarg += 5; } else { - error->all(FLERR, "Illegal pair_coeff command, tangential model not recognized"); + error->all(FLERR, "Illegal pair_coeff command, " + "tangential model not recognized"); } } else if (strcmp(arg[iarg], "rolling") == 0) { - if (iarg + 1 >= narg) error->all(FLERR, "Illegal wall/gran command, not enough parameters"); + if (iarg + 1 >= narg) + error->all(FLERR, "Illegal wall/gran command, not enough parameters"); if (strcmp(arg[iarg+1], "none") == 0) { roll_model = ROLL_NONE; iarg += 2; } else if (strcmp(arg[iarg+1], "sds") == 0) { - if (iarg + 4 >= narg) error->all(FLERR,"Illegal wall/gran command, not enough parameters provided for rolling model"); + if (iarg + 4 >= narg) + error->all(FLERR,"Illegal wall/gran command, " + "not enough parameters provided for rolling model"); roll_model = ROLL_SDS; roll_history = 1; - roll_coeffs[0] = force->numeric(FLERR,arg[iarg+2]); //kR - roll_coeffs[1] = force->numeric(FLERR,arg[iarg+3]); //gammaR - roll_coeffs[2] = force->numeric(FLERR,arg[iarg+4]); //rolling friction coeff. + // kR, gammaR, rolling friction coeff + roll_coeffs[0] = force->numeric(FLERR,arg[iarg+2]); + roll_coeffs[1] = force->numeric(FLERR,arg[iarg+3]); + roll_coeffs[2] = force->numeric(FLERR,arg[iarg+4]); iarg += 5; } else { - error->all(FLERR, "Illegal wall/gran command, rolling friction model not recognized"); + error->all(FLERR, "Illegal wall/gran command, " + "rolling friction model not recognized"); } } else if (strcmp(arg[iarg], "twisting") == 0) { - if (iarg + 1 >= narg) error->all(FLERR, "Illegal wall/gran command, not enough parameters"); + if (iarg + 1 >= narg) + error->all(FLERR, "Illegal wall/gran command, not enough parameters"); if (strcmp(arg[iarg+1], "none") == 0) { twist_model = TWIST_NONE; iarg += 2; @@ -238,7 +272,9 @@ FixWallGran::FixWallGran(LAMMPS *lmp, int narg, char **arg) : twist_history = 1; iarg += 2; } else if (strcmp(arg[iarg+1], "sds") == 0) { - if (iarg + 4 >= narg) error->all(FLERR,"Illegal wall/gran command, not enough parameters provided for twist model"); + if (iarg + 4 >= narg) + error->all(FLERR,"Illegal wall/gran command, " + "not enough parameters provided for twist model"); twist_model = TWIST_SDS; twist_history = 1; twist_coeffs[0] = force->numeric(FLERR,arg[iarg+2]); //kt @@ -246,7 +282,8 @@ FixWallGran::FixWallGran(LAMMPS *lmp, int narg, char **arg) : twist_coeffs[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. iarg += 5; } else { - error->all(FLERR, "Illegal wall/gran command, twisting friction model not recognized"); + error->all(FLERR, "Illegal wall/gran command, " + "twisting friction model not recognized"); } } else if (strcmp(arg[iarg], "xplane") == 0 || strcmp(arg[iarg], "yplane") == 0 || @@ -472,8 +509,6 @@ void FixWallGran::init() 27.467*pow(cor,4)-18.022*pow(cor,5)+ 4.8218*pow(cor,6); } - - } /* ---------------------------------------------------------------------- */ @@ -616,7 +651,8 @@ void FixWallGran::post_force(int /*vflag*/) else { if (pairstyle == GRANULAR && normal_model == JKR && use_history) { if ((history_one[i][0] == 0) && (rsq > radius[i]*radius[i])) { - // Particles have not contacted yet, and are outside of contact distance + // Particles have not contacted yet, + // and are outside of contact distance for (j = 0; j < size_history; j++) history_one[i][j] = 0.0; continue; @@ -824,7 +860,8 @@ void FixWallGran::hooke_history(double rsq, double dx, double dy, double dz, history[1] += vtr2*dt; history[2] += vtr3*dt; } - shrmag = sqrt(history[0]*history[0] + history[1]*history[1] + history[2]*history[2]); + shrmag = sqrt(history[0]*history[0] + history[1]*history[1] + + history[2]*history[2]); // rotate shear displacements @@ -954,7 +991,8 @@ void FixWallGran::hertz_history(double rsq, double dx, double dy, double dz, history[1] += vtr2*dt; history[2] += vtr3*dt; } - shrmag = sqrt(history[0]*history[0] + history[1]*history[1] + history[2]*history[2]); + shrmag = sqrt(history[0]*history[0] + history[1]*history[1] + + history[2]*history[2]); // rotate history displacements @@ -1015,372 +1053,382 @@ void FixWallGran::hertz_history(double rsq, double dx, double dy, double dz, torque[2] -= radius*tor3; } +/* ---------------------------------------------------------------------- */ void FixWallGran::granular(double rsq, double dx, double dy, double dz, - double *vwall, double rwall, double *v, - double *f, double *omega, double *torque, - double radius, double meff, double *history, - double *contact) + double *vwall, double rwall, double *v, + double *f, double *omega, double *torque, + double radius, double meff, double *history, + double *contact) { - double fx,fy,fz,nx,ny,nz; - double radsum,r,rinv; - double Reff, delta, dR, dR2; + double fx,fy,fz,nx,ny,nz; + double radsum,r,rinv; + double Reff, delta, dR, dR2; - double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3; - double wr1,wr2,wr3; - double vtr1,vtr2,vtr3,vrel; + double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3; + double wr1,wr2,wr3; + double vtr1,vtr2,vtr3,vrel; - double knfac, damp_normal, damp_normal_prefactor; - double k_tangential, damp_tangential; - double Fne, Ft, Fdamp, Fntot, Fncrit, Fscrit, Frcrit; - double fs, fs1, fs2, fs3; + double knfac, damp_normal, damp_normal_prefactor; + double k_tangential, damp_tangential; + double Fne, Ft, Fdamp, Fntot, Fncrit, Fscrit, Frcrit; + double fs, fs1, fs2, fs3; - double tor1,tor2,tor3; - double relrot1,relrot2,relrot3,vrl1,vrl2,vrl3; + double tor1,tor2,tor3; + double relrot1,relrot2,relrot3,vrl1,vrl2,vrl3; - //For JKR - double R2, coh, F_pulloff, a, a2, E; - double t0, t1, t2, t3, t4, t5, t6; - double sqrt1, sqrt2, sqrt3; + // for JKR + double R2, coh, F_pulloff, a, a2, E; + double t0, t1, t2, t3, t4, t5, t6; + double sqrt1, sqrt2, sqrt3; - //Rolling - double k_roll, damp_roll; - double torroll1, torroll2, torroll3; - double rollmag, rolldotn, scalefac; - double fr, fr1, fr2, fr3; + // rolling + double k_roll, damp_roll; + double torroll1, torroll2, torroll3; + double rollmag, rolldotn, scalefac; + double fr, fr1, fr2, fr3; - //Twisting - double k_twist, damp_twist, mu_twist; - double signtwist, magtwist, magtortwist, Mtcrit; - double tortwist1, tortwist2, tortwist3; + // twisting + double k_twist, damp_twist, mu_twist; + double signtwist, magtwist, magtortwist, Mtcrit; + double tortwist1, tortwist2, tortwist3; - double shrmag,rsht; + double shrmag,rsht; - r = sqrt(rsq); - radsum = rwall + radius; + r = sqrt(rsq); + radsum = rwall + radius; - E = normal_coeffs[0]; + E = normal_coeffs[0]; - radsum = radius + rwall; - if (rwall == 0) Reff = radius; - else Reff = radius*rwall/(radius+rwall); + radsum = radius + rwall; + if (rwall == 0) Reff = radius; + else Reff = radius*rwall/(radius+rwall); - rinv = 1.0/r; + rinv = 1.0/r; - nx = dx*rinv; - ny = dy*rinv; - nz = dz*rinv; + nx = dx*rinv; + ny = dy*rinv; + nz = dz*rinv; - // relative translational velocity + // relative translational velocity - vr1 = v[0] - vwall[0]; - vr2 = v[1] - vwall[1]; - vr3 = v[2] - vwall[2]; + vr1 = v[0] - vwall[0]; + vr2 = v[1] - vwall[1]; + vr3 = v[2] - vwall[2]; - // normal component + // normal component - vnnr = vr1*nx + vr2*ny + vr3*nz; //v_R . n - vn1 = nx*vnnr; - vn2 = ny*vnnr; - vn3 = nz*vnnr; + vnnr = vr1*nx + vr2*ny + vr3*nz; //v_R . n + vn1 = nx*vnnr; + vn2 = ny*vnnr; + vn3 = nz*vnnr; - delta = radsum - r; - dR = delta*Reff; - if (normal_model == JKR) { - history[0] = 1.0; - E *= THREEQUARTERS; - R2=Reff*Reff; - coh = normal_coeffs[3]; - dR2 = dR*dR; - t0 = coh*coh*R2*R2*E; - t1 = PI27SQ*t0; - t2 = 8*dR*dR2*E*E*E; - t3 = 4*dR2*E; - sqrt1 = MAX(0, t0*(t1+2*t2)); //In case of sqrt(0) < 0 due to precision issues - t4 = cbrt(t1+t2+THREEROOT3*M_PI*sqrt(sqrt1)); - t5 = t3/t4 + t4/E; - sqrt2 = MAX(0, 2*dR + t5); - t6 = sqrt(sqrt2); - sqrt3 = MAX(0, 4*dR - t5 + SIXROOT6*coh*M_PI*R2/(E*t6)); - a = INVROOT6*(t6 + sqrt(sqrt3)); - a2 = a*a; - knfac = normal_coeffs[0]*a; - Fne = knfac*a2/Reff - TWOPI*a2*sqrt(4*coh*E/(M_PI*a)); - } - else{ - knfac = E; //Hooke - a = sqrt(dR); - if (normal_model != HOOKE) { - Fne *= a; - knfac *= a; - } - Fne = knfac*delta; - if (normal_model == DMT) - Fne -= 4*MY_PI*normal_coeffs[3]*Reff; - } + delta = radsum - r; + dR = delta*Reff; + if (normal_model == JKR) { + history[0] = 1.0; + E *= THREEQUARTERS; + R2=Reff*Reff; + coh = normal_coeffs[3]; + dR2 = dR*dR; + t0 = coh*coh*R2*R2*E; + t1 = PI27SQ*t0; + t2 = 8*dR*dR2*E*E*E; + t3 = 4*dR2*E; + sqrt1 = MAX(0, t0*(t1+2*t2)); // in case sqrt(0) < 0 due to precision issues + t4 = cbrt(t1+t2+THREEROOT3*M_PI*sqrt(sqrt1)); + t5 = t3/t4 + t4/E; + sqrt2 = MAX(0, 2*dR + t5); + t6 = sqrt(sqrt2); + sqrt3 = MAX(0, 4*dR - t5 + SIXROOT6*coh*M_PI*R2/(E*t6)); + a = INVROOT6*(t6 + sqrt(sqrt3)); + a2 = a*a; + knfac = normal_coeffs[0]*a; + Fne = knfac*a2/Reff - TWOPI*a2*sqrt(4*coh*E/(M_PI*a)); + } + else{ + knfac = E; //Hooke + a = sqrt(dR); + if (normal_model != HOOKE) { + Fne *= a; + knfac *= a; + } + Fne = knfac*delta; + if (normal_model == DMT) + Fne -= 4*MY_PI*normal_coeffs[3]*Reff; + } - if (damping_model == VELOCITY) { - damp_normal = 1; - } - else if (damping_model == VISCOELASTIC) { - damp_normal = a*meff; - } - else if (damping_model == TSUJI) { - damp_normal = sqrt(meff*knfac); - } + if (damping_model == VELOCITY) { + damp_normal = 1; + } + else if (damping_model == VISCOELASTIC) { + damp_normal = a*meff; + } + else if (damping_model == TSUJI) { + damp_normal = sqrt(meff*knfac); + } - damp_normal_prefactor = normal_coeffs[1]*damp_normal; - Fdamp = -damp_normal_prefactor*vnnr; + damp_normal_prefactor = normal_coeffs[1]*damp_normal; + Fdamp = -damp_normal_prefactor*vnnr; - Fntot = Fne + Fdamp; + Fntot = Fne + Fdamp; - //**************************************** - //Tangential force, including history effects - //**************************************** + //**************************************** + // tangential force, including history effects + //**************************************** - // tangential component - vt1 = vr1 - vn1; - vt2 = vr2 - vn2; - vt3 = vr3 - vn3; + // tangential component + vt1 = vr1 - vn1; + vt2 = vr2 - vn2; + vt3 = vr3 - vn3; - // relative rotational velocity - wr1 = radius*omega[0] * rinv; - wr2 = radius*omega[1] * rinv; - wr3 = radius*omega[2] * rinv; + // relative rotational velocity + wr1 = radius*omega[0] * rinv; + wr2 = radius*omega[1] * rinv; + wr3 = radius*omega[2] * rinv; - // relative tangential velocities - vtr1 = vt1 - (nz*wr2-ny*wr3); - vtr2 = vt2 - (nx*wr3-nz*wr1); - vtr3 = vt3 - (ny*wr1-nx*wr2); - vrel = vtr1*vtr1 + vtr2*vtr2 + vtr3*vtr3; - vrel = sqrt(vrel); + // relative tangential velocities + vtr1 = vt1 - (nz*wr2-ny*wr3); + vtr2 = vt2 - (nx*wr3-nz*wr1); + vtr3 = vt3 - (ny*wr1-nx*wr2); + vrel = vtr1*vtr1 + vtr2*vtr2 + vtr3*vtr3; + vrel = sqrt(vrel); - if (normal_model == JKR) { - F_pulloff = 3*M_PI*coh*Reff; - Fncrit = fabs(Fne + 2*F_pulloff); - } - else if (normal_model == DMT) { - F_pulloff = 4*M_PI*coh*Reff; - Fncrit = fabs(Fne + 2*F_pulloff); - } - else{ - Fncrit = fabs(Fntot); - } + if (normal_model == JKR) { + F_pulloff = 3*M_PI*coh*Reff; + Fncrit = fabs(Fne + 2*F_pulloff); + } + else if (normal_model == DMT) { + F_pulloff = 4*M_PI*coh*Reff; + Fncrit = fabs(Fne + 2*F_pulloff); + } + else{ + Fncrit = fabs(Fntot); + } - //------------------------------ - //Tangential forces - //------------------------------ - k_tangential = tangential_coeffs[0]; - damp_tangential = tangential_coeffs[1]*damp_normal_prefactor; + //------------------------------ + // tangential forces + //------------------------------ - int thist0 = tangential_history_index; - int thist1 = thist0 + 1; - int thist2 = thist1 + 1; + k_tangential = tangential_coeffs[0]; + damp_tangential = tangential_coeffs[1]*damp_normal_prefactor; - if (tangential_history) { - if (tangential_model == TANGENTIAL_MINDLIN) { - k_tangential *= a; - } - else if (tangential_model == TANGENTIAL_MINDLIN_RESCALE) { - k_tangential *= a; - if (a < history[3]) { //On unloading, rescale the shear displacements - double factor = a/history[thist2+1]; - history[thist0] *= factor; - history[thist1] *= factor; - history[thist2] *= factor; - } - } - shrmag = sqrt(history[thist0]*history[thist0] + history[thist1]*history[thist1] + - history[thist2]*history[thist2]); + int thist0 = tangential_history_index; + int thist1 = thist0 + 1; + int thist2 = thist1 + 1; - // Rotate and update displacements. - // See e.g. eq. 17 of Luding, Gran. Matter 2008, v10,p235 - if (history_update) { - rsht = history[thist0]*nx + history[thist1]*ny + history[thist2]*nz; - if (fabs(rsht) < EPSILON) rsht = 0; - if (rsht > 0) { - scalefac = shrmag/(shrmag - rsht); //if rhst == shrmag, contacting pair has rotated 90 deg. in one step, in which case you deserve a crash! - history[thist0] -= rsht*nx; - history[thist1] -= rsht*ny; - history[thist2] -= rsht*nz; - //Also rescale to preserve magnitude - history[thist0] *= scalefac; - history[thist1] *= scalefac; - history[thist2] *= scalefac; - } - //Update history - history[thist0] += vtr1*dt; - history[thist1] += vtr2*dt; - history[thist2] += vtr3*dt; - } + if (tangential_history) { + if (tangential_model == TANGENTIAL_MINDLIN) { + k_tangential *= a; + } + else if (tangential_model == TANGENTIAL_MINDLIN_RESCALE) { + k_tangential *= a; + if (a < history[3]) { //On unloading, rescale the shear displacements + double factor = a/history[thist2+1]; + history[thist0] *= factor; + history[thist1] *= factor; + history[thist2] *= factor; + } + } + shrmag = sqrt(history[thist0]*history[thist0] + + history[thist1]*history[thist1] + + history[thist2]*history[thist2]); - // tangential forces = history + tangential velocity damping - fs1 = -k_tangential*history[thist0] - damp_tangential*vtr1; - fs2 = -k_tangential*history[thist1] - damp_tangential*vtr2; - fs3 = -k_tangential*history[thist2] - damp_tangential*vtr3; + // rotate and update displacements. + // see e.g. eq. 17 of Luding, Gran. Matter 2008, v10,p235 + if (history_update) { + rsht = history[thist0]*nx + history[thist1]*ny + history[thist2]*nz; + if (fabs(rsht) < EPSILON) rsht = 0; + if (rsht > 0) { + // if rhst == shrmag, contacting pair has rotated 90 deg in one step, + // in which case you deserve a crash! + scalefac = shrmag/(shrmag - rsht); + history[thist0] -= rsht*nx; + history[thist1] -= rsht*ny; + history[thist2] -= rsht*nz; + // also rescale to preserve magnitude + history[thist0] *= scalefac; + history[thist1] *= scalefac; + history[thist2] *= scalefac; + } + // update history + history[thist0] += vtr1*dt; + history[thist1] += vtr2*dt; + history[thist2] += vtr3*dt; + } - // rescale frictional displacements and forces if needed - Fscrit = tangential_coeffs[2] * Fncrit; - fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); - if (fs > Fscrit) { - if (shrmag != 0.0) { - history[thist0] = -1.0/k_tangential*(Fscrit*fs1/fs + damp_tangential*vtr1); - history[thist1] = -1.0/k_tangential*(Fscrit*fs2/fs + damp_tangential*vtr2); - history[thist2] = -1.0/k_tangential*(Fscrit*fs3/fs + damp_tangential*vtr3); - fs1 *= Fscrit/fs; - fs2 *= Fscrit/fs; - fs3 *= Fscrit/fs; - } else fs1 = fs2 = fs3 = 0.0; - } - } - else{ //Classic pair gran/hooke (no history) - fs = meff*damp_tangential*vrel; - if (vrel != 0.0) Ft = MIN(Fne,fs) / vrel; - else Ft = 0.0; - fs1 = -Ft*vtr1; - fs2 = -Ft*vtr2; - fs3 = -Ft*vtr3; - } + // tangential forces = history + tangential velocity damping + fs1 = -k_tangential*history[thist0] - damp_tangential*vtr1; + fs2 = -k_tangential*history[thist1] - damp_tangential*vtr2; + fs3 = -k_tangential*history[thist2] - damp_tangential*vtr3; - //**************************************** - // Rolling resistance - //**************************************** + // rescale frictional displacements and forces if needed + Fscrit = tangential_coeffs[2] * Fncrit; + fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); + if (fs > Fscrit) { + if (shrmag != 0.0) { + history[thist0] = -1.0/k_tangential*(Fscrit*fs1/fs + + damp_tangential*vtr1); + history[thist1] = -1.0/k_tangential*(Fscrit*fs2/fs + + damp_tangential*vtr2); + history[thist2] = -1.0/k_tangential*(Fscrit*fs3/fs + + damp_tangential*vtr3); + fs1 *= Fscrit/fs; + fs2 *= Fscrit/fs; + fs3 *= Fscrit/fs; + } else fs1 = fs2 = fs3 = 0.0; + } + } else { // classic pair gran/hooke (no history) + fs = meff*damp_tangential*vrel; + if (vrel != 0.0) Ft = MIN(Fne,fs) / vrel; + else Ft = 0.0; + fs1 = -Ft*vtr1; + fs2 = -Ft*vtr2; + fs3 = -Ft*vtr3; + } - if (roll_model != ROLL_NONE) { - relrot1 = omega[0]; - relrot2 = omega[1]; - relrot3 = omega[2]; + //**************************************** + // rolling resistance + //**************************************** - // rolling velocity, see eq. 31 of Wang et al, Particuology v 23, p 49 (2015) - // This is different from the Marshall papers, which use the Bagi/Kuhn formulation - // for rolling velocity (see Wang et al for why the latter is wrong) - vrl1 = Reff*(relrot2*nz - relrot3*ny); //- 0.5*((radj-radi)/radsum)*vtr1; - vrl2 = Reff*(relrot3*nx - relrot1*nz); //- 0.5*((radj-radi)/radsum)*vtr2; - vrl3 = Reff*(relrot1*ny - relrot2*nx); //- 0.5*((radj-radi)/radsum)*vtr3; + if (roll_model != ROLL_NONE) { + relrot1 = omega[0]; + relrot2 = omega[1]; + relrot3 = omega[2]; - int rhist0 = roll_history_index; - int rhist1 = rhist0 + 1; - int rhist2 = rhist1 + 1; + // rolling velocity, see eq. 31 of Wang et al, Particuology v 23, p 49 (2015) + // This is different from the Marshall papers, + // which use the Bagi/Kuhn formulation + // for rolling velocity (see Wang et al for why the latter is wrong) + vrl1 = Reff*(relrot2*nz - relrot3*ny); //- 0.5*((radj-radi)/radsum)*vtr1; + vrl2 = Reff*(relrot3*nx - relrot1*nz); //- 0.5*((radj-radi)/radsum)*vtr2; + vrl3 = Reff*(relrot1*ny - relrot2*nx); //- 0.5*((radj-radi)/radsum)*vtr3; - // Rolling displacement - rollmag = sqrt(history[rhist0]*history[rhist0] + - history[rhist1]*history[rhist1] + - history[rhist2]*history[rhist2]); + int rhist0 = roll_history_index; + int rhist1 = rhist0 + 1; + int rhist2 = rhist1 + 1; - rolldotn = history[rhist0]*nx + history[rhist1]*ny + history[rhist2]*nz; + // rolling displacement + rollmag = sqrt(history[rhist0]*history[rhist0] + + history[rhist1]*history[rhist1] + + history[rhist2]*history[rhist2]); - if (history_update) { - if (fabs(rolldotn) < EPSILON) rolldotn = 0; - if (rolldotn > 0) { //Rotate into tangential plane - scalefac = rollmag/(rollmag - rolldotn); - history[rhist0] -= rolldotn*nx; - history[rhist1] -= rolldotn*ny; - history[rhist2] -= rolldotn*nz; - //Also rescale to preserve magnitude - history[rhist0] *= scalefac; - history[rhist1] *= scalefac; - history[rhist2] *= scalefac; - } - history[rhist0] += vrl1*dt; - history[rhist1] += vrl2*dt; - history[rhist2] += vrl3*dt; - } + rolldotn = history[rhist0]*nx + history[rhist1]*ny + history[rhist2]*nz; - k_roll = roll_coeffs[0]; - damp_roll = roll_coeffs[1]; - fr1 = -k_roll*history[rhist0] - damp_roll*vrl1; - fr2 = -k_roll*history[rhist1] - damp_roll*vrl2; - fr3 = -k_roll*history[rhist2] - damp_roll*vrl3; + if (history_update) { + if (fabs(rolldotn) < EPSILON) rolldotn = 0; + if (rolldotn > 0) { // rotate into tangential plane + scalefac = rollmag/(rollmag - rolldotn); + history[rhist0] -= rolldotn*nx; + history[rhist1] -= rolldotn*ny; + history[rhist2] -= rolldotn*nz; + // also rescale to preserve magnitude + history[rhist0] *= scalefac; + history[rhist1] *= scalefac; + history[rhist2] *= scalefac; + } + history[rhist0] += vrl1*dt; + history[rhist1] += vrl2*dt; + history[rhist2] += vrl3*dt; + } - // rescale frictional displacements and forces if needed - Frcrit = roll_coeffs[2] * Fncrit; + k_roll = roll_coeffs[0]; + damp_roll = roll_coeffs[1]; + fr1 = -k_roll*history[rhist0] - damp_roll*vrl1; + fr2 = -k_roll*history[rhist1] - damp_roll*vrl2; + fr3 = -k_roll*history[rhist2] - damp_roll*vrl3; - fr = sqrt(fr1*fr1 + fr2*fr2 + fr3*fr3); - if (fr > Frcrit) { - if (rollmag != 0.0) { - history[rhist0] = -1.0/k_roll*(Frcrit*fr1/fr + damp_roll*vrl1); - history[rhist1] = -1.0/k_roll*(Frcrit*fr2/fr + damp_roll*vrl2); - history[rhist2] = -1.0/k_roll*(Frcrit*fr3/fr + damp_roll*vrl3); - fr1 *= Frcrit/fr; - fr2 *= Frcrit/fr; - fr3 *= Frcrit/fr; - } else fr1 = fr2 = fr3 = 0.0; - } - } + // rescale frictional displacements and forces if needed + Frcrit = roll_coeffs[2] * Fncrit; - //**************************************** - // Twisting torque, including history effects - //**************************************** - if (twist_model != TWIST_NONE) { - magtwist = relrot1*nx + relrot2*ny + relrot3*nz; //Omega_T (eq 29 of Marshall) - if (twist_model == TWIST_MARSHALL) { - k_twist = 0.5*k_tangential*a*a;; //eq 32 of Marshall paper - damp_twist = 0.5*damp_tangential*a*a; - mu_twist = TWOTHIRDS*a*tangential_coeffs[2]; - } - else{ - k_twist = twist_coeffs[0]; - damp_twist = twist_coeffs[1]; - mu_twist = twist_coeffs[2]; - } - if (history_update) { - history[twist_history_index] += magtwist*dt; - } - magtortwist = -k_twist*history[twist_history_index] - damp_twist*magtwist;//M_t torque (eq 30) - signtwist = (magtwist > 0) - (magtwist < 0); - Mtcrit = mu_twist*Fncrit;//critical torque (eq 44) - if (fabs(magtortwist) > Mtcrit) { - history[twist_history_index] = 1.0/k_twist*(Mtcrit*signtwist - damp_twist*magtwist); - magtortwist = -Mtcrit * signtwist; //eq 34 - } - } - // Apply forces & torques + fr = sqrt(fr1*fr1 + fr2*fr2 + fr3*fr3); + if (fr > Frcrit) { + if (rollmag != 0.0) { + history[rhist0] = -1.0/k_roll*(Frcrit*fr1/fr + damp_roll*vrl1); + history[rhist1] = -1.0/k_roll*(Frcrit*fr2/fr + damp_roll*vrl2); + history[rhist2] = -1.0/k_roll*(Frcrit*fr3/fr + damp_roll*vrl3); + fr1 *= Frcrit/fr; + fr2 *= Frcrit/fr; + fr3 *= Frcrit/fr; + } else fr1 = fr2 = fr3 = 0.0; + } + } - fx = nx*Fntot + fs1; - fy = ny*Fntot + fs2; - fz = nz*Fntot + fs3; + //**************************************** + // twisting torque, including history effects + //**************************************** - if (peratom_flag) { - contact[1] = fx; - contact[2] = fy; - contact[3] = fz; - } + if (twist_model != TWIST_NONE) { + magtwist = relrot1*nx + relrot2*ny + relrot3*nz; //Omega_T (eq 29 of Marshall) + if (twist_model == TWIST_MARSHALL) { + k_twist = 0.5*k_tangential*a*a;; // eq 32 of Marshall paper + damp_twist = 0.5*damp_tangential*a*a; + mu_twist = TWOTHIRDS*a*tangential_coeffs[2]; + } + else{ + k_twist = twist_coeffs[0]; + damp_twist = twist_coeffs[1]; + mu_twist = twist_coeffs[2]; + } + if (history_update) { + history[twist_history_index] += magtwist*dt; + } + // M_t torque (eq 30) + magtortwist = -k_twist*history[twist_history_index] - damp_twist*magtwist; + signtwist = (magtwist > 0) - (magtwist < 0); + Mtcrit = mu_twist*Fncrit; // critical torque (eq 44) + if (fabs(magtortwist) > Mtcrit) { + history[twist_history_index] = 1.0/k_twist*(Mtcrit*signtwist - + damp_twist*magtwist); + magtortwist = -Mtcrit * signtwist; // eq 34 + } + } - f[0] += fx; - f[1] += fy; - f[2] += fz; + // apply forces & torques - tor1 = ny*fs3 - nz*fs2; - tor2 = nz*fs1 - nx*fs3; - tor3 = nx*fs2 - ny*fs1; + fx = nx*Fntot + fs1; + fy = ny*Fntot + fs2; + fz = nz*Fntot + fs3; - torque[0] -= radius*tor1; - torque[1] -= radius*tor2; - torque[2] -= radius*tor3; + if (peratom_flag) { + contact[1] = fx; + contact[2] = fy; + contact[3] = fz; + } - if (twist_model != TWIST_NONE) { - tortwist1 = magtortwist * nx; - tortwist2 = magtortwist * ny; - tortwist3 = magtortwist * nz; + f[0] += fx; + f[1] += fy; + f[2] += fz; - torque[0] += tortwist1; - torque[1] += tortwist2; - torque[2] += tortwist3; - } + tor1 = ny*fs3 - nz*fs2; + tor2 = nz*fs1 - nx*fs3; + tor3 = nx*fs2 - ny*fs1; - if (roll_model != ROLL_NONE) { - torroll1 = Reff*(ny*fr3 - nz*fr2); //n cross fr - torroll2 = Reff*(nz*fr1 - nx*fr3); - torroll3 = Reff*(nx*fr2 - ny*fr1); + torque[0] -= radius*tor1; + torque[1] -= radius*tor2; + torque[2] -= radius*tor3; - torque[0] += torroll1; - torque[1] += torroll2; - torque[2] += torroll3; - } + if (twist_model != TWIST_NONE) { + tortwist1 = magtortwist * nx; + tortwist2 = magtortwist * ny; + tortwist3 = magtortwist * nz; + + torque[0] += tortwist1; + torque[1] += tortwist2; + torque[2] += tortwist3; + } + + if (roll_model != ROLL_NONE) { + torroll1 = Reff*(ny*fr3 - nz*fr2); //n cross fr + torroll2 = Reff*(nz*fr1 - nx*fr3); + torroll3 = Reff*(nx*fr2 - ny*fr1); + + torque[0] += torroll1; + torque[1] += torroll2; + torque[2] += torroll3; + } } - - /* ---------------------------------------------------------------------- memory usage of local atom-based arrays ------------------------------------------------------------------------- */ @@ -1389,9 +1437,10 @@ double FixWallGran::memory_usage() { int nmax = atom->nmax; double bytes = 0.0; - if (use_history) bytes += nmax*size_history * sizeof(double); // shear history - if (fix_rigid) bytes += nmax * sizeof(int); // mass_rigid - if (peratom_flag) bytes += nmax*size_peratom_cols*sizeof(double); //store contacts + if (use_history) bytes += nmax*size_history * sizeof(double); // shear history + if (fix_rigid) bytes += nmax * sizeof(int); // mass_rigid + // store contacts + if (peratom_flag) bytes += nmax*size_peratom_cols*sizeof(double); return bytes; } @@ -1401,7 +1450,8 @@ double FixWallGran::memory_usage() void FixWallGran::grow_arrays(int nmax) { - if (use_history) memory->grow(history_one,nmax,size_history,"fix_wall_gran:history_one"); + if (use_history) memory->grow(history_one,nmax,size_history, + "fix_wall_gran:history_one"); if (peratom_flag) { memory->grow(array_atom,nmax,size_peratom_cols,"fix_wall_gran:array_atom"); } diff --git a/src/GRANULAR/fix_wall_gran.h b/src/GRANULAR/fix_wall_gran.h index a81cdcb6c8..ee81477ddb 100644 --- a/src/GRANULAR/fix_wall_gran.h +++ b/src/GRANULAR/fix_wall_gran.h @@ -66,26 +66,24 @@ class FixWallGran : public Fix { bigint time_origin; double kn,kt,gamman,gammat,xmu; - //For granular - //Model choices + // for granular model choices int normal_model, damping_model; int tangential_model, roll_model, twist_model; - int beyond_contact; - //History flags + // history flags int normal_history, tangential_history, roll_history, twist_history; - //Indices of history entries + // indices of history entries int normal_history_index; int tangential_history_index; int roll_history_index; int twist_history_index; - //Material coefficients + // material coefficients double Emod, poiss, Gmod; - //Contact model coefficients + // contact model coefficients double normal_coeffs[4]; double tangential_coeffs[3]; double roll_coeffs[3]; @@ -97,7 +95,7 @@ class FixWallGran : public Fix { char *idregion; int use_history; // if particle/wall interaction stores history - int history_update; // flag for whether shear history is updated + int history_update; // flag for whether shear history is updated int size_history; // # of shear history values per contact // shear history for single contact per particle @@ -110,7 +108,8 @@ class FixWallGran : public Fix { double *mass_rigid; // rigid mass for owned+ghost atoms int nmax; // allocated size of mass_rigid - // Store particle interactions + // store particle interactions + int store; }; diff --git a/src/GRANULAR/fix_wall_gran_region.cpp b/src/GRANULAR/fix_wall_gran_region.cpp index 95b34e0929..e6f8406be0 100644 --- a/src/GRANULAR/fix_wall_gran_region.cpp +++ b/src/GRANULAR/fix_wall_gran_region.cpp @@ -47,8 +47,9 @@ enum {NORMAL_HOOKE, NORMAL_HERTZ, HERTZ_MATERIAL, DMT, JKR}; /* ---------------------------------------------------------------------- */ FixWallGranRegion::FixWallGranRegion(LAMMPS *lmp, int narg, char **arg) : - FixWallGran(lmp, narg, arg), region(NULL), region_style(NULL), ncontact(NULL), - walls(NULL), history_many(NULL), c2r(NULL) + FixWallGran(lmp, narg, arg), region(NULL), region_style(NULL), + ncontact(NULL), + walls(NULL), history_many(NULL), c2r(NULL) { restart_global = 1; motion_resetflag = 0; @@ -190,7 +191,8 @@ void FixWallGranRegion::post_force(int /*vflag*/) if (!region->match(x[i][0],x[i][1],x[i][2])) continue; if (pairstyle == GRANULAR && normal_model == JKR){ - nc = region->surface(x[i][0],x[i][1],x[i][2],radius[i]+pulloff_distance(radius[i])); + nc = region->surface(x[i][0],x[i][1],x[i][2], + radius[i]+pulloff_distance(radius[i])); } else{ nc = region->surface(x[i][0],x[i][1],x[i][2],radius[i]); @@ -278,8 +280,9 @@ void FixWallGranRegion::post_force(int /*vflag*/) v[i],f[i],omega[i],torque[i], radius[i],meff,history_many[i][c2r[ic]], contact); else if (pairstyle == GRANULAR) - granular(rsq,dx,dy,dz,vwall,region->contact[ic].radius, v[i],f[i],omega[i],torque[i], radius[i],meff,history_many[i][c2r[ic]], contact); - + granular(rsq,dx,dy,dz,vwall,region->contact[ic].radius, + v[i],f[i],omega[i],torque[i], + radius[i],meff,history_many[i][c2r[ic]],contact); } } } @@ -364,11 +367,11 @@ void FixWallGranRegion::grow_arrays(int nmax) if (use_history) { memory->grow(ncontact,nmax,"fix_wall_gran:ncontact"); memory->grow(walls,nmax,tmax,"fix_wall_gran:walls"); - memory->grow(history_many,nmax,tmax,size_history,"fix_wall_gran:history_many"); + memory->grow(history_many,nmax,tmax,size_history, + "fix_wall_gran:history_many"); } - if (peratom_flag){ + if (peratom_flag) memory->grow(array_atom,nmax,size_peratom_cols,"fix_wall_gran:array_atom"); - } } /* ---------------------------------------------------------------------- diff --git a/src/GRANULAR/pair_gran_hooke_history.cpp b/src/GRANULAR/pair_gran_hooke_history.cpp index 344e72f8ef..c86c2b0c90 100644 --- a/src/GRANULAR/pair_gran_hooke_history.cpp +++ b/src/GRANULAR/pair_gran_hooke_history.cpp @@ -59,7 +59,9 @@ PairGranHookeHistory::PairGranHookeHistory(LAMMPS *lmp) : Pair(lmp) comm_forward = 1; - nondefault_history_transfer = 0; //keep default behavior of history[i][j] = -history[j][i] + // keep default behavior of history[i][j] = -history[j][i] + + nondefault_history_transfer = 0; } /* ---------------------------------------------------------------------- */ diff --git a/src/GRANULAR/pair_gran_hooke_history.h b/src/GRANULAR/pair_gran_hooke_history.h index 2cb609fd82..b1bb212f89 100644 --- a/src/GRANULAR/pair_gran_hooke_history.h +++ b/src/GRANULAR/pair_gran_hooke_history.h @@ -26,6 +26,8 @@ namespace LAMMPS_NS { class PairGranHookeHistory : public Pair { public: + int nondefault_history_transfer; + PairGranHookeHistory(class LAMMPS *); virtual ~PairGranHookeHistory(); virtual void compute(int, int); @@ -42,7 +44,6 @@ class PairGranHookeHistory : public Pair { int pack_forward_comm(int, int *, double *, int, int *); void unpack_forward_comm(int, int, double *); double memory_usage(); - int nondefault_history_transfer; protected: double kn,kt,gamman,gammat,xmu; diff --git a/src/GRANULAR/pair_granular.cpp b/src/GRANULAR/pair_granular.cpp index b3046788e0..c8450c5434 100644 --- a/src/GRANULAR/pair_granular.cpp +++ b/src/GRANULAR/pair_granular.cpp @@ -11,9 +11,9 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- -Contributing authors: -Dan Bolintineanu (SNL), Ishan Srivastava (SNL), Jeremy Lechman(SNL) -Leo Silbert (SNL), Gary Grest (SNL) + Contributing authors: + Dan Bolintineanu (SNL), Ishan Srivastava (SNL), Jeremy Lechman(SNL) + Leo Silbert (SNL), Gary Grest (SNL) ----------------------------------------------------------------------- */ #include @@ -52,7 +52,8 @@ using namespace MathConst; enum {HOOKE, HERTZ, HERTZ_MATERIAL, DMT, JKR}; enum {VELOCITY, VISCOELASTIC, TSUJI}; -enum {TANGENTIAL_NOHISTORY, TANGENTIAL_HISTORY, TANGENTIAL_MINDLIN, TANGENTIAL_MINDLIN_RESCALE}; +enum {TANGENTIAL_NOHISTORY, TANGENTIAL_HISTORY, + TANGENTIAL_MINDLIN, TANGENTIAL_MINDLIN_RESCALE}; enum {TWIST_NONE, TWIST_SDS, TWIST_MARSHALL}; enum {ROLL_NONE, ROLL_SDS}; @@ -90,10 +91,10 @@ PairGranular::PairGranular(LAMMPS *lmp) : Pair(lmp) nondefault_history_transfer = 0; tangential_history_index = 0; roll_history_index = twist_history_index = 0; - } /* ---------------------------------------------------------------------- */ + PairGranular::~PairGranular() { delete [] svector; @@ -118,16 +119,17 @@ PairGranular::~PairGranular() memory->destroy(roll_model); memory->destroy(twist_model); - - delete [] onerad_dynamic; delete [] onerad_frozen; delete [] maxrad_dynamic; delete [] maxrad_frozen; } + memory->destroy(mass_rigid); } +/* ---------------------------------------------------------------------- */ + void PairGranular::compute(int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; @@ -147,18 +149,18 @@ void PairGranular::compute(int eflag, int vflag) double mi,mj,meff; double relrot1,relrot2,relrot3,vrl1,vrl2,vrl3; - // For JKR + // for JKR double R2, coh, F_pulloff, delta_pulloff, dist_pulloff, a, a2, E; double t0, t1, t2, t3, t4, t5, t6; double sqrt1, sqrt2, sqrt3; - // Rolling + // rolling double k_roll, damp_roll; double torroll1, torroll2, torroll3; double rollmag, rolldotn, scalefac; double fr, fr1, fr2, fr3; - // Twisting + // twisting double k_twist, damp_twist, mu_twist; double signtwist, magtwist, magtortwist, Mtcrit; double tortwist1, tortwist2, tortwist3; @@ -317,7 +319,8 @@ void PairGranular::compute(int eflag, int vflag) t1 = PI27SQ*t0; t2 = 8*dR*dR2*E*E*E; t3 = 4*dR2*E; - sqrt1 = MAX(0, t0*(t1+2*t2)); //In case of sqrt(0) < 0 due to precision issues + // in case sqrt(0) < 0 due to precision issues + sqrt1 = MAX(0, t0*(t1+2*t2)); t4 = cbrt(t1+t2+THREEROOT3*M_PI*sqrt(sqrt1)); t5 = t3/t4 + t4/E; sqrt2 = MAX(0, 2*dR + t5); @@ -328,7 +331,7 @@ void PairGranular::compute(int eflag, int vflag) knfac = normal_coeffs[itype][jtype][0]*a; Fne = knfac*a2/Reff - TWOPI*a2*sqrt(4*coh*E/(M_PI*a)); } else { - knfac = E; //Hooke + knfac = E; // Hooke Fne = knfac*delta; a = sqrt(dR); if (normal_model[itype][jtype] != HOOKE) { @@ -339,7 +342,9 @@ void PairGranular::compute(int eflag, int vflag) Fne -= 4*MY_PI*normal_coeffs[itype][jtype][3]*Reff; } - //Consider restricting Hooke to only have 'velocity' as an option for damping? + // NOTE: consider restricting Hooke to only have + // 'velocity' as an option for damping? + if (damping_model[itype][jtype] == VELOCITY) { damp_normal = 1; } else if (damping_model[itype][jtype] == VISCOELASTIC) { @@ -354,7 +359,7 @@ void PairGranular::compute(int eflag, int vflag) Fntot = Fne + Fdamp; //**************************************** - //Tangential force, including history effects + // tangential force, including history effects //**************************************** // tangential component @@ -374,7 +379,7 @@ void PairGranular::compute(int eflag, int vflag) vrel = vtr1*vtr1 + vtr2*vtr2 + vtr3*vtr3; vrel = sqrt(vrel); - // If any history is needed: + // if any history is needed if (use_history) { touch[jj] = 1; history = &allhistory[size_history*jj]; @@ -391,45 +396,51 @@ void PairGranular::compute(int eflag, int vflag) } //------------------------------ - //Tangential forces + // tangential forces //------------------------------ k_tangential = tangential_coeffs[itype][jtype][0]; - damp_tangential = tangential_coeffs[itype][jtype][1]*damp_normal_prefactor; + damp_tangential = tangential_coeffs[itype][jtype][1] * + damp_normal_prefactor; if (tangential_history) { if (tangential_model[itype][jtype] == TANGENTIAL_MINDLIN) { k_tangential *= a; - } else if (tangential_model[itype][jtype] == TANGENTIAL_MINDLIN_RESCALE) { + } else if (tangential_model[itype][jtype] == + TANGENTIAL_MINDLIN_RESCALE) { k_tangential *= a; - if (a < history[3]) { //On unloading, rescale the shear displacements + // on unloading, rescale the shear displacements + if (a < history[3]) { double factor = a/history[3]; history[0] *= factor; history[1] *= factor; history[2] *= factor; } } - // Rotate and update displacements. - // See e.g. eq. 17 of Luding, Gran. Matter 2008, v10,p235 + // rotate and update displacements. + // see e.g. eq. 17 of Luding, Gran. Matter 2008, v10,p235 if (historyupdate) { rsht = history[0]*nx + history[1]*ny + history[2]*nz; if (fabs(rsht) < EPSILON) rsht = 0; if (rsht > 0) { shrmag = sqrt(history[0]*history[0] + history[1]*history[1] + history[2]*history[2]); - scalefac = shrmag/(shrmag - rsht); //if rsht == shrmag, contacting pair has rotated 90 deg. in one step, in which case you deserve a crash! + // if rsht == shrmag, contacting pair has rotated 90 deg + // in one step, in which case you deserve a crash! + scalefac = shrmag/(shrmag - rsht); history[0] -= rsht*nx; history[1] -= rsht*ny; history[2] -= rsht*nz; - //Also rescale to preserve magnitude + // also rescale to preserve magnitude history[0] *= scalefac; history[1] *= scalefac; history[2] *= scalefac; } - //Update history + // update history history[0] += vtr1*dt; history[1] += vtr2*dt; history[2] += vtr3*dt; - if (tangential_model[itype][jtype] == TANGENTIAL_MINDLIN_RESCALE) history[3] = a; + if (tangential_model[itype][jtype] == TANGENTIAL_MINDLIN_RESCALE) + history[3] = a; } // tangential forces = history + tangential velocity damping @@ -444,15 +455,18 @@ void PairGranular::compute(int eflag, int vflag) shrmag = sqrt(history[0]*history[0] + history[1]*history[1] + history[2]*history[2]); if (shrmag != 0.0) { - history[0] = -1.0/k_tangential*(Fscrit*fs1/fs + damp_tangential*vtr1); - history[1] = -1.0/k_tangential*(Fscrit*fs2/fs + damp_tangential*vtr2); - history[2] = -1.0/k_tangential*(Fscrit*fs3/fs + damp_tangential*vtr3); + history[0] = -1.0/k_tangential*(Fscrit*fs1/fs + + damp_tangential*vtr1); + history[1] = -1.0/k_tangential*(Fscrit*fs2/fs + + damp_tangential*vtr2); + history[2] = -1.0/k_tangential*(Fscrit*fs3/fs + + damp_tangential*vtr3); fs1 *= Fscrit/fs; fs2 *= Fscrit/fs; fs3 *= Fscrit/fs; } else fs1 = fs2 = fs3 = 0.0; } - } else{ //Classic pair gran/hooke (no history) + } else { // classic pair gran/hooke (no history) fs = meff*damp_tangential*vrel; if (vrel != 0.0) Ft = MIN(Fne,fs) / vrel; else Ft = 0.0; @@ -462,7 +476,7 @@ void PairGranular::compute(int eflag, int vflag) } //**************************************** - // Rolling resistance + // rolling resistance //**************************************** if (roll_model[itype][jtype] != ROLL_NONE) { @@ -470,12 +484,18 @@ void PairGranular::compute(int eflag, int vflag) relrot2 = omega[i][1] - omega[j][1]; relrot3 = omega[i][2] - omega[j][2]; - // rolling velocity, see eq. 31 of Wang et al, Particuology v 23, p 49 (2015) - // This is different from the Marshall papers, which use the Bagi/Kuhn formulation + // rolling velocity, + // see eq. 31 of Wang et al, Particuology v 23, p 49 (2015) + // this is different from the Marshall papers, + // which use the Bagi/Kuhn formulation // for rolling velocity (see Wang et al for why the latter is wrong) - vrl1 = Reff*(relrot2*nz - relrot3*ny); //- 0.5*((radj-radi)/radsum)*vtr1; - vrl2 = Reff*(relrot3*nx - relrot1*nz); //- 0.5*((radj-radi)/radsum)*vtr2; - vrl3 = Reff*(relrot1*ny - relrot2*nx); //- 0.5*((radj-radi)/radsum)*vtr3; + // - 0.5*((radj-radi)/radsum)*vtr1; + // - 0.5*((radj-radi)/radsum)*vtr2; + // - 0.5*((radj-radi)/radsum)*vtr3; + + vrl1 = Reff*(relrot2*nz - relrot3*ny); + vrl2 = Reff*(relrot3*nx - relrot1*nz); + vrl3 = Reff*(relrot1*ny - relrot2*nx); int rhist0 = roll_history_index; int rhist1 = rhist0 + 1; @@ -484,7 +504,7 @@ void PairGranular::compute(int eflag, int vflag) rolldotn = history[rhist0]*nx + history[rhist1]*ny + history[rhist2]*nz; if (historyupdate) { if (fabs(rolldotn) < EPSILON) rolldotn = 0; - if (rolldotn > 0) { //Rotate into tangential plane + if (rolldotn > 0) { // rotate into tangential plane rollmag = sqrt(history[rhist0]*history[rhist0] + history[rhist1]*history[rhist1] + history[rhist2]*history[rhist2]); @@ -492,7 +512,7 @@ void PairGranular::compute(int eflag, int vflag) history[rhist0] -= rolldotn*nx; history[rhist1] -= rolldotn*ny; history[rhist2] -= rolldotn*nz; - //Also rescale to preserve magnitude + // also rescale to preserve magnitude history[rhist0] *= scalefac; history[rhist1] *= scalefac; history[rhist2] *= scalefac; @@ -528,12 +548,14 @@ void PairGranular::compute(int eflag, int vflag) } //**************************************** - // Twisting torque, including history effects + // twisting torque, including history effects //**************************************** + if (twist_model[itype][jtype] != TWIST_NONE) { - magtwist = relrot1*nx + relrot2*ny + relrot3*nz; //Omega_T (eq 29 of Marshall) + // omega_T (eq 29 of Marshall) + magtwist = relrot1*nx + relrot2*ny + relrot3*nz; if (twist_model[itype][jtype] == TWIST_MARSHALL) { - k_twist = 0.5*k_tangential*a*a;; //eq 32 of Marshall paper + k_twist = 0.5*k_tangential*a*a;; // eq 32 of Marshall paper damp_twist = 0.5*damp_tangential*a*a; mu_twist = TWOTHIRDS*a*tangential_coeffs[itype][jtype][2]; } else { @@ -544,15 +566,18 @@ void PairGranular::compute(int eflag, int vflag) if (historyupdate) { history[twist_history_index] += magtwist*dt; } - magtortwist = -k_twist*history[twist_history_index] - damp_twist*magtwist;//M_t torque (eq 30) + magtortwist = -k_twist*history[twist_history_index] - + damp_twist*magtwist; // M_t torque (eq 30) signtwist = (magtwist > 0) - (magtwist < 0); - Mtcrit = mu_twist*Fncrit;//critical torque (eq 44) + Mtcrit = mu_twist*Fncrit; // critical torque (eq 44) if (fabs(magtortwist) > Mtcrit) { - history[twist_history_index] = 1.0/k_twist*(Mtcrit*signtwist - damp_twist*magtwist); - magtortwist = -Mtcrit * signtwist; //eq 34 + history[twist_history_index] = 1.0/k_twist*(Mtcrit*signtwist - + damp_twist*magtwist); + magtortwist = -Mtcrit * signtwist; // eq 34 } } - // Apply forces & torques + + // apply forces & torques fx = nx*Fntot + fs1; fy = ny*Fntot + fs2; @@ -582,7 +607,7 @@ void PairGranular::compute(int eflag, int vflag) } if (roll_model[itype][jtype] != ROLL_NONE) { - torroll1 = Reff*(ny*fr3 - nz*fr2); //n cross fr + torroll1 = Reff*(ny*fr3 - nz*fr2); // n cross fr torroll2 = Reff*(nz*fr1 - nx*fr3); torroll3 = Reff*(nx*fr2 - ny*fr1); @@ -619,9 +644,8 @@ void PairGranular::compute(int eflag, int vflag) } } - /* ---------------------------------------------------------------------- -allocate all arrays + allocate all arrays ------------------------------------------------------------------------- */ void PairGranular::allocate() @@ -657,7 +681,7 @@ void PairGranular::allocate() } /* ---------------------------------------------------------------------- - global settings + global settings ------------------------------------------------------------------------- */ void PairGranular::settings(int narg, char **arg) @@ -665,7 +689,7 @@ void PairGranular::settings(int narg, char **arg) if (narg == 1) { cutoff_global = force->numeric(FLERR,arg[0]); } else { - cutoff_global = -1; //Will be set based on particle sizes, model choice + cutoff_global = -1; // will be set based on particle sizes, model choice } normal_history = tangential_history = 0; @@ -705,45 +729,57 @@ void PairGranular::coeff(int narg, char **arg) int iarg = 2; while (iarg < narg) { if (strcmp(arg[iarg], "hooke") == 0) { - if (iarg + 2 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hooke option"); + if (iarg + 2 >= narg) + error->all(FLERR,"Illegal pair_coeff command, " + "not enough parameters provided for Hooke option"); normal_model_one = HOOKE; - normal_coeffs_one[0] = force->numeric(FLERR,arg[iarg+1]); //kn - normal_coeffs_one[1] = force->numeric(FLERR,arg[iarg+2]); //damping + normal_coeffs_one[0] = force->numeric(FLERR,arg[iarg+1]); // kn + normal_coeffs_one[1] = force->numeric(FLERR,arg[iarg+2]); // damping iarg += 3; } else if (strcmp(arg[iarg], "hertz") == 0) { int num_coeffs = 2; - if (iarg + num_coeffs >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hertz option"); + if (iarg + num_coeffs >= narg) + error->all(FLERR,"Illegal pair_coeff command, " + "not enough parameters provided for Hertz option"); normal_model_one = HERTZ; - normal_coeffs_one[0] = force->numeric(FLERR,arg[iarg+1]); //kn - normal_coeffs_one[1] = force->numeric(FLERR,arg[iarg+2]); //damping + normal_coeffs_one[0] = force->numeric(FLERR,arg[iarg+1]); // kn + normal_coeffs_one[1] = force->numeric(FLERR,arg[iarg+2]); // damping iarg += num_coeffs+1; } else if (strcmp(arg[iarg], "hertz/material") == 0) { int num_coeffs = 3; - if (iarg + num_coeffs >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hertz/material option"); + if (iarg + num_coeffs >= narg) + error->all(FLERR,"Illegal pair_coeff command, " + "not enough parameters provided for Hertz/material option"); normal_model_one = HERTZ_MATERIAL; - normal_coeffs_one[0] = force->numeric(FLERR,arg[iarg+1]); //E - normal_coeffs_one[1] = force->numeric(FLERR,arg[iarg+2]); //damping - normal_coeffs_one[2] = force->numeric(FLERR,arg[iarg+3]); //Poisson's ratio + normal_coeffs_one[0] = force->numeric(FLERR,arg[iarg+1]); // E + normal_coeffs_one[1] = force->numeric(FLERR,arg[iarg+2]); // damping + normal_coeffs_one[2] = force->numeric(FLERR,arg[iarg+3]); // Poisson's ratio iarg += num_coeffs+1; } else if (strcmp(arg[iarg], "dmt") == 0) { - if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for Hertz option"); + if (iarg + 4 >= narg) + error->all(FLERR,"Illegal pair_coeff command, " + "not enough parameters provided for Hertz option"); normal_model_one = DMT; - normal_coeffs_one[0] = force->numeric(FLERR,arg[iarg+1]); //E - normal_coeffs_one[1] = force->numeric(FLERR,arg[iarg+2]); //damping - normal_coeffs_one[2] = force->numeric(FLERR,arg[iarg+3]); //Poisson's ratio - normal_coeffs_one[3] = force->numeric(FLERR,arg[iarg+4]); //cohesion + normal_coeffs_one[0] = force->numeric(FLERR,arg[iarg+1]); // E + normal_coeffs_one[1] = force->numeric(FLERR,arg[iarg+2]); // damping + normal_coeffs_one[2] = force->numeric(FLERR,arg[iarg+3]); // Poisson's ratio + normal_coeffs_one[3] = force->numeric(FLERR,arg[iarg+4]); // cohesion iarg += 5; } else if (strcmp(arg[iarg], "jkr") == 0) { - if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for JKR option"); + if (iarg + 4 >= narg) + error->all(FLERR,"Illegal pair_coeff command, " + "not enough parameters provided for JKR option"); beyond_contact = 1; normal_model_one = JKR; - normal_coeffs_one[0] = force->numeric(FLERR,arg[iarg+1]); //E - normal_coeffs_one[1] = force->numeric(FLERR,arg[iarg+2]); //damping - normal_coeffs_one[2] = force->numeric(FLERR,arg[iarg+3]); //Poisson's ratio - normal_coeffs_one[3] = force->numeric(FLERR,arg[iarg+4]); //cohesion + normal_coeffs_one[0] = force->numeric(FLERR,arg[iarg+1]); // E + normal_coeffs_one[1] = force->numeric(FLERR,arg[iarg+2]); // damping + normal_coeffs_one[2] = force->numeric(FLERR,arg[iarg+3]); // Poisson's ratio + normal_coeffs_one[3] = force->numeric(FLERR,arg[iarg+4]); // cohesion iarg += 5; } else if (strcmp(arg[iarg], "damping") == 0) { - if (iarg+1 >= narg) error->all(FLERR, "Illegal pair_coeff command, not enough parameters provided for damping model"); + if (iarg+1 >= narg) + error->all(FLERR, "Illegal pair_coeff command, " + "not enough parameters provided for damping model"); if (strcmp(arg[iarg+1], "velocity") == 0) { damping_model_one = VELOCITY; iarg += 1; @@ -753,58 +789,80 @@ void PairGranular::coeff(int narg, char **arg) } else if (strcmp(arg[iarg+1], "tsuji") == 0) { damping_model_one = TSUJI; iarg += 1; - } else error->all(FLERR, "Illegal pair_coeff command, unrecognized damping model"); + } else error->all(FLERR, "Illegal pair_coeff command, " + "unrecognized damping model"); iarg += 1; } else if (strcmp(arg[iarg], "tangential") == 0) { - if (iarg + 1 >= narg) error->all(FLERR,"Illegal pair_coeff command, must specify tangential model after 'tangential' keyword"); + if (iarg + 1 >= narg) + error->all(FLERR,"Illegal pair_coeff command, must specify " + "tangential model after tangential keyword"); if (strcmp(arg[iarg+1], "linear_nohistory") == 0) { - if (iarg + 3 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for tangential model"); + if (iarg + 3 >= narg) + error->all(FLERR,"Illegal pair_coeff command, " + "not enough parameters provided for tangential model"); tangential_model_one = TANGENTIAL_NOHISTORY; tangential_coeffs_one[0] = 0; - tangential_coeffs_one[1] = force->numeric(FLERR,arg[iarg+2]); //gammat - tangential_coeffs_one[2] = force->numeric(FLERR,arg[iarg+3]); //friction coeff. + // gammat and friction coeff + tangential_coeffs_one[1] = force->numeric(FLERR,arg[iarg+2]); + tangential_coeffs_one[2] = force->numeric(FLERR,arg[iarg+3]); iarg += 4; } else if ((strcmp(arg[iarg+1], "linear_history") == 0) || (strcmp(arg[iarg+1], "mindlin") == 0) || (strcmp(arg[iarg+1], "mindlin_rescale") == 0)) { - if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for tangential model"); - if (strcmp(arg[iarg+1], "linear_history") == 0) tangential_model_one = TANGENTIAL_HISTORY; - else if (strcmp(arg[iarg+1], "mindlin") == 0) tangential_model_one = TANGENTIAL_MINDLIN; - else if (strcmp(arg[iarg+1], "mindlin_rescale") == 0) tangential_model_one = TANGENTIAL_MINDLIN_RESCALE; + if (iarg + 4 >= narg) + error->all(FLERR,"Illegal pair_coeff command, " + "not enough parameters provided for tangential model"); + if (strcmp(arg[iarg+1], "linear_history") == 0) + tangential_model_one = TANGENTIAL_HISTORY; + else if (strcmp(arg[iarg+1], "mindlin") == 0) + tangential_model_one = TANGENTIAL_MINDLIN; + else if (strcmp(arg[iarg+1], "mindlin_rescale") == 0) + tangential_model_one = TANGENTIAL_MINDLIN_RESCALE; tangential_history = 1; - if ((tangential_model_one == TANGENTIAL_MINDLIN || tangential_model_one == TANGENTIAL_MINDLIN_RESCALE) && + if ((tangential_model_one == TANGENTIAL_MINDLIN || + tangential_model_one == TANGENTIAL_MINDLIN_RESCALE) && (strcmp(arg[iarg+2], "NULL") == 0)) { if (normal_model_one == HERTZ || normal_model_one == HOOKE) { - error->all(FLERR, "NULL setting for Mindlin tangential stiffness requires a normal contact model that specifies material properties"); + error->all(FLERR, "NULL setting for Mindlin tangential " + "stiffness requires a normal contact model that " + "specifies material properties"); } tangential_coeffs_one[0] = -1; } else { - tangential_coeffs_one[0] = force->numeric(FLERR,arg[iarg+2]); //kt + tangential_coeffs_one[0] = force->numeric(FLERR,arg[iarg+2]); // kt } - tangential_coeffs_one[1] = force->numeric(FLERR,arg[iarg+3]); //gammat - tangential_coeffs_one[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. + // gammat and friction coeff + tangential_coeffs_one[1] = force->numeric(FLERR,arg[iarg+3]); + tangential_coeffs_one[2] = force->numeric(FLERR,arg[iarg+4]); iarg += 5; } else { - error->all(FLERR, "Illegal pair_coeff command, tangential model not recognized"); + error->all(FLERR, "Illegal pair_coeff command, " + "tangential model not recognized"); } } else if (strcmp(arg[iarg], "rolling") == 0) { - if (iarg + 1 >= narg) error->all(FLERR, "Illegal pair_coeff command, not enough parameters"); + if (iarg + 1 >= narg) + error->all(FLERR, "Illegal pair_coeff command, not enough parameters"); if (strcmp(arg[iarg+1], "none") == 0) { roll_model_one = ROLL_NONE; iarg += 2; } else if (strcmp(arg[iarg+1], "sds") == 0) { - if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for rolling model"); + if (iarg + 4 >= narg) + error->all(FLERR,"Illegal pair_coeff command, " + "not enough parameters provided for rolling model"); roll_model_one = ROLL_SDS; roll_history = 1; - roll_coeffs_one[0] = force->numeric(FLERR,arg[iarg+2]); //kR - roll_coeffs_one[1] = force->numeric(FLERR,arg[iarg+3]); //gammaR - roll_coeffs_one[2] = force->numeric(FLERR,arg[iarg+4]); //rolling friction coeff. + // kR and gammaR and rolling friction coeff + roll_coeffs_one[0] = force->numeric(FLERR,arg[iarg+2]); + roll_coeffs_one[1] = force->numeric(FLERR,arg[iarg+3]); + roll_coeffs_one[2] = force->numeric(FLERR,arg[iarg+4]); iarg += 5; } else { - error->all(FLERR, "Illegal pair_coeff command, rolling friction model not recognized"); + error->all(FLERR, "Illegal pair_coeff command, " + "rolling friction model not recognized"); } } else if (strcmp(arg[iarg], "twisting") == 0) { - if (iarg + 1 >= narg) error->all(FLERR, "Illegal pair_coeff command, not enough parameters"); + if (iarg + 1 >= narg) + error->all(FLERR, "Illegal pair_coeff command, not enough parameters"); if (strcmp(arg[iarg+1], "none") == 0) { twist_model_one = TWIST_NONE; iarg += 2; @@ -813,24 +871,31 @@ void PairGranular::coeff(int narg, char **arg) twist_history = 1; iarg += 2; } else if (strcmp(arg[iarg+1], "sds") == 0) { - if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, not enough parameters provided for twist model"); + if (iarg + 4 >= narg) + error->all(FLERR,"Illegal pair_coeff command, " + "not enough parameters provided for twist model"); twist_model_one = TWIST_SDS; twist_history = 1; - twist_coeffs_one[0] = force->numeric(FLERR,arg[iarg+2]); //kt - twist_coeffs_one[1] = force->numeric(FLERR,arg[iarg+3]); //gammat - twist_coeffs_one[2] = force->numeric(FLERR,arg[iarg+4]); //friction coeff. + // kt and gammat and friction coeff + twist_coeffs_one[0] = force->numeric(FLERR,arg[iarg+2]); + twist_coeffs_one[1] = force->numeric(FLERR,arg[iarg+3]); + twist_coeffs_one[2] = force->numeric(FLERR,arg[iarg+4]); iarg += 5; } else { - error->all(FLERR, "Illegal pair_coeff command, twisting friction model not recognized"); + error->all(FLERR, "Illegal pair_coeff command, " + "twisting friction model not recognized"); } } else if (strcmp(arg[iarg], "cutoff") == 0) { - if (iarg + 1 >= narg) error->all(FLERR, "Illegal pair_coeff command, not enough parameters"); + if (iarg + 1 >= narg) + error->all(FLERR, "Illegal pair_coeff command, not enough parameters"); cutoff_one = force->numeric(FLERR,arg[iarg+1]); } else error->all(FLERR, "Illegal pair coeff command"); } - //It is an error not to specify normal or tangential model - if ((normal_model_one < 0) || (tangential_model_one < 0)) error->all(FLERR, "Illegal pair coeff command, must specify normal contact model"); + // error not to specify normal or tangential model + if ((normal_model_one < 0) || (tangential_model_one < 0)) + error->all(FLERR, "Illegal pair coeff command, " + "must specify normal or tangential contact model"); int count = 0; double damp; @@ -849,7 +914,9 @@ void PairGranular::coeff(int narg, char **arg) if (normal_model_one != HERTZ && normal_model_one != HOOKE) { Emod[i][j] = Emod[j][i] = normal_coeffs_one[0]; poiss[i][j] = poiss[j][i] = normal_coeffs_one[2]; - normal_coeffs[i][j][0] = normal_coeffs[j][i][0] = FOURTHIRDS*mix_stiffnessE(Emod[i][j], Emod[i][j], poiss[i][j], poiss[i][j]); + normal_coeffs[i][j][0] = normal_coeffs[j][i][0] = + FOURTHIRDS*mix_stiffnessE(Emod[i][j],Emod[i][j], + poiss[i][j],poiss[i][j]); } else { normal_coeffs[i][j][0] = normal_coeffs[j][i][0] = normal_coeffs_one[0]; } @@ -860,12 +927,15 @@ void PairGranular::coeff(int narg, char **arg) tangential_model[i][j] = tangential_model[j][i] = tangential_model_one; if (tangential_coeffs_one[0] == -1) { - tangential_coeffs[i][j][0] = tangential_coeffs[j][i][0] = 8*mix_stiffnessG(Emod[i][j], Emod[i][j], poiss[i][j], poiss[i][j]); + tangential_coeffs[i][j][0] = tangential_coeffs[j][i][0] = + 8*mix_stiffnessG(Emod[i][j],Emod[i][j],poiss[i][j],poiss[i][j]); } else { - tangential_coeffs[i][j][0] = tangential_coeffs[j][i][0] = tangential_coeffs_one[0]; + tangential_coeffs[i][j][0] = tangential_coeffs[j][i][0] = + tangential_coeffs_one[0]; } for (int k = 1; k < 3; k++) - tangential_coeffs[i][j][k] = tangential_coeffs[j][i][k] = tangential_coeffs_one[k]; + tangential_coeffs[i][j][k] = tangential_coeffs[j][i][k] = + tangential_coeffs_one[k]; roll_model[i][j] = roll_model[j][i] = roll_model_one; if (roll_model_one != ROLL_NONE) @@ -877,13 +947,13 @@ void PairGranular::coeff(int narg, char **arg) for (int k = 0; k < 3; k++) twist_coeffs[i][j][k] = twist_coeffs[j][i][k] = twist_coeffs_one[k]; - cutoff_type[i][j] = cutoff_type[j][i] = cutoff_one; setflag[i][j] = 1; count++; } } + if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); } @@ -902,17 +972,21 @@ void PairGranular::init_style() if (comm->ghost_velocity == 0) error->all(FLERR,"Pair granular requires ghost atoms store velocity"); - // Determine whether we need a granular neigh list, how large it needs to be - use_history = normal_history || tangential_history || roll_history || twist_history; + // determine whether we need a granular neigh list, how large it needs to be + + use_history = normal_history || tangential_history || + roll_history || twist_history; + + // for JKR, will need fix/neigh/history to keep track of touch arrays - //For JKR, will need fix/neigh/history to keep track of touch arrays for (int i = 1; i <= atom->ntypes; i++) for (int j = i; j <= atom->ntypes; j++) if (normal_model[i][j] == JKR) use_history = 1; size_history = 3*tangential_history + 3*roll_history + twist_history; - //Determine location of tangential/roll/twist histories in array + // determine location of tangential/roll/twist histories in array + if (roll_history) { if (tangential_history) roll_history_index = 3; else roll_history_index = 0; @@ -1036,7 +1110,7 @@ void PairGranular::init_style() } /* ---------------------------------------------------------------------- - init for one type pair i,j and corresponding j,i + init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairGranular::init_one(int i, int j) @@ -1051,46 +1125,58 @@ double PairGranular::init_one(int i, int j) (twist_model[i][i] != twist_model[j][j])) { char str[512]; - sprintf(str,"Granular pair style functional forms are different, cannot mix coefficients for types %d and %d. \nThis combination must be set explicitly via pair_coeff command.",i,j); + sprintf(str,"Granular pair style functional forms are different, " + "cannot mix coefficients for types %d and %d. \n" + "This combination must be set explicitly " + "via pair_coeff command",i,j); error->one(FLERR,str); } if (normal_model[i][j] == HERTZ || normal_model[i][j] == HOOKE) - normal_coeffs[i][j][0] = normal_coeffs[j][i][0] = mix_geom(normal_coeffs[i][i][0], normal_coeffs[j][j][0]); + normal_coeffs[i][j][0] = normal_coeffs[j][i][0] = + mix_geom(normal_coeffs[i][i][0], normal_coeffs[j][j][0]); else - normal_coeffs[i][j][0] = normal_coeffs[j][i][0] = mix_stiffnessE(Emod[i][i], Emod[j][j], poiss[i][i], poiss[j][j]); + normal_coeffs[i][j][0] = normal_coeffs[j][i][0] = + mix_stiffnessE(Emod[i][i], Emod[j][j], poiss[i][i], poiss[j][j]); - normal_coeffs[i][j][1] = normal_coeffs[j][i][1] = mix_geom(normal_coeffs[i][i][1], normal_coeffs[j][j][1]); + normal_coeffs[i][j][1] = normal_coeffs[j][i][1] = + mix_geom(normal_coeffs[i][i][1], normal_coeffs[j][j][1]); if ((normal_model[i][j] == JKR) || (normal_model[i][j] == DMT)) - normal_coeffs[i][j][3] = normal_coeffs[j][i][3] = mix_geom(normal_coeffs[i][i][3], normal_coeffs[j][j][3]); + normal_coeffs[i][j][3] = normal_coeffs[j][i][3] = + mix_geom(normal_coeffs[i][i][3], normal_coeffs[j][j][3]); for (int k = 0; k < 3; k++) - tangential_coeffs[i][j][k] = tangential_coeffs[j][i][k] = mix_geom(tangential_coeffs[i][i][k], tangential_coeffs[j][j][k]); + tangential_coeffs[i][j][k] = tangential_coeffs[j][i][k] = + mix_geom(tangential_coeffs[i][i][k], tangential_coeffs[j][j][k]); if (roll_model[i][j] != ROLL_NONE) { for (int k = 0; k < 3; k++) - roll_coeffs[i][j][k] = roll_coeffs[j][i][k] = mix_geom(roll_coeffs[i][i][k], roll_coeffs[j][j][k]); + roll_coeffs[i][j][k] = roll_coeffs[j][i][k] = + mix_geom(roll_coeffs[i][i][k], roll_coeffs[j][j][k]); } if (twist_model[i][j] != TWIST_NONE && twist_model[i][j] != TWIST_MARSHALL) { for (int k = 0; k < 3; k++) - twist_coeffs[i][j][k] = twist_coeffs[j][i][k] = mix_geom(twist_coeffs[i][i][k], twist_coeffs[j][j][k]); + twist_coeffs[i][j][k] = twist_coeffs[j][i][k] = + mix_geom(twist_coeffs[i][i][k], twist_coeffs[j][j][k]); } } - // It is possible that cut[i][j] at this point is still 0.0. This can happen when + // It is possible that cut[i][j] at this point is still 0.0. + // This can happen when // there is a future fix_pour after the current run. A cut[i][j] = 0.0 creates // problems because neighbor.cpp uses min(cut[i][j]) to decide on the bin size // To avoid this issue, for cases involving cut[i][j] = 0.0 (possible only // if there is no current information about radius/cutoff of type i and j). // we assign cutoff = max(cut[i][j]) for i,j such that cut[i][j] > 0.0. + double pulloff; if (cutoff_type[i][j] < 0 && cutoff_global < 0) { if (((maxrad_dynamic[i] > 0.0) && (maxrad_dynamic[j] > 0.0)) || ((maxrad_dynamic[i] > 0.0) && (maxrad_frozen[j] > 0.0)) || - ((maxrad_frozen[i] > 0.0) && (maxrad_dynamic[j] > 0.0))) { // radius info about both i and j exist - + // radius info about both i and j exist + ((maxrad_frozen[i] > 0.0) && (maxrad_dynamic[j] > 0.0))) { cutoff = maxrad_dynamic[i]+maxrad_dynamic[j]; pulloff = 0.0; if (normal_model[i][j] == JKR) { @@ -1105,7 +1191,13 @@ double PairGranular::init_one(int i, int j) if (normal_model[i][j] == JKR) pulloff = pulloff_distance(maxrad_dynamic[i], maxrad_frozen[j], i, j); cutoff = MAX(cutoff,maxrad_dynamic[i]+maxrad_frozen[j]+pulloff); - } else { // radius info about either i or j does not exist (i.e. not present and not about to get poured; set to largest value to not interfere with neighbor list) + + } else { + + // radius info about either i or j does not exist + // (i.e. not present and not about to get poured; + // set to largest value to not interfere with neighbor list) + double cutmax = 0.0; for (int k = 1; k <= atom->ntypes; k++) { cutmax = MAX(cutmax,2.0*maxrad_dynamic[k]); @@ -1123,8 +1215,8 @@ double PairGranular::init_one(int i, int j) } /* ---------------------------------------------------------------------- - proc 0 writes to restart file - ------------------------------------------------------------------------- */ + proc 0 writes to restart file +------------------------------------------------------------------------- */ void PairGranular::write_restart(FILE *fp) { @@ -1149,8 +1241,8 @@ void PairGranular::write_restart(FILE *fp) } /* ---------------------------------------------------------------------- - proc 0 reads from restart file, bcasts - ------------------------------------------------------------------------- */ + proc 0 reads from restart file, bcasts +------------------------------------------------------------------------- */ void PairGranular::read_restart(FILE *fp) { @@ -1189,7 +1281,6 @@ void PairGranular::read_restart(FILE *fp) } } - /* ---------------------------------------------------------------------- */ void PairGranular::reset_dt() @@ -1216,18 +1307,17 @@ double PairGranular::single(int i, int j, int itype, int jtype, double Fne, Ft, Fdamp, Fntot, Fncrit, Fscrit, Frcrit; double fs, fs1, fs2, fs3; - //For JKR + // for JKR double R2, coh, F_pulloff, delta_pulloff, dist_pulloff, a, a2, E; double delta, t0, t1, t2, t3, t4, t5, t6; double sqrt1, sqrt2, sqrt3; - - //Rolling + // rolling double k_roll, damp_roll; double rollmag; double fr, fr1, fr2, fr3; - //Twisting + // twisting double k_twist, damp_twist, mu_twist; double signtwist, magtwist, magtortwist, Mtcrit; @@ -1338,7 +1428,8 @@ double PairGranular::single(int i, int j, int itype, int jtype, t1 = PI27SQ*t0; t2 = 8*dR*dR2*E*E*E; t3 = 4*dR2*E; - sqrt1 = MAX(0, t0*(t1+2*t2)); //In case of sqrt(0) < 0 due to precision issues + // in case sqrt(0) < 0 due to precision issues + sqrt1 = MAX(0, t0*(t1+2*t2)); t4 = cbrt(t1+t2+THREEROOT3*M_PI*sqrt(sqrt1)); t5 = t3/t4 + t4/E; sqrt2 = MAX(0, 2*dR + t5); @@ -1387,7 +1478,7 @@ double PairGranular::single(int i, int j, int itype, int jtype, } //**************************************** - //Tangential force, including history effects + // tangential force, including history effects //**************************************** // tangential component @@ -1418,7 +1509,7 @@ double PairGranular::single(int i, int j, int itype, int jtype, } //------------------------------ - //Tangential forces + // tangential forces //------------------------------ k_tangential = tangential_coeffs[itype][jtype][0]; damp_tangential = tangential_coeffs[itype][jtype][1]*damp_normal_prefactor; @@ -1428,7 +1519,8 @@ double PairGranular::single(int i, int j, int itype, int jtype, k_tangential *= a; } else if (tangential_model[itype][jtype] == TANGENTIAL_MINDLIN_RESCALE) { k_tangential *= a; - if (a < history[3]) { //On unloading, rescale the shear displacements + // on unloading, rescale the shear displacements + if (a < history[3]) { double factor = a/history[3]; history[0] *= factor; history[1] *= factor; @@ -1457,7 +1549,9 @@ double PairGranular::single(int i, int j, int itype, int jtype, fs3 *= Fscrit/fs; } else fs1 = fs2 = fs3 = 0.0; } - } else { //Classic pair gran/hooke (no history) + + // classic pair gran/hooke (no history) + } else { fs = meff*damp_tangential*vrel; if (vrel != 0.0) Ft = MIN(Fne,fs) / vrel; else Ft = 0.0; @@ -1467,7 +1561,7 @@ double PairGranular::single(int i, int j, int itype, int jtype, } //**************************************** - // Rolling resistance + // rolling resistance //**************************************** if (roll_model[itype][jtype] != ROLL_NONE) { @@ -1476,8 +1570,10 @@ double PairGranular::single(int i, int j, int itype, int jtype, relrot3 = omega[i][2] - omega[j][2]; // rolling velocity, see eq. 31 of Wang et al, Particuology v 23, p 49 (2015) - // This is different from the Marshall papers, which use the Bagi/Kuhn formulation + // this is different from the Marshall papers, + // which use the Bagi/Kuhn formulation // for rolling velocity (see Wang et al for why the latter is wrong) + vrl1 = Reff*(relrot2*nz - relrot3*ny); //- 0.5*((radj-radi)/radsum)*vtr1; vrl2 = Reff*(relrot3*nx - relrot1*nz); //- 0.5*((radj-radi)/radsum)*vtr2; vrl3 = Reff*(relrot1*ny - relrot2*nx); //- 0.5*((radj-radi)/radsum)*vtr3; @@ -1486,7 +1582,7 @@ double PairGranular::single(int i, int j, int itype, int jtype, int rhist1 = rhist0 + 1; int rhist2 = rhist1 + 1; - // Rolling displacement + // rolling displacement rollmag = sqrt(history[rhist0]*history[rhist0] + history[rhist1]*history[rhist1] + history[rhist2]*history[rhist2]); @@ -1512,10 +1608,12 @@ double PairGranular::single(int i, int j, int itype, int jtype, } //**************************************** - // Twisting torque, including history effects + // twisting torque, including history effects //**************************************** + if (twist_model[itype][jtype] != TWIST_NONE) { - magtwist = relrot1*nx + relrot2*ny + relrot3*nz; //Omega_T (eq 29 of Marshall) + // omega_T (eq 29 of Marshall) + magtwist = relrot1*nx + relrot2*ny + relrot3*nz; if (twist_model[itype][jtype] == TWIST_MARSHALL) { k_twist = 0.5*k_tangential*a*a;; //eq 32 damp_twist = 0.5*damp_tangential*a*a; @@ -1525,11 +1623,12 @@ double PairGranular::single(int i, int j, int itype, int jtype, damp_twist = twist_coeffs[itype][jtype][1]; mu_twist = twist_coeffs[itype][jtype][2]; } - magtortwist = -k_twist*history[twist_history_index] - damp_twist*magtwist;//M_t torque (eq 30) + // M_t torque (eq 30) + magtortwist = -k_twist*history[twist_history_index] - damp_twist*magtwist; signtwist = (magtwist > 0) - (magtwist < 0); - Mtcrit = mu_twist*Fncrit;//critical torque (eq 44) + Mtcrit = mu_twist*Fncrit; // critical torque (eq 44) if (fabs(magtortwist) > Mtcrit) { - magtortwist = -Mtcrit * signtwist; //eq 34 + magtortwist = -Mtcrit * signtwist; // eq 34 } } @@ -1578,8 +1677,8 @@ void PairGranular::unpack_forward_comm(int n, int first, double *buf) } /* ---------------------------------------------------------------------- - memory usage of local atom-based arrays - ------------------------------------------------------------------------- */ + memory usage of local atom-based arrays +------------------------------------------------------------------------- */ double PairGranular::memory_usage() { @@ -1588,25 +1687,27 @@ double PairGranular::memory_usage() } /* ---------------------------------------------------------------------- - mixing of Young's modulus (E) + mixing of Young's modulus (E) ------------------------------------------------------------------------- */ -double PairGranular::mix_stiffnessE(double Eii, double Ejj, double poisii, double poisjj) +double PairGranular::mix_stiffnessE(double Eii, double Ejj, + double poisii, double poisjj) { return 1/((1-poisii*poisii)/Eii+(1-poisjj*poisjj)/Ejj); } /* ---------------------------------------------------------------------- - mixing of shear modulus (G) + mixing of shear modulus (G) ------------------------------------------------------------------------ */ -double PairGranular::mix_stiffnessG(double Eii, double Ejj, double poisii, double poisjj) +double PairGranular::mix_stiffnessG(double Eii, double Ejj, + double poisii, double poisjj) { return 1/((2*(2-poisii)*(1+poisii)/Eii) + (2*(2-poisjj)*(1+poisjj)/Ejj)); } /* ---------------------------------------------------------------------- - mixing of everything else + mixing of everything else ------------------------------------------------------------------------- */ double PairGranular::mix_geom(double valii, double valjj) @@ -1616,10 +1717,11 @@ double PairGranular::mix_geom(double valii, double valjj) /* ---------------------------------------------------------------------- - Compute pull-off distance (beyond contact) for a given radius and atom type + compute pull-off distance (beyond contact) for a given radius and atom type ------------------------------------------------------------------------- */ -double PairGranular::pulloff_distance(double radi, double radj, int itype, int jtype) +double PairGranular::pulloff_distance(double radi, double radj, + int itype, int jtype) { double E, coh, a, Reff; Reff = radi*radj/(radi+radj); @@ -1631,11 +1733,12 @@ double PairGranular::pulloff_distance(double radi, double radj, int itype, int j } /* ---------------------------------------------------------------------- - Transfer history during fix/neigh/history exchange - Only needed if any history entries i-j are not just negative of j-i entries + transfer history during fix/neigh/history exchange + only needed if any history entries i-j are not just negative of j-i entries ------------------------------------------------------------------------- */ -void PairGranular::transfer_history(double* source, double* target) { + +void PairGranular::transfer_history(double* source, double* target) +{ for (int i = 0; i < size_history; i++) target[i] = history_transfer_factors[i]*source[i]; } - diff --git a/src/GRANULAR/pair_granular.h b/src/GRANULAR/pair_granular.h index 4743d271f5..935e676487 100644 --- a/src/GRANULAR/pair_granular.h +++ b/src/GRANULAR/pair_granular.h @@ -66,29 +66,29 @@ class PairGranular : public Pair { int size_history; int *history_transfer_factors; - //Model choices + // model choices int **normal_model, **damping_model; int **tangential_model, **roll_model, **twist_model; - //History flags + // history flags int normal_history, tangential_history, roll_history, twist_history; - //Indices of history entries + // indices of history entries int normal_history_index; int tangential_history_index; int roll_history_index; int twist_history_index; - //Per-type material coefficients + // per-type material coefficients double **Emod, **poiss, **Gmod; - //Per-type coefficients, set in pair coeff command + // per-type coefficients, set in pair coeff command double ***normal_coeffs; double ***tangential_coeffs; double ***roll_coeffs; double ***twist_coeffs; - //Optional user-specified global cutoff, per-type user-specified cutoffs + // optional user-specified global cutoff, per-type user-specified cutoffs double **cutoff_type; double cutoff_global; diff --git a/src/fix_neigh_history.cpp b/src/fix_neigh_history.cpp index e33ebe57dc..207c409596 100644 --- a/src/fix_neigh_history.cpp +++ b/src/fix_neigh_history.cpp @@ -408,7 +408,8 @@ void FixNeighHistory::pre_exchange_newton() m = npartner[j]++; partner[j][m] = tag[i]; jvalues = &valuepartner[j][dnum*m]; - if (pair->nondefault_history_transfer) pair->transfer_history(onevalues, jvalues); + if (pair->nondefault_history_transfer) + pair->transfer_history(onevalues,jvalues); else for (n = 0; n < dnum; n++) jvalues[n] = -onevalues[n]; } } @@ -521,7 +522,8 @@ void FixNeighHistory::pre_exchange_no_newton() m = npartner[j]++; partner[j][m] = tag[i]; jvalues = &valuepartner[j][dnum*m]; - if (pair->nondefault_history_transfer) pair->transfer_history(onevalues, jvalues); + if (pair->nondefault_history_transfer) + pair->transfer_history(onevalues, jvalues); else for (n = 0; n < dnum; n++) jvalues[n] = -onevalues[n]; } } diff --git a/src/pair.h b/src/pair.h index 0911bff706..035ebc8773 100644 --- a/src/pair.h +++ b/src/pair.h @@ -98,7 +98,7 @@ class Pair : protected Pointers { enum{GEOMETRIC,ARITHMETIC,SIXTHPOWER}; // mixing options - int beyond_contact, nondefault_history_transfer; //for granular styles + int beyond_contact, nondefault_history_transfer; // for granular styles // KOKKOS host/device flag and data masks From 5d7c52e114cb1f51cb191efd943058814054bc23 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 28 Mar 2019 11:23:37 -0400 Subject: [PATCH 40/44] clean up whitespace issues caused by commit 5210c4c3a4e21e63036ca51554fc8f49ceb88274 --- src/GRANULAR/fix_wall_gran.cpp | 50 +++++------ src/GRANULAR/fix_wall_gran_region.cpp | 2 +- src/GRANULAR/pair_gran_hooke_history.cpp | 2 +- src/GRANULAR/pair_granular.cpp | 102 +++++++++++------------ src/GRANULAR/pair_granular.h | 2 +- 5 files changed, 79 insertions(+), 79 deletions(-) diff --git a/src/GRANULAR/fix_wall_gran.cpp b/src/GRANULAR/fix_wall_gran.cpp index 9925c37e4b..650938fd7c 100644 --- a/src/GRANULAR/fix_wall_gran.cpp +++ b/src/GRANULAR/fix_wall_gran.cpp @@ -124,7 +124,7 @@ FixWallGran::FixWallGran(LAMMPS *lmp, int narg, char **arg) : roll_model = twist_model = NONE; while (iarg < narg) { if (strcmp(arg[iarg], "hooke") == 0) { - if (iarg + 2 >= narg) + if (iarg + 2 >= narg) error->all(FLERR,"Illegal fix wall/gran command, " "not enough parameters provided for Hooke option"); normal_model = NORMAL_HOOKE; @@ -133,7 +133,7 @@ FixWallGran::FixWallGran(LAMMPS *lmp, int narg, char **arg) : iarg += 3; } else if (strcmp(arg[iarg], "hertz") == 0) { int num_coeffs = 2; - if (iarg + num_coeffs >= narg) + if (iarg + num_coeffs >= narg) error->all(FLERR,"Illegal fix wall/gran command, " "not enough parameters provided for Hertz option"); normal_model = NORMAL_HERTZ; @@ -142,7 +142,7 @@ FixWallGran::FixWallGran(LAMMPS *lmp, int narg, char **arg) : iarg += num_coeffs+1; } else if (strcmp(arg[iarg], "hertz/material") == 0) { int num_coeffs = 3; - if (iarg + num_coeffs >= narg) + if (iarg + num_coeffs >= narg) error->all(FLERR,"Illegal fix wall/gran command, " "not enough parameters provided for Hertz option"); normal_model = HERTZ_MATERIAL; @@ -153,7 +153,7 @@ FixWallGran::FixWallGran(LAMMPS *lmp, int narg, char **arg) : normal_coeffs[2] = poiss; iarg += num_coeffs+1; } else if (strcmp(arg[iarg], "dmt") == 0) { - if (iarg + 4 >= narg) + if (iarg + 4 >= narg) error->all(FLERR,"Illegal fix wall/gran command, " "not enough parameters provided for Hertz option"); normal_model = DMT; @@ -165,7 +165,7 @@ FixWallGran::FixWallGran(LAMMPS *lmp, int narg, char **arg) : normal_coeffs[3] = force->numeric(FLERR,arg[iarg+4]); //cohesion iarg += 5; } else if (strcmp(arg[iarg], "jkr") == 0) { - if (iarg + 4 >= narg) + if (iarg + 4 >= narg) error->all(FLERR,"Illegal wall/gran command, " "not enough parameters provided for JKR option"); beyond_contact = 1; @@ -178,7 +178,7 @@ FixWallGran::FixWallGran(LAMMPS *lmp, int narg, char **arg) : normal_coeffs[3] = force->numeric(FLERR,arg[iarg+4]); //cohesion iarg += 5; } else if (strcmp(arg[iarg], "damping") == 0) { - if (iarg+1 >= narg) + if (iarg+1 >= narg) error->all(FLERR, "Illegal wall/gran command, " "not enough parameters provided for damping model"); if (strcmp(arg[iarg+1], "velocity") == 0) { @@ -194,11 +194,11 @@ FixWallGran::FixWallGran(LAMMPS *lmp, int narg, char **arg) : "unrecognized damping model"); iarg += 1; } else if (strcmp(arg[iarg], "tangential") == 0) { - if (iarg + 1 >= narg) + if (iarg + 1 >= narg) error->all(FLERR,"Illegal pair_coeff command, " "must specify tangential model after tangential keyword"); if (strcmp(arg[iarg+1], "linear_nohistory") == 0) { - if (iarg + 3 >= narg) + if (iarg + 3 >= narg) error->all(FLERR,"Illegal pair_coeff command, " "not enough parameters provided for tangential model"); tangential_model = TANGENTIAL_NOHISTORY; @@ -210,16 +210,16 @@ FixWallGran::FixWallGran(LAMMPS *lmp, int narg, char **arg) : } else if ((strcmp(arg[iarg+1], "linear_history") == 0) || (strcmp(arg[iarg+1], "mindlin") == 0) || (strcmp(arg[iarg+1], "mindlin_rescale") == 0)) { - if (iarg + 4 >= narg) + if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, " "not enough parameters provided for tangential model"); - if (strcmp(arg[iarg+1], "linear_history") == 0) + if (strcmp(arg[iarg+1], "linear_history") == 0) tangential_model = TANGENTIAL_HISTORY; - else if (strcmp(arg[iarg+1], "mindlin") == 0) + else if (strcmp(arg[iarg+1], "mindlin") == 0) tangential_model = TANGENTIAL_MINDLIN; - else if (strcmp(arg[iarg+1], "mindlin_rescale") == 0) + else if (strcmp(arg[iarg+1], "mindlin_rescale") == 0) tangential_model = TANGENTIAL_MINDLIN_RESCALE; - if ((tangential_model == TANGENTIAL_MINDLIN || + if ((tangential_model == TANGENTIAL_MINDLIN || tangential_model == TANGENTIAL_MINDLIN_RESCALE) && (strcmp(arg[iarg+2], "NULL") == 0)) { if (normal_model == NORMAL_HERTZ || normal_model == NORMAL_HOOKE) { @@ -241,13 +241,13 @@ FixWallGran::FixWallGran(LAMMPS *lmp, int narg, char **arg) : "tangential model not recognized"); } } else if (strcmp(arg[iarg], "rolling") == 0) { - if (iarg + 1 >= narg) + if (iarg + 1 >= narg) error->all(FLERR, "Illegal wall/gran command, not enough parameters"); if (strcmp(arg[iarg+1], "none") == 0) { roll_model = ROLL_NONE; iarg += 2; } else if (strcmp(arg[iarg+1], "sds") == 0) { - if (iarg + 4 >= narg) + if (iarg + 4 >= narg) error->all(FLERR,"Illegal wall/gran command, " "not enough parameters provided for rolling model"); roll_model = ROLL_SDS; @@ -272,7 +272,7 @@ FixWallGran::FixWallGran(LAMMPS *lmp, int narg, char **arg) : twist_history = 1; iarg += 2; } else if (strcmp(arg[iarg+1], "sds") == 0) { - if (iarg + 4 >= narg) + if (iarg + 4 >= narg) error->all(FLERR,"Illegal wall/gran command, " "not enough parameters provided for twist model"); twist_model = TWIST_SDS; @@ -860,7 +860,7 @@ void FixWallGran::hooke_history(double rsq, double dx, double dy, double dz, history[1] += vtr2*dt; history[2] += vtr3*dt; } - shrmag = sqrt(history[0]*history[0] + history[1]*history[1] + + shrmag = sqrt(history[0]*history[0] + history[1]*history[1] + history[2]*history[2]); // rotate shear displacements @@ -991,7 +991,7 @@ void FixWallGran::hertz_history(double rsq, double dx, double dy, double dz, history[1] += vtr2*dt; history[2] += vtr3*dt; } - shrmag = sqrt(history[0]*history[0] + history[1]*history[1] + + shrmag = sqrt(history[0]*history[0] + history[1]*history[1] + history[2]*history[2]); // rotate history displacements @@ -1230,7 +1230,7 @@ void FixWallGran::granular(double rsq, double dx, double dy, double dz, history[thist2] *= factor; } } - shrmag = sqrt(history[thist0]*history[thist0] + + shrmag = sqrt(history[thist0]*history[thist0] + history[thist1]*history[thist1] + history[thist2]*history[thist2]); @@ -1242,7 +1242,7 @@ void FixWallGran::granular(double rsq, double dx, double dy, double dz, if (rsht > 0) { // if rhst == shrmag, contacting pair has rotated 90 deg in one step, // in which case you deserve a crash! - scalefac = shrmag/(shrmag - rsht); + scalefac = shrmag/(shrmag - rsht); history[thist0] -= rsht*nx; history[thist1] -= rsht*ny; history[thist2] -= rsht*nz; @@ -1267,11 +1267,11 @@ void FixWallGran::granular(double rsq, double dx, double dy, double dz, fs = sqrt(fs1*fs1 + fs2*fs2 + fs3*fs3); if (fs > Fscrit) { if (shrmag != 0.0) { - history[thist0] = -1.0/k_tangential*(Fscrit*fs1/fs + + history[thist0] = -1.0/k_tangential*(Fscrit*fs1/fs + damp_tangential*vtr1); - history[thist1] = -1.0/k_tangential*(Fscrit*fs2/fs + + history[thist1] = -1.0/k_tangential*(Fscrit*fs2/fs + damp_tangential*vtr2); - history[thist2] = -1.0/k_tangential*(Fscrit*fs3/fs + + history[thist2] = -1.0/k_tangential*(Fscrit*fs3/fs + damp_tangential*vtr3); fs1 *= Fscrit/fs; fs2 *= Fscrit/fs; @@ -1378,7 +1378,7 @@ void FixWallGran::granular(double rsq, double dx, double dy, double dz, signtwist = (magtwist > 0) - (magtwist < 0); Mtcrit = mu_twist*Fncrit; // critical torque (eq 44) if (fabs(magtortwist) > Mtcrit) { - history[twist_history_index] = 1.0/k_twist*(Mtcrit*signtwist - + history[twist_history_index] = 1.0/k_twist*(Mtcrit*signtwist - damp_twist*magtwist); magtortwist = -Mtcrit * signtwist; // eq 34 } @@ -1440,7 +1440,7 @@ double FixWallGran::memory_usage() if (use_history) bytes += nmax*size_history * sizeof(double); // shear history if (fix_rigid) bytes += nmax * sizeof(int); // mass_rigid // store contacts - if (peratom_flag) bytes += nmax*size_peratom_cols*sizeof(double); + if (peratom_flag) bytes += nmax*size_peratom_cols*sizeof(double); return bytes; } diff --git a/src/GRANULAR/fix_wall_gran_region.cpp b/src/GRANULAR/fix_wall_gran_region.cpp index e6f8406be0..7702967504 100644 --- a/src/GRANULAR/fix_wall_gran_region.cpp +++ b/src/GRANULAR/fix_wall_gran_region.cpp @@ -47,7 +47,7 @@ enum {NORMAL_HOOKE, NORMAL_HERTZ, HERTZ_MATERIAL, DMT, JKR}; /* ---------------------------------------------------------------------- */ FixWallGranRegion::FixWallGranRegion(LAMMPS *lmp, int narg, char **arg) : - FixWallGran(lmp, narg, arg), region(NULL), region_style(NULL), + FixWallGran(lmp, narg, arg), region(NULL), region_style(NULL), ncontact(NULL), walls(NULL), history_many(NULL), c2r(NULL) { diff --git a/src/GRANULAR/pair_gran_hooke_history.cpp b/src/GRANULAR/pair_gran_hooke_history.cpp index c86c2b0c90..27d2cf10a8 100644 --- a/src/GRANULAR/pair_gran_hooke_history.cpp +++ b/src/GRANULAR/pair_gran_hooke_history.cpp @@ -61,7 +61,7 @@ PairGranHookeHistory::PairGranHookeHistory(LAMMPS *lmp) : Pair(lmp) // keep default behavior of history[i][j] = -history[j][i] - nondefault_history_transfer = 0; + nondefault_history_transfer = 0; } /* ---------------------------------------------------------------------- */ diff --git a/src/GRANULAR/pair_granular.cpp b/src/GRANULAR/pair_granular.cpp index c8450c5434..7cc2348bbd 100644 --- a/src/GRANULAR/pair_granular.cpp +++ b/src/GRANULAR/pair_granular.cpp @@ -52,7 +52,7 @@ using namespace MathConst; enum {HOOKE, HERTZ, HERTZ_MATERIAL, DMT, JKR}; enum {VELOCITY, VISCOELASTIC, TSUJI}; -enum {TANGENTIAL_NOHISTORY, TANGENTIAL_HISTORY, +enum {TANGENTIAL_NOHISTORY, TANGENTIAL_HISTORY, TANGENTIAL_MINDLIN, TANGENTIAL_MINDLIN_RESCALE}; enum {TWIST_NONE, TWIST_SDS, TWIST_MARSHALL}; enum {ROLL_NONE, ROLL_SDS}; @@ -320,7 +320,7 @@ void PairGranular::compute(int eflag, int vflag) t2 = 8*dR*dR2*E*E*E; t3 = 4*dR2*E; // in case sqrt(0) < 0 due to precision issues - sqrt1 = MAX(0, t0*(t1+2*t2)); + sqrt1 = MAX(0, t0*(t1+2*t2)); t4 = cbrt(t1+t2+THREEROOT3*M_PI*sqrt(sqrt1)); t5 = t3/t4 + t4/E; sqrt2 = MAX(0, 2*dR + t5); @@ -405,7 +405,7 @@ void PairGranular::compute(int eflag, int vflag) if (tangential_history) { if (tangential_model[itype][jtype] == TANGENTIAL_MINDLIN) { k_tangential *= a; - } else if (tangential_model[itype][jtype] == + } else if (tangential_model[itype][jtype] == TANGENTIAL_MINDLIN_RESCALE) { k_tangential *= a; // on unloading, rescale the shear displacements @@ -439,7 +439,7 @@ void PairGranular::compute(int eflag, int vflag) history[0] += vtr1*dt; history[1] += vtr2*dt; history[2] += vtr3*dt; - if (tangential_model[itype][jtype] == TANGENTIAL_MINDLIN_RESCALE) + if (tangential_model[itype][jtype] == TANGENTIAL_MINDLIN_RESCALE) history[3] = a; } @@ -455,11 +455,11 @@ void PairGranular::compute(int eflag, int vflag) shrmag = sqrt(history[0]*history[0] + history[1]*history[1] + history[2]*history[2]); if (shrmag != 0.0) { - history[0] = -1.0/k_tangential*(Fscrit*fs1/fs + + history[0] = -1.0/k_tangential*(Fscrit*fs1/fs + damp_tangential*vtr1); - history[1] = -1.0/k_tangential*(Fscrit*fs2/fs + + history[1] = -1.0/k_tangential*(Fscrit*fs2/fs + damp_tangential*vtr2); - history[2] = -1.0/k_tangential*(Fscrit*fs3/fs + + history[2] = -1.0/k_tangential*(Fscrit*fs3/fs + damp_tangential*vtr3); fs1 *= Fscrit/fs; fs2 *= Fscrit/fs; @@ -486,15 +486,15 @@ void PairGranular::compute(int eflag, int vflag) // rolling velocity, // see eq. 31 of Wang et al, Particuology v 23, p 49 (2015) - // this is different from the Marshall papers, + // this is different from the Marshall papers, // which use the Bagi/Kuhn formulation // for rolling velocity (see Wang et al for why the latter is wrong) // - 0.5*((radj-radi)/radsum)*vtr1; // - 0.5*((radj-radi)/radsum)*vtr2; // - 0.5*((radj-radi)/radsum)*vtr3; - vrl1 = Reff*(relrot2*nz - relrot3*ny); - vrl2 = Reff*(relrot3*nx - relrot1*nz); + vrl1 = Reff*(relrot2*nz - relrot3*ny); + vrl2 = Reff*(relrot3*nx - relrot1*nz); vrl3 = Reff*(relrot1*ny - relrot2*nx); int rhist0 = roll_history_index; @@ -566,12 +566,12 @@ void PairGranular::compute(int eflag, int vflag) if (historyupdate) { history[twist_history_index] += magtwist*dt; } - magtortwist = -k_twist*history[twist_history_index] - + magtortwist = -k_twist*history[twist_history_index] - damp_twist*magtwist; // M_t torque (eq 30) signtwist = (magtwist > 0) - (magtwist < 0); Mtcrit = mu_twist*Fncrit; // critical torque (eq 44) if (fabs(magtortwist) > Mtcrit) { - history[twist_history_index] = 1.0/k_twist*(Mtcrit*signtwist - + history[twist_history_index] = 1.0/k_twist*(Mtcrit*signtwist - damp_twist*magtwist); magtortwist = -Mtcrit * signtwist; // eq 34 } @@ -729,7 +729,7 @@ void PairGranular::coeff(int narg, char **arg) int iarg = 2; while (iarg < narg) { if (strcmp(arg[iarg], "hooke") == 0) { - if (iarg + 2 >= narg) + if (iarg + 2 >= narg) error->all(FLERR,"Illegal pair_coeff command, " "not enough parameters provided for Hooke option"); normal_model_one = HOOKE; @@ -738,7 +738,7 @@ void PairGranular::coeff(int narg, char **arg) iarg += 3; } else if (strcmp(arg[iarg], "hertz") == 0) { int num_coeffs = 2; - if (iarg + num_coeffs >= narg) + if (iarg + num_coeffs >= narg) error->all(FLERR,"Illegal pair_coeff command, " "not enough parameters provided for Hertz option"); normal_model_one = HERTZ; @@ -747,7 +747,7 @@ void PairGranular::coeff(int narg, char **arg) iarg += num_coeffs+1; } else if (strcmp(arg[iarg], "hertz/material") == 0) { int num_coeffs = 3; - if (iarg + num_coeffs >= narg) + if (iarg + num_coeffs >= narg) error->all(FLERR,"Illegal pair_coeff command, " "not enough parameters provided for Hertz/material option"); normal_model_one = HERTZ_MATERIAL; @@ -756,7 +756,7 @@ void PairGranular::coeff(int narg, char **arg) normal_coeffs_one[2] = force->numeric(FLERR,arg[iarg+3]); // Poisson's ratio iarg += num_coeffs+1; } else if (strcmp(arg[iarg], "dmt") == 0) { - if (iarg + 4 >= narg) + if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, " "not enough parameters provided for Hertz option"); normal_model_one = DMT; @@ -766,7 +766,7 @@ void PairGranular::coeff(int narg, char **arg) normal_coeffs_one[3] = force->numeric(FLERR,arg[iarg+4]); // cohesion iarg += 5; } else if (strcmp(arg[iarg], "jkr") == 0) { - if (iarg + 4 >= narg) + if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, " "not enough parameters provided for JKR option"); beyond_contact = 1; @@ -777,7 +777,7 @@ void PairGranular::coeff(int narg, char **arg) normal_coeffs_one[3] = force->numeric(FLERR,arg[iarg+4]); // cohesion iarg += 5; } else if (strcmp(arg[iarg], "damping") == 0) { - if (iarg+1 >= narg) + if (iarg+1 >= narg) error->all(FLERR, "Illegal pair_coeff command, " "not enough parameters provided for damping model"); if (strcmp(arg[iarg+1], "velocity") == 0) { @@ -793,11 +793,11 @@ void PairGranular::coeff(int narg, char **arg) "unrecognized damping model"); iarg += 1; } else if (strcmp(arg[iarg], "tangential") == 0) { - if (iarg + 1 >= narg) + if (iarg + 1 >= narg) error->all(FLERR,"Illegal pair_coeff command, must specify " "tangential model after tangential keyword"); if (strcmp(arg[iarg+1], "linear_nohistory") == 0) { - if (iarg + 3 >= narg) + if (iarg + 3 >= narg) error->all(FLERR,"Illegal pair_coeff command, " "not enough parameters provided for tangential model"); tangential_model_one = TANGENTIAL_NOHISTORY; @@ -809,17 +809,17 @@ void PairGranular::coeff(int narg, char **arg) } else if ((strcmp(arg[iarg+1], "linear_history") == 0) || (strcmp(arg[iarg+1], "mindlin") == 0) || (strcmp(arg[iarg+1], "mindlin_rescale") == 0)) { - if (iarg + 4 >= narg) + if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, " "not enough parameters provided for tangential model"); - if (strcmp(arg[iarg+1], "linear_history") == 0) + if (strcmp(arg[iarg+1], "linear_history") == 0) tangential_model_one = TANGENTIAL_HISTORY; else if (strcmp(arg[iarg+1], "mindlin") == 0) tangential_model_one = TANGENTIAL_MINDLIN; - else if (strcmp(arg[iarg+1], "mindlin_rescale") == 0) + else if (strcmp(arg[iarg+1], "mindlin_rescale") == 0) tangential_model_one = TANGENTIAL_MINDLIN_RESCALE; tangential_history = 1; - if ((tangential_model_one == TANGENTIAL_MINDLIN || + if ((tangential_model_one == TANGENTIAL_MINDLIN || tangential_model_one == TANGENTIAL_MINDLIN_RESCALE) && (strcmp(arg[iarg+2], "NULL") == 0)) { if (normal_model_one == HERTZ || normal_model_one == HOOKE) { @@ -840,13 +840,13 @@ void PairGranular::coeff(int narg, char **arg) "tangential model not recognized"); } } else if (strcmp(arg[iarg], "rolling") == 0) { - if (iarg + 1 >= narg) + if (iarg + 1 >= narg) error->all(FLERR, "Illegal pair_coeff command, not enough parameters"); if (strcmp(arg[iarg+1], "none") == 0) { roll_model_one = ROLL_NONE; iarg += 2; } else if (strcmp(arg[iarg+1], "sds") == 0) { - if (iarg + 4 >= narg) + if (iarg + 4 >= narg) error->all(FLERR,"Illegal pair_coeff command, " "not enough parameters provided for rolling model"); roll_model_one = ROLL_SDS; @@ -861,7 +861,7 @@ void PairGranular::coeff(int narg, char **arg) "rolling friction model not recognized"); } } else if (strcmp(arg[iarg], "twisting") == 0) { - if (iarg + 1 >= narg) + if (iarg + 1 >= narg) error->all(FLERR, "Illegal pair_coeff command, not enough parameters"); if (strcmp(arg[iarg+1], "none") == 0) { twist_model_one = TWIST_NONE; @@ -886,14 +886,14 @@ void PairGranular::coeff(int narg, char **arg) "twisting friction model not recognized"); } } else if (strcmp(arg[iarg], "cutoff") == 0) { - if (iarg + 1 >= narg) + if (iarg + 1 >= narg) error->all(FLERR, "Illegal pair_coeff command, not enough parameters"); cutoff_one = force->numeric(FLERR,arg[iarg+1]); } else error->all(FLERR, "Illegal pair coeff command"); } // error not to specify normal or tangential model - if ((normal_model_one < 0) || (tangential_model_one < 0)) + if ((normal_model_one < 0) || (tangential_model_one < 0)) error->all(FLERR, "Illegal pair coeff command, " "must specify normal or tangential contact model"); @@ -914,7 +914,7 @@ void PairGranular::coeff(int narg, char **arg) if (normal_model_one != HERTZ && normal_model_one != HOOKE) { Emod[i][j] = Emod[j][i] = normal_coeffs_one[0]; poiss[i][j] = poiss[j][i] = normal_coeffs_one[2]; - normal_coeffs[i][j][0] = normal_coeffs[j][i][0] = + normal_coeffs[i][j][0] = normal_coeffs[j][i][0] = FOURTHIRDS*mix_stiffnessE(Emod[i][j],Emod[i][j], poiss[i][j],poiss[i][j]); } else { @@ -927,14 +927,14 @@ void PairGranular::coeff(int narg, char **arg) tangential_model[i][j] = tangential_model[j][i] = tangential_model_one; if (tangential_coeffs_one[0] == -1) { - tangential_coeffs[i][j][0] = tangential_coeffs[j][i][0] = + tangential_coeffs[i][j][0] = tangential_coeffs[j][i][0] = 8*mix_stiffnessG(Emod[i][j],Emod[i][j],poiss[i][j],poiss[i][j]); } else { - tangential_coeffs[i][j][0] = tangential_coeffs[j][i][0] = + tangential_coeffs[i][j][0] = tangential_coeffs[j][i][0] = tangential_coeffs_one[0]; } for (int k = 1; k < 3; k++) - tangential_coeffs[i][j][k] = tangential_coeffs[j][i][k] = + tangential_coeffs[i][j][k] = tangential_coeffs[j][i][k] = tangential_coeffs_one[k]; roll_model[i][j] = roll_model[j][i] = roll_model_one; @@ -974,7 +974,7 @@ void PairGranular::init_style() // determine whether we need a granular neigh list, how large it needs to be - use_history = normal_history || tangential_history || + use_history = normal_history || tangential_history || roll_history || twist_history; // for JKR, will need fix/neigh/history to keep track of touch arrays @@ -1133,36 +1133,36 @@ double PairGranular::init_one(int i, int j) } if (normal_model[i][j] == HERTZ || normal_model[i][j] == HOOKE) - normal_coeffs[i][j][0] = normal_coeffs[j][i][0] = + normal_coeffs[i][j][0] = normal_coeffs[j][i][0] = mix_geom(normal_coeffs[i][i][0], normal_coeffs[j][j][0]); else - normal_coeffs[i][j][0] = normal_coeffs[j][i][0] = + normal_coeffs[i][j][0] = normal_coeffs[j][i][0] = mix_stiffnessE(Emod[i][i], Emod[j][j], poiss[i][i], poiss[j][j]); - normal_coeffs[i][j][1] = normal_coeffs[j][i][1] = + normal_coeffs[i][j][1] = normal_coeffs[j][i][1] = mix_geom(normal_coeffs[i][i][1], normal_coeffs[j][j][1]); if ((normal_model[i][j] == JKR) || (normal_model[i][j] == DMT)) - normal_coeffs[i][j][3] = normal_coeffs[j][i][3] = + normal_coeffs[i][j][3] = normal_coeffs[j][i][3] = mix_geom(normal_coeffs[i][i][3], normal_coeffs[j][j][3]); for (int k = 0; k < 3; k++) - tangential_coeffs[i][j][k] = tangential_coeffs[j][i][k] = + tangential_coeffs[i][j][k] = tangential_coeffs[j][i][k] = mix_geom(tangential_coeffs[i][i][k], tangential_coeffs[j][j][k]); if (roll_model[i][j] != ROLL_NONE) { for (int k = 0; k < 3; k++) - roll_coeffs[i][j][k] = roll_coeffs[j][i][k] = + roll_coeffs[i][j][k] = roll_coeffs[j][i][k] = mix_geom(roll_coeffs[i][i][k], roll_coeffs[j][j][k]); } if (twist_model[i][j] != TWIST_NONE && twist_model[i][j] != TWIST_MARSHALL) { for (int k = 0; k < 3; k++) - twist_coeffs[i][j][k] = twist_coeffs[j][i][k] = + twist_coeffs[i][j][k] = twist_coeffs[j][i][k] = mix_geom(twist_coeffs[i][i][k], twist_coeffs[j][j][k]); } } - // It is possible that cut[i][j] at this point is still 0.0. + // It is possible that cut[i][j] at this point is still 0.0. // This can happen when // there is a future fix_pour after the current run. A cut[i][j] = 0.0 creates // problems because neighbor.cpp uses min(cut[i][j]) to decide on the bin size @@ -1176,7 +1176,7 @@ double PairGranular::init_one(int i, int j) if (((maxrad_dynamic[i] > 0.0) && (maxrad_dynamic[j] > 0.0)) || ((maxrad_dynamic[i] > 0.0) && (maxrad_frozen[j] > 0.0)) || // radius info about both i and j exist - ((maxrad_frozen[i] > 0.0) && (maxrad_dynamic[j] > 0.0))) { + ((maxrad_frozen[i] > 0.0) && (maxrad_dynamic[j] > 0.0))) { cutoff = maxrad_dynamic[i]+maxrad_dynamic[j]; pulloff = 0.0; if (normal_model[i][j] == JKR) { @@ -1194,7 +1194,7 @@ double PairGranular::init_one(int i, int j) } else { - // radius info about either i or j does not exist + // radius info about either i or j does not exist // (i.e. not present and not about to get poured; // set to largest value to not interfere with neighbor list) @@ -1520,7 +1520,7 @@ double PairGranular::single(int i, int j, int itype, int jtype, } else if (tangential_model[itype][jtype] == TANGENTIAL_MINDLIN_RESCALE) { k_tangential *= a; // on unloading, rescale the shear displacements - if (a < history[3]) { + if (a < history[3]) { double factor = a/history[3]; history[0] *= factor; history[1] *= factor; @@ -1551,7 +1551,7 @@ double PairGranular::single(int i, int j, int itype, int jtype, } // classic pair gran/hooke (no history) - } else { + } else { fs = meff*damp_tangential*vrel; if (vrel != 0.0) Ft = MIN(Fne,fs) / vrel; else Ft = 0.0; @@ -1570,7 +1570,7 @@ double PairGranular::single(int i, int j, int itype, int jtype, relrot3 = omega[i][2] - omega[j][2]; // rolling velocity, see eq. 31 of Wang et al, Particuology v 23, p 49 (2015) - // this is different from the Marshall papers, + // this is different from the Marshall papers, // which use the Bagi/Kuhn formulation // for rolling velocity (see Wang et al for why the latter is wrong) @@ -1690,7 +1690,7 @@ double PairGranular::memory_usage() mixing of Young's modulus (E) ------------------------------------------------------------------------- */ -double PairGranular::mix_stiffnessE(double Eii, double Ejj, +double PairGranular::mix_stiffnessE(double Eii, double Ejj, double poisii, double poisjj) { return 1/((1-poisii*poisii)/Eii+(1-poisjj*poisjj)/Ejj); @@ -1700,14 +1700,14 @@ double PairGranular::mix_stiffnessE(double Eii, double Ejj, mixing of shear modulus (G) ------------------------------------------------------------------------ */ -double PairGranular::mix_stiffnessG(double Eii, double Ejj, +double PairGranular::mix_stiffnessG(double Eii, double Ejj, double poisii, double poisjj) { return 1/((2*(2-poisii)*(1+poisii)/Eii) + (2*(2-poisjj)*(1+poisjj)/Ejj)); } /* ---------------------------------------------------------------------- - mixing of everything else + mixing of everything else ------------------------------------------------------------------------- */ double PairGranular::mix_geom(double valii, double valjj) @@ -1720,7 +1720,7 @@ double PairGranular::mix_geom(double valii, double valjj) compute pull-off distance (beyond contact) for a given radius and atom type ------------------------------------------------------------------------- */ -double PairGranular::pulloff_distance(double radi, double radj, +double PairGranular::pulloff_distance(double radi, double radj, int itype, int jtype) { double E, coh, a, Reff; diff --git a/src/GRANULAR/pair_granular.h b/src/GRANULAR/pair_granular.h index 935e676487..d799acb733 100644 --- a/src/GRANULAR/pair_granular.h +++ b/src/GRANULAR/pair_granular.h @@ -5,7 +5,7 @@ Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains - certain rights in this software. This software is distributed under + certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. From 03ee03c043523abb3a88b4574b0e6a2fc86eaa36 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 28 Mar 2019 11:44:50 -0400 Subject: [PATCH 41/44] remove set but unused flag --- src/GRANULAR/fix_wall_gran.cpp | 1 - src/GRANULAR/fix_wall_gran.h | 1 - 2 files changed, 2 deletions(-) diff --git a/src/GRANULAR/fix_wall_gran.cpp b/src/GRANULAR/fix_wall_gran.cpp index 650938fd7c..555c5071e7 100644 --- a/src/GRANULAR/fix_wall_gran.cpp +++ b/src/GRANULAR/fix_wall_gran.cpp @@ -168,7 +168,6 @@ FixWallGran::FixWallGran(LAMMPS *lmp, int narg, char **arg) : if (iarg + 4 >= narg) error->all(FLERR,"Illegal wall/gran command, " "not enough parameters provided for JKR option"); - beyond_contact = 1; normal_model = JKR; Emod = force->numeric(FLERR,arg[iarg+1]); //E normal_coeffs[1] = force->numeric(FLERR,arg[iarg+2]); //damping diff --git a/src/GRANULAR/fix_wall_gran.h b/src/GRANULAR/fix_wall_gran.h index ee81477ddb..f147e29433 100644 --- a/src/GRANULAR/fix_wall_gran.h +++ b/src/GRANULAR/fix_wall_gran.h @@ -69,7 +69,6 @@ class FixWallGran : public Fix { // for granular model choices int normal_model, damping_model; int tangential_model, roll_model, twist_model; - int beyond_contact; // history flags int normal_history, tangential_history, roll_history, twist_history; From 3cc740b9d3950dff935eb65edacba5140638b1a3 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 28 Mar 2019 11:46:04 -0400 Subject: [PATCH 42/44] handle granular specific pair style flags consistently and make sure they are never accessed uninitialized --- src/GRANULAR/pair_gran_hooke_history.h | 2 -- src/pair.cpp | 3 +++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/GRANULAR/pair_gran_hooke_history.h b/src/GRANULAR/pair_gran_hooke_history.h index b1bb212f89..81f2d8fd4a 100644 --- a/src/GRANULAR/pair_gran_hooke_history.h +++ b/src/GRANULAR/pair_gran_hooke_history.h @@ -26,8 +26,6 @@ namespace LAMMPS_NS { class PairGranHookeHistory : public Pair { public: - int nondefault_history_transfer; - PairGranHookeHistory(class LAMMPS *); virtual ~PairGranHookeHistory(); virtual void compute(int, int); diff --git a/src/pair.cpp b/src/pair.cpp index 44cf3a43ea..bce70af2a3 100644 --- a/src/pair.cpp +++ b/src/pair.cpp @@ -100,6 +100,9 @@ Pair::Pair(LAMMPS *lmp) : Pointers(lmp) num_tally_compute = 0; list_tally_compute = NULL; + nondefault_history_transfer = 0; + beyond_contact = 0; + // KOKKOS per-fix data masks execution_space = Host; From b9bddd7ba6ce1a0dda0424e29250143db072a2e8 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 28 Mar 2019 11:47:41 -0400 Subject: [PATCH 43/44] use ev_init() and add some more cosmetic changes to pair granular --- src/GRANULAR/pair_granular.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/GRANULAR/pair_granular.cpp b/src/GRANULAR/pair_granular.cpp index 7cc2348bbd..5254f93c9e 100644 --- a/src/GRANULAR/pair_granular.cpp +++ b/src/GRANULAR/pair_granular.cpp @@ -170,13 +170,10 @@ void PairGranular::compute(int eflag, int vflag) int *touch,**firsttouch; double *history,*allhistory,**firsthistory; - bool touchflag; + bool touchflag = false; + const bool historyupdate = (update->setupflag) ? false : true; - if (eflag || vflag) ev_setup(eflag,vflag); - else evflag = vflag_fdotr = 0; - - int historyupdate = 1; - if (update->setupflag) historyupdate = 0; + ev_init(eflag,vflag); // update rigid body info for owned & ghost atoms if using FixRigid masses // body[i] = which body atom I is in, -1 if none From ab12a7c95b5287f560d24e6098705ccd157e1e7e Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 28 Mar 2019 11:58:04 -0400 Subject: [PATCH 44/44] use consistent constants from math_const.h and fast integer powers from math_special --- src/GRANULAR/pair_granular.cpp | 42 +++++++++++++++++----------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/GRANULAR/pair_granular.cpp b/src/GRANULAR/pair_granular.cpp index 5254f93c9e..973acbbaf4 100644 --- a/src/GRANULAR/pair_granular.cpp +++ b/src/GRANULAR/pair_granular.cpp @@ -36,17 +36,18 @@ See the README file in the top-level LAMMPS directory. #include "memory.h" #include "error.h" #include "math_const.h" +#include "math_special.h" using namespace LAMMPS_NS; using namespace MathConst; +using namespace MathSpecial; #define PI27SQ 266.47931882941264802866 // 27*PI**2 #define THREEROOT3 5.19615242270663202362 // 3*sqrt(3) #define SIXROOT6 14.69693845669906728801 // 6*sqrt(6) #define INVROOT6 0.40824829046386307274 // 1/sqrt(6) -#define FOURTHIRDS 1.333333333333333 // 4/3 +#define FOURTHIRDS 4.0/3.0 // 4/3 #define THREEQUARTERS 0.75 // 3/4 -#define TWOPI 6.28318530717959 // 2*PI #define EPSILON 1e-10 @@ -251,8 +252,8 @@ void PairGranular::compute(int eflag, int vflag) if (touch[jj]) { R2 = Reff*Reff; coh = normal_coeffs[itype][jtype][3]; - a = cbrt(9.0*M_PI*coh*R2/(4*E)); - delta_pulloff = a*a/Reff - 2*sqrt(M_PI*coh*a/E); + a = cbrt(9.0*MY_PI*coh*R2/(4*E)); + delta_pulloff = a*a/Reff - 2*sqrt(MY_PI*coh*a/E); dist_pulloff = radsum-delta_pulloff; touchflag = (rsq < dist_pulloff*dist_pulloff); } else { @@ -318,15 +319,15 @@ void PairGranular::compute(int eflag, int vflag) t3 = 4*dR2*E; // in case sqrt(0) < 0 due to precision issues sqrt1 = MAX(0, t0*(t1+2*t2)); - t4 = cbrt(t1+t2+THREEROOT3*M_PI*sqrt(sqrt1)); + t4 = cbrt(t1+t2+THREEROOT3*MY_PI*sqrt(sqrt1)); t5 = t3/t4 + t4/E; sqrt2 = MAX(0, 2*dR + t5); t6 = sqrt(sqrt2); - sqrt3 = MAX(0, 4*dR - t5 + SIXROOT6*coh*M_PI*R2/(E*t6)); + sqrt3 = MAX(0, 4*dR - t5 + SIXROOT6*coh*MY_PI*R2/(E*t6)); a = INVROOT6*(t6 + sqrt(sqrt3)); a2 = a*a; knfac = normal_coeffs[itype][jtype][0]*a; - Fne = knfac*a2/Reff - TWOPI*a2*sqrt(4*coh*E/(M_PI*a)); + Fne = knfac*a2/Reff - MY_2PI*a2*sqrt(4*coh*E/(MY_PI*a)); } else { knfac = E; // Hooke Fne = knfac*delta; @@ -383,10 +384,10 @@ void PairGranular::compute(int eflag, int vflag) } if (normal_model[itype][jtype] == JKR) { - F_pulloff = 3*M_PI*coh*Reff; + F_pulloff = 3*MY_PI*coh*Reff; Fncrit = fabs(Fne + 2*F_pulloff); } else if (normal_model[itype][jtype] == DMT) { - F_pulloff = 4*M_PI*coh*Reff; + F_pulloff = 4*MY_PI*coh*Reff; Fncrit = fabs(Fne + 2*F_pulloff); } else { Fncrit = fabs(Fntot); @@ -899,9 +900,8 @@ void PairGranular::coeff(int narg, char **arg) if (damping_model_one == TSUJI) { double cor; cor = normal_coeffs_one[1]; - damp = 1.2728-4.2783*cor+11.087*pow(cor,2)-22.348*pow(cor,3)+ - 27.467*pow(cor,4)-18.022*pow(cor,5)+ - 4.8218*pow(cor,6); + damp = 1.2728-4.2783*cor+11.087*square(cor)-22.348*cube(cor)+ + 27.467*powint(cor,4)-18.022*powint(cor,5)+4.8218*powint(cor,6); } else damp = normal_coeffs_one[1]; for (int i = ilo; i <= ihi; i++) { @@ -1335,8 +1335,8 @@ double PairGranular::single(int i, int j, int itype, int jtype, E *= THREEQUARTERS; R2 = Reff*Reff; coh = normal_coeffs[itype][jtype][3]; - a = cbrt(9.0*M_PI*coh*R2/(4*E)); - delta_pulloff = a*a/Reff - 2*sqrt(M_PI*coh*a/E); + a = cbrt(9.0*MY_PI*coh*R2/(4*E)); + delta_pulloff = a*a/Reff - 2*sqrt(MY_PI*coh*a/E); dist_pulloff = radsum+delta_pulloff; touchflag = (rsq <= dist_pulloff*dist_pulloff); } else touchflag = (rsq <= radsum*radsum); @@ -1427,15 +1427,15 @@ double PairGranular::single(int i, int j, int itype, int jtype, t3 = 4*dR2*E; // in case sqrt(0) < 0 due to precision issues sqrt1 = MAX(0, t0*(t1+2*t2)); - t4 = cbrt(t1+t2+THREEROOT3*M_PI*sqrt(sqrt1)); + t4 = cbrt(t1+t2+THREEROOT3*MY_PI*sqrt(sqrt1)); t5 = t3/t4 + t4/E; sqrt2 = MAX(0, 2*dR + t5); t6 = sqrt(sqrt2); - sqrt3 = MAX(0, 4*dR - t5 + SIXROOT6*coh*M_PI*R2/(E*t6)); + sqrt3 = MAX(0, 4*dR - t5 + SIXROOT6*coh*MY_PI*R2/(E*t6)); a = INVROOT6*(t6 + sqrt(sqrt3)); a2 = a*a; knfac = normal_coeffs[itype][jtype][0]*a; - Fne = knfac*a2/Reff - TWOPI*a2*sqrt(4*coh*E/(M_PI*a)); + Fne = knfac*a2/Reff - MY_2PI*a2*sqrt(4*coh*E/(MY_PI*a)); } else { knfac = E; Fne = knfac*delta; @@ -1496,10 +1496,10 @@ double PairGranular::single(int i, int j, int itype, int jtype, vrel = sqrt(vrel); if (normal_model[itype][jtype] == JKR) { - F_pulloff = 3*M_PI*coh*Reff; + F_pulloff = 3*MY_PI*coh*Reff; Fncrit = fabs(Fne + 2*F_pulloff); } else if (normal_model[itype][jtype] == DMT) { - F_pulloff = 4*M_PI*coh*Reff; + F_pulloff = 4*MY_PI*coh*Reff; Fncrit = fabs(Fne + 2*F_pulloff); } else { Fncrit = fabs(Fntot); @@ -1725,8 +1725,8 @@ double PairGranular::pulloff_distance(double radi, double radj, if (Reff <= 0) return 0; coh = normal_coeffs[itype][itype][3]; E = normal_coeffs[itype][jtype][0]*THREEQUARTERS; - a = cbrt(9*M_PI*coh*Reff/(4*E)); - return a*a/Reff - 2*sqrt(M_PI*coh*a/E); + a = cbrt(9*MY_PI*coh*Reff/(4*E)); + return a*a/Reff - 2*sqrt(MY_PI*coh*a/E); } /* ----------------------------------------------------------------------