// clang-format off /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator https://www.lammps.org/, Sandia National Laboratories LAMMPS development team: developers@lammps.org Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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 "improper_fourier_omp.h" #include "atom.h" #include "comm.h" #include "force.h" #include "neighbor.h" #include #include "omp_compat.h" #include "suffix.h" using namespace LAMMPS_NS; #define TOLERANCE 0.05 #define SMALL 0.001 /* ---------------------------------------------------------------------- */ ImproperFourierOMP::ImproperFourierOMP(class LAMMPS *lmp) : ImproperFourier(lmp), ThrOMP(lmp,THR_IMPROPER) { suffix_flag |= Suffix::OMP; } /* ---------------------------------------------------------------------- */ void ImproperFourierOMP::compute(int eflag, int vflag) { ev_init(eflag,vflag); const int nall = atom->nlocal + atom->nghost; const int nthreads = comm->nthreads; const int inum = neighbor->nimproperlist; #if defined(_OPENMP) #pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; loop_setup_thr(ifrom, ito, tid, inum, nthreads); ThrData *thr = fix->get_thr(tid); thr->timer(Timer::START); ev_setup_thr(eflag, vflag, nall, eatom, vatom, cvatom, thr); if (inum > 0) { if (evflag) { if (eflag) { if (force->newton_bond) eval<1,1,1>(ifrom, ito, thr); else eval<1,1,0>(ifrom, ito, thr); } else { if (force->newton_bond) eval<1,0,1>(ifrom, ito, thr); else eval<1,0,0>(ifrom, ito, thr); } } else { if (force->newton_bond) eval<0,0,1>(ifrom, ito, thr); else eval<0,0,0>(ifrom, ito, thr); } } thr->timer(Timer::BOND); reduce_thr(this, eflag, vflag, thr); } // end of omp parallel region } template void ImproperFourierOMP::eval(int nfrom, int nto, ThrData * const thr) { int i1,i2,i3,i4,n,type; double vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z; const double * const * const x = atom->x; const int * const * const improperlist = neighbor->improperlist; for (n = nfrom; n < nto; n++) { i1 = improperlist[n][0]; i2 = improperlist[n][1]; i3 = improperlist[n][2]; i4 = improperlist[n][3]; type = improperlist[n][4]; // 1st bond vb1x = x[i2][0] - x[i1][0]; vb1y = x[i2][1] - x[i1][1]; vb1z = x[i2][2] - x[i1][2]; // 2nd bond vb2x = x[i3][0] - x[i1][0]; vb2y = x[i3][1] - x[i1][1]; vb2z = x[i3][2] - x[i1][2]; // 3rd bond vb3x = x[i4][0] - x[i1][0]; vb3y = x[i4][1] - x[i1][1]; vb3z = x[i4][2] - x[i1][2]; add1_thr(i1,i2,i3,i4,type, vb1x,vb1y,vb1z, vb2x,vb2y,vb2z, vb3x,vb3y,vb3z,thr); if (all[type]) { add1_thr(i1,i4,i2,i3,type, vb3x,vb3y,vb3z, vb1x,vb1y,vb1z, vb2x,vb2y,vb2z,thr); add1_thr(i1,i3,i4,i2,type, vb2x,vb2y,vb2z, vb3x,vb3y,vb3z, vb1x,vb1y,vb1z,thr); } } } template void ImproperFourierOMP::add1_thr(const int i1,const int i2, const int i3,const int i4, const int type, const double &vb1x, const double &vb1y, const double &vb1z, const double &vb2x, const double &vb2y, const double &vb2z, const double &vb3x, const double &vb3y, const double &vb3z, ThrData * const thr) { double eimproper,f1[3],f2[3],f3[3],f4[3]; double c,c2,a,s,projhfg,dhax,dhay,dhaz,dahx,dahy,dahz,cotphi; double ax,ay,az,ra2,rh2,ra,rh,rar,rhr,arx,ary,arz,hrx,hry,hrz; double * const * const f = thr->get_f(); const int nlocal = atom->nlocal; eimproper = 0.0; // c0 calculation // A = vb1 X vb2 is perpendicular to IJK plane ax = vb1y*vb2z-vb1z*vb2y; ay = vb1z*vb2x-vb1x*vb2z; az = vb1x*vb2y-vb1y*vb2x; ra2 = ax*ax+ay*ay+az*az; rh2 = vb3x*vb3x+vb3y*vb3y+vb3z*vb3z; ra = sqrt(ra2); rh = sqrt(rh2); if (ra < SMALL) ra = SMALL; if (rh < SMALL) rh = SMALL; rar = 1/ra; rhr = 1/rh; arx = ax*rar; ary = ay*rar; arz = az*rar; hrx = vb3x*rhr; hry = vb3y*rhr; hrz = vb3z*rhr; c = arx*hrx+ary*hry+arz*hrz; // error check if (c > 1.0 + TOLERANCE || c < (-1.0 - TOLERANCE)) problem(FLERR, i1, i2, i3, i4); if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; s = sqrt(1.0 - c*c); if (s < SMALL) s = SMALL; cotphi = c/s; projhfg = (vb3x*vb1x+vb3y*vb1y+vb3z*vb1z) / sqrt(vb1x*vb1x+vb1y*vb1y+vb1z*vb1z); projhfg += (vb3x*vb2x+vb3y*vb2y+vb3z*vb2z) / sqrt(vb2x*vb2x+vb2y*vb2y+vb2z*vb2z); if (projhfg > 0.0) { s *= -1.0; cotphi *= -1.0; } // force and energy // E = k ( C0 + C1 cos(w) + C2 cos(w) c2 = 2.0*s*s-1.0; if (EFLAG) eimproper = k[type]*(C0[type]+C1[type]*s+C2[type]*c2); // dhax = diffrence between H and A in X direction, etc a = k[type]*(C1[type]+4.0*C2[type]*s)*cotphi; dhax = hrx-c*arx; dhay = hry-c*ary; dhaz = hrz-c*arz; dahx = arx-c*hrx; dahy = ary-c*hry; dahz = arz-c*hrz; f2[0] = (dhay*vb1z - dhaz*vb1y)*rar*a; f2[1] = (dhaz*vb1x - dhax*vb1z)*rar*a; f2[2] = (dhax*vb1y - dhay*vb1x)*rar*a; f3[0] = (-dhay*vb2z + dhaz*vb2y)*rar*a; f3[1] = (-dhaz*vb2x + dhax*vb2z)*rar*a; f3[2] = (-dhax*vb2y + dhay*vb2x)*rar*a; f4[0] = dahx*rhr*a; f4[1] = dahy*rhr*a; f4[2] = dahz*rhr*a; f1[0] = -(f2[0] + f3[0] + f4[0]); f1[1] = -(f2[1] + f3[1] + f4[1]); f1[2] = -(f2[2] + f3[2] + f4[2]); // apply force to each of 4 atoms if (NEWTON_BOND || i1 < nlocal) { f[i1][0] += f1[0]; f[i1][1] += f1[1]; f[i1][2] += f1[2]; } if (NEWTON_BOND || i2 < nlocal) { f[i2][0] += f3[0]; f[i2][1] += f3[1]; f[i2][2] += f3[2]; } if (NEWTON_BOND || i3 < nlocal) { f[i3][0] += f2[0]; f[i3][1] += f2[1]; f[i3][2] += f2[2]; } if (NEWTON_BOND || i4 < nlocal) { f[i4][0] += f4[0]; f[i4][1] += f4[1]; f[i4][2] += f4[2]; } if (EVFLAG) ev_tally_thr(this,i1,i2,i3,i4,nlocal,NEWTON_BOND,eimproper,f1,f2,f4, -vb1x,-vb1y,-vb1z,vb2x-vb1x,vb2y-vb1y,vb2z-vb1z,vb3x-vb2x,vb3y-vb2y,vb3z-vb2z,thr); }