1 // clang-format off
2 /* ----------------------------------------------------------------------
3    LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
4    https://www.lammps.org/, Sandia National Laboratories
5    Steve Plimpton, sjplimp@sandia.gov
6 
7    Copyright (2003) Sandia Corporation.  Under the terms of Contract
8    DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
9    certain rights in this software.  This software is distributed under
10    the GNU General Public License.
11 
12    See the README file in the top-level LAMMPS directory.
13 ------------------------------------------------------------------------- */
14 
15 /* ----------------------------------------------------------------------
16    Contributing author: Xiaowang Zhou (SNL)
17 ------------------------------------------------------------------------- */
18 
19 #include "pair_eim.h"
20 
21 #include "atom.h"
22 #include "comm.h"
23 #include "error.h"
24 #include "force.h"
25 #include "memory.h"
26 #include "neigh_list.h"
27 #include "neighbor.h"
28 #include "tokenizer.h"
29 
30 #include <cmath>
31 #include <cstring>
32 
33 using namespace LAMMPS_NS;
34 
35 /* ---------------------------------------------------------------------- */
36 
PairEIM(LAMMPS * lmp)37 PairEIM::PairEIM(LAMMPS *lmp) : Pair(lmp)
38 {
39   single_enable = 0;
40   restartinfo = 0;
41   one_coeff = 1;
42   manybody_flag = 1;
43   centroidstressflag = CENTROID_NOTAVAIL;
44   unit_convert_flag = utils::get_supported_conversions(utils::ENERGY);
45 
46   setfl = nullptr;
47   nmax = 0;
48   rho = nullptr;
49   fp = nullptr;
50 
51   negativity = nullptr;
52   q0 = nullptr;
53   cutforcesq = nullptr;
54   Fij = nullptr;
55   Gij = nullptr;
56   phiij = nullptr;
57 
58   Fij_spline = nullptr;
59   Gij_spline = nullptr;
60   phiij_spline = nullptr;
61 
62   // set comm size needed by this Pair
63 
64   comm_forward = 1;
65   comm_reverse = 1;
66 }
67 
68 /* ----------------------------------------------------------------------
69    check if allocated, since class can be destructed when incomplete
70 ------------------------------------------------------------------------- */
71 
~PairEIM()72 PairEIM::~PairEIM()
73 {
74   memory->destroy(rho);
75   memory->destroy(fp);
76 
77   if (allocated) {
78     memory->destroy(setflag);
79     memory->destroy(cutsq);
80     memory->destroy(type2Fij);
81     memory->destroy(type2Gij);
82     memory->destroy(type2phiij);
83   }
84 
85   deallocate_setfl();
86 
87   delete [] negativity;
88   delete [] q0;
89   memory->destroy(cutforcesq);
90   memory->destroy(Fij);
91   memory->destroy(Gij);
92   memory->destroy(phiij);
93 
94   memory->destroy(Fij_spline);
95   memory->destroy(Gij_spline);
96   memory->destroy(phiij_spline);
97 }
98 
99 /* ---------------------------------------------------------------------- */
100 
compute(int eflag,int vflag)101 void PairEIM::compute(int eflag, int vflag)
102 {
103   int i,j,ii,jj,m,inum,jnum,itype,jtype;
104   double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair;
105   double rsq,r,p,rhoip,rhojp,phip,phi,coul,coulp,recip,psip;
106   double *coeff;
107   int *ilist,*jlist,*numneigh,**firstneigh;
108 
109   evdwl = 0.0;
110   ev_init(eflag,vflag);
111 
112   // grow energy array if necessary
113 
114   if (atom->nmax > nmax) {
115     memory->destroy(rho);
116     memory->destroy(fp);
117     nmax = atom->nmax;
118     memory->create(rho,nmax,"pair:rho");
119     memory->create(fp,nmax,"pair:fp");
120   }
121 
122   double **x = atom->x;
123   double **f = atom->f;
124   int *type = atom->type;
125   int nlocal = atom->nlocal;
126   int newton_pair = force->newton_pair;
127 
128   inum = list->inum;
129   ilist = list->ilist;
130   numneigh = list->numneigh;
131   firstneigh = list->firstneigh;
132 
133   // zero out density
134 
135   if (newton_pair) {
136     m = nlocal + atom->nghost;
137     for (i = 0; i < m; i++) {
138       rho[i] = 0.0;
139       fp[i] = 0.0;
140     }
141   } else {
142     for (i = 0; i < nlocal; i++) {
143       rho[i] = 0.0;
144       fp[i] = 0.0;
145     }
146   }
147 
148   // rho = density at each atom
149   // loop over neighbors of my atoms
150 
151   for (ii = 0; ii < inum; ii++) {
152     i = ilist[ii];
153     xtmp = x[i][0];
154     ytmp = x[i][1];
155     ztmp = x[i][2];
156     itype = type[i];
157     jlist = firstneigh[i];
158     jnum = numneigh[i];
159 
160     for (jj = 0; jj < jnum; jj++) {
161       j = jlist[jj];
162       j &= NEIGHMASK;
163       jtype = type[j];
164       delx = xtmp - x[j][0];
165       dely = ytmp - x[j][1];
166       delz = ztmp - x[j][2];
167       rsq = delx*delx + dely*dely + delz*delz;
168 
169       if (rsq < cutforcesq[itype][jtype]) {
170         p = sqrt(rsq)*rdr + 1.0;
171         m = static_cast<int> (p);
172         m = MIN(m,nr-1);
173         p -= m;
174         p = MIN(p,1.0);
175         coeff = Fij_spline[type2Fij[itype][jtype]][m];
176         rho[i] += ((coeff[3]*p + coeff[4])*p + coeff[5])*p + coeff[6];
177         if (newton_pair || j < nlocal) {
178           coeff = Fij_spline[type2Fij[jtype][itype]][m];
179           rho[j] += ((coeff[3]*p + coeff[4])*p + coeff[5])*p + coeff[6];
180         }
181       }
182     }
183   }
184 
185   // communicate and sum densities
186 
187   rhofp = 1;
188   if (newton_pair) comm->reverse_comm_pair(this);
189   comm->forward_comm_pair(this);
190 
191   for (ii = 0; ii < inum; ii++) {
192     i = ilist[ii];
193     xtmp = x[i][0];
194     ytmp = x[i][1];
195     ztmp = x[i][2];
196     itype = type[i];
197     jlist = firstneigh[i];
198     jnum = numneigh[i];
199 
200     for (jj = 0; jj < jnum; jj++) {
201       j = jlist[jj];
202       j &= NEIGHMASK;
203       jtype = type[j];
204 
205       delx = xtmp - x[j][0];
206       dely = ytmp - x[j][1];
207       delz = ztmp - x[j][2];
208       rsq = delx*delx + dely*dely + delz*delz;
209 
210       if (rsq < cutforcesq[itype][jtype]) {
211         p = sqrt(rsq)*rdr + 1.0;
212         m = static_cast<int> (p);
213         m = MIN(m,nr-1);
214         p -= m;
215         p = MIN(p,1.0);
216         coeff = Gij_spline[type2Gij[itype][jtype]][m];
217         fp[i] += rho[j]*(((coeff[3]*p + coeff[4])*p + coeff[5])*p + coeff[6]);
218         if (newton_pair || j < nlocal) {
219           fp[j] += rho[i]*(((coeff[3]*p + coeff[4])*p + coeff[5])*p +
220                            coeff[6]);
221         }
222       }
223     }
224   }
225 
226   // communicate and sum modified densities
227 
228   rhofp = 2;
229   if (newton_pair) comm->reverse_comm_pair(this);
230   comm->forward_comm_pair(this);
231 
232   for (ii = 0; ii < inum; ii++) {
233     i = ilist[ii];
234     if (eflag) {
235       phi = 0.5*rho[i]*fp[i];
236       if (eflag_global) eng_vdwl += phi;
237       if (eflag_atom) eatom[i] += phi;
238     }
239   }
240 
241   // compute forces on each atom
242   // loop over neighbors of my atoms
243 
244   for (ii = 0; ii < inum; ii++) {
245     i = ilist[ii];
246     xtmp = x[i][0];
247     ytmp = x[i][1];
248     ztmp = x[i][2];
249     itype = type[i];
250 
251     jlist = firstneigh[i];
252     jnum = numneigh[i];
253 
254     for (jj = 0; jj < jnum; jj++) {
255       j = jlist[jj];
256       j &= NEIGHMASK;
257       jtype = type[j];
258       delx = xtmp - x[j][0];
259       dely = ytmp - x[j][1];
260       delz = ztmp - x[j][2];
261       rsq = delx*delx + dely*dely + delz*delz;
262 
263       if (rsq < cutforcesq[itype][jtype]) {
264         r = sqrt(rsq);
265         p = r*rdr + 1.0;
266         m = static_cast<int> (p);
267         m = MIN(m,nr-1);
268         p -= m;
269         p = MIN(p,1.0);
270 
271         // rhoip = derivative of (density at atom j due to atom i)
272         // rhojp = derivative of (density at atom i due to atom j)
273         // phi = pair potential energy
274         // phip = phi'
275 
276         coeff = Fij_spline[type2Fij[jtype][itype]][m];
277         rhoip = (coeff[0]*p + coeff[1])*p + coeff[2];
278         coeff = Fij_spline[type2Fij[itype][jtype]][m];
279         rhojp = (coeff[0]*p + coeff[1])*p + coeff[2];
280         coeff = phiij_spline[type2phiij[itype][jtype]][m];
281         phip = (coeff[0]*p + coeff[1])*p + coeff[2];
282         phi = ((coeff[3]*p + coeff[4])*p + coeff[5])*p + coeff[6];
283         coeff = Gij_spline[type2Gij[itype][jtype]][m];
284         coul = ((coeff[3]*p + coeff[4])*p + coeff[5])*p + coeff[6];
285         coulp = (coeff[0]*p + coeff[1])*p + coeff[2];
286         psip = phip + (rho[i]*rho[j]-q0[itype]*q0[jtype])*coulp +
287                fp[i]*rhojp + fp[j]*rhoip;
288         recip = 1.0/r;
289         fpair = -psip*recip;
290         f[i][0] += delx*fpair;
291         f[i][1] += dely*fpair;
292         f[i][2] += delz*fpair;
293         if (newton_pair || j < nlocal) {
294           f[j][0] -= delx*fpair;
295           f[j][1] -= dely*fpair;
296           f[j][2] -= delz*fpair;
297         }
298 
299         if (eflag) evdwl = phi-q0[itype]*q0[jtype]*coul;
300         if (evflag) ev_tally(i,j,nlocal,newton_pair,
301                              evdwl,0.0,fpair,delx,dely,delz);
302       }
303     }
304   }
305 
306   if (vflag_fdotr) virial_fdotr_compute();
307 }
308 
309 /* ----------------------------------------------------------------------
310    allocate all arrays
311 ------------------------------------------------------------------------- */
312 
allocate()313 void PairEIM::allocate()
314 {
315   allocated = 1;
316   int n = atom->ntypes;
317 
318   memory->create(setflag,n+1,n+1,"pair:setflag");
319   for (int i = 1; i <= n; i++)
320     for (int j = i; j <= n; j++)
321       setflag[i][j] = 0;
322 
323   memory->create(cutsq,n+1,n+1,"pair:cutsq");
324 
325   map = new int[n+1];
326   for (int i = 1; i <= n; i++) map[i] = -1;
327 
328   memory->create(type2Fij,n+1,n+1,"pair:type2Fij");
329   memory->create(type2Gij,n+1,n+1,"pair:type2Gij");
330   memory->create(type2phiij,n+1,n+1,"pair:type2phiij");
331 }
332 
333 /* ----------------------------------------------------------------------
334    global settings
335 ------------------------------------------------------------------------- */
336 
settings(int narg,char **)337 void PairEIM::settings(int narg, char **/*arg*/)
338 {
339   if (narg > 0) error->all(FLERR,"Illegal pair_style command");
340 }
341 
342 /* ----------------------------------------------------------------------
343    set coeffs from set file
344 ------------------------------------------------------------------------- */
345 
coeff(int narg,char ** arg)346 void PairEIM::coeff(int narg, char **arg)
347 {
348   if (!allocated) allocate();
349 
350   if (narg < 5) error->all(FLERR,"Incorrect args for pair coefficients");
351 
352   // insure I,J args are * *
353 
354   if (strcmp(arg[0],"*") != 0 || strcmp(arg[1],"*") != 0)
355     error->all(FLERR,"Incorrect args for pair coefficients");
356 
357   const int ntypes = atom->ntypes;
358   map_element2type(ntypes,arg+(narg-ntypes));
359 
360   // read EIM file
361 
362   deallocate_setfl();
363   setfl = new Setfl();
364   read_file(arg[2+nelements]);
365 
366   // set per-type atomic masses
367 
368   for (int i = 1; i <= ntypes; i++)
369     for (int j = i; j <= ntypes; j++)
370       if ((map[i] >= 0) && (map[j] >= 0))
371         if (i == j) atom->set_mass(FLERR,i,setfl->mass[map[i]]);
372 }
373 
374 /* ----------------------------------------------------------------------
375    init specific to this pair style
376 ------------------------------------------------------------------------- */
377 
init_style()378 void PairEIM::init_style()
379 {
380   // convert read-in file(s) to arrays and spline them
381 
382   file2array();
383   array2spline();
384 
385   neighbor->request(this,instance_me);
386 }
387 
388 /* ----------------------------------------------------------------------
389    init for one type pair i,j and corresponding j,i
390 ------------------------------------------------------------------------- */
391 
init_one(int i,int j)392 double PairEIM::init_one(int i, int j)
393 {
394   cutmax = sqrt(cutforcesq[i][j]);
395   return cutmax;
396 }
397 
398 /* ----------------------------------------------------------------------
399    read potential values from a set file
400 ------------------------------------------------------------------------- */
401 
read_file(char * filename)402 void PairEIM::read_file(char *filename)
403 {
404   int npair = nelements*(nelements+1)/2;
405   setfl->ielement = new int[nelements];
406   setfl->mass = new double[nelements];
407   setfl->negativity = new double[nelements];
408   setfl->ra = new double[nelements];
409   setfl->ri = new double[nelements];
410   setfl->Ec = new double[nelements];
411   setfl->q0 = new double[nelements];
412   setfl->rcutphiA = new double[npair];
413   setfl->rcutphiR = new double[npair];
414   setfl->Eb = new double[npair];
415   setfl->r0 = new double[npair];
416   setfl->alpha = new double[npair];
417   setfl->beta = new double[npair];
418   setfl->rcutq = new double[npair];
419   setfl->Asigma = new double[npair];
420   setfl->rq = new double[npair];
421   setfl->rcutsigma = new double[npair];
422   setfl->Ac = new double[npair];
423   setfl->zeta = new double[npair];
424   setfl->rs = new double[npair];
425   setfl->tp = new int[npair];
426 
427   // read potential file
428   if ( comm->me == 0) {
429     EIMPotentialFileReader reader(lmp, filename, unit_convert_flag);
430 
431     reader.get_global(setfl);
432 
433     for (int i = 0; i < nelements; i++) {
434       reader.get_element(setfl, i, elements[i]);
435     }
436 
437     for (int i = 0; i < nelements; i++) {
438       for (int j = i; j < nelements; j++) {
439         int ij;
440         if (i == j) ij = i;
441         else if (i < j) ij = nelements*(i+1) - (i+1)*(i+2)/2 + j;
442         else ij = nelements*(j+1) - (j+1)*(j+2)/2 + i;
443         reader.get_pair(setfl, ij, elements[i], elements[j]);
444       }
445     }
446   }
447 
448   // broadcast potential information to other procs
449   MPI_Bcast(&setfl->division, 1, MPI_DOUBLE, 0, world);
450   MPI_Bcast(&setfl->rbig, 1, MPI_DOUBLE, 0, world);
451   MPI_Bcast(&setfl->rsmall, 1, MPI_DOUBLE, 0, world);
452 
453   MPI_Bcast(setfl->ielement, nelements, MPI_INT, 0, world);
454   MPI_Bcast(setfl->mass, nelements, MPI_DOUBLE, 0, world);
455   MPI_Bcast(setfl->negativity, nelements, MPI_DOUBLE, 0, world);
456   MPI_Bcast(setfl->ra, nelements, MPI_DOUBLE, 0, world);
457   MPI_Bcast(setfl->ri, nelements, MPI_DOUBLE, 0, world);
458   MPI_Bcast(setfl->Ec, nelements, MPI_DOUBLE, 0, world);
459   MPI_Bcast(setfl->q0, nelements, MPI_DOUBLE, 0, world);
460 
461   MPI_Bcast(setfl->rcutphiA, npair, MPI_DOUBLE, 0, world);
462   MPI_Bcast(setfl->rcutphiR, npair, MPI_DOUBLE, 0, world);
463   MPI_Bcast(setfl->Eb, npair, MPI_DOUBLE, 0, world);
464   MPI_Bcast(setfl->r0, npair, MPI_DOUBLE, 0, world);
465   MPI_Bcast(setfl->alpha, npair, MPI_DOUBLE, 0, world);
466   MPI_Bcast(setfl->beta, npair, MPI_DOUBLE, 0, world);
467   MPI_Bcast(setfl->rcutq, npair, MPI_DOUBLE, 0, world);
468   MPI_Bcast(setfl->Asigma, npair, MPI_DOUBLE, 0, world);
469   MPI_Bcast(setfl->rq, npair, MPI_DOUBLE, 0, world);
470   MPI_Bcast(setfl->rcutsigma, npair, MPI_DOUBLE, 0, world);
471   MPI_Bcast(setfl->Ac, npair, MPI_DOUBLE, 0, world);
472   MPI_Bcast(setfl->zeta, npair, MPI_DOUBLE, 0, world);
473   MPI_Bcast(setfl->rs, npair, MPI_DOUBLE, 0, world);
474   MPI_Bcast(setfl->tp, npair, MPI_INT, 0, world);
475 
476   setfl->nr = 5000;
477   setfl->cut = 0.0;
478   for (int i = 0; i < npair; i++) {
479     if (setfl->cut < setfl->rcutphiA[i]) setfl->cut = setfl->rcutphiA[i];
480     if (setfl->cut < setfl->rcutphiR[i]) setfl->cut = setfl->rcutphiR[i];
481     if (setfl->cut < setfl->rcutq[i]) setfl->cut = setfl->rcutq[i];
482     if (setfl->cut < setfl->rcutsigma[i]) setfl->cut = setfl->rcutsigma[i];
483   }
484   setfl->dr = setfl->cut/(setfl->nr-1.0);
485 
486   memory->create(setfl->cuts,nelements,nelements,"pair:cuts");
487   for (int i = 0; i < nelements; i++) {
488     for (int j = 0; j < nelements; j++) {
489       if (i > j) {
490         setfl->cuts[i][j] = setfl->cuts[j][i];
491       } else {
492         int ij;
493         if (i == j) {
494           ij = i;
495         } else {
496           ij = nelements*(i+1) - (i+1)*(i+2)/2 + j;
497         }
498         setfl->cuts[i][j] = setfl->rcutphiA[ij];
499         if (setfl->cuts[i][j] < setfl->rcutphiR[ij])
500           setfl->cuts[i][j] = setfl->rcutphiR[ij];
501         if (setfl->cuts[i][j] < setfl->rcutq[ij])
502           setfl->cuts[i][j] = setfl->rcutq[ij];
503         if (setfl->cuts[i][j] < setfl->rcutsigma[ij])
504           setfl->cuts[i][j] = setfl->rcutsigma[ij];
505       }
506     }
507   }
508 
509   memory->create(setfl->Fij,nelements,nelements,setfl->nr+1,"pair:Fij");
510   memory->create(setfl->Gij,nelements,nelements,setfl->nr+1,"pair:Gij");
511   memory->create(setfl->phiij,nelements,nelements,setfl->nr+1,"pair:phiij");
512 
513   for (int i = 0; i < nelements; i++)
514     for (int j = 0; j < nelements; j++) {
515       for (int k = 0; k < setfl->nr; k++) {
516         if (i > j) {
517           setfl->phiij[i][j][k+1] = setfl->phiij[j][i][k+1];
518         } else {
519           double r = k*setfl->dr;
520           setfl->phiij[i][j][k+1] = funcphi(i,j,r);
521         }
522       }
523     }
524 
525   for (int i = 0; i < nelements; i++)
526     for (int j = 0; j < nelements; j++) {
527       for (int k = 0; k < setfl->nr; k++) {
528         double r = k*setfl->dr;
529         setfl->Fij[i][j][k+1] = funcsigma(i,j,r);
530       }
531     }
532 
533   for (int i = 0; i < nelements; i++)
534     for (int j = 0; j < nelements; j++) {
535       for (int k = 0; k < setfl->nr; k++) {
536         if (i > j) {
537           setfl->Gij[i][j][k+1] = setfl->Gij[j][i][k+1];
538         } else {
539           double r = k*setfl->dr;
540           setfl->Gij[i][j][k+1] = funccoul(i,j,r);
541         }
542       }
543     }
544 }
545 
546 /* ----------------------------------------------------------------------
547    deallocate data associated with setfl file
548 ------------------------------------------------------------------------- */
549 
deallocate_setfl()550 void PairEIM::deallocate_setfl()
551 {
552   if (!setfl) return;
553   delete [] setfl->ielement;
554   delete [] setfl->mass;
555   delete [] setfl->negativity;
556   delete [] setfl->ra;
557   delete [] setfl->ri;
558   delete [] setfl->Ec;
559   delete [] setfl->q0;
560   delete [] setfl->rcutphiA;
561   delete [] setfl->rcutphiR;
562   delete [] setfl->Eb;
563   delete [] setfl->r0;
564   delete [] setfl->alpha;
565   delete [] setfl->beta;
566   delete [] setfl->rcutq;
567   delete [] setfl->Asigma;
568   delete [] setfl->rq;
569   delete [] setfl->rcutsigma;
570   delete [] setfl->Ac;
571   delete [] setfl->zeta;
572   delete [] setfl->rs;
573   delete [] setfl->tp;
574   memory->destroy(setfl->cuts);
575   memory->destroy(setfl->Fij);
576   memory->destroy(setfl->Gij);
577   memory->destroy(setfl->phiij);
578   delete setfl;
579 }
580 
581 /* ----------------------------------------------------------------------
582    convert read-in potentials to standard array format
583    interpolate all file values to a single grid and cutoff
584 ------------------------------------------------------------------------- */
585 
file2array()586 void PairEIM::file2array()
587 {
588   int i,j,m,n;
589   int irow,icol;
590   int ntypes = atom->ntypes;
591 
592   delete [] negativity;
593   delete [] q0;
594   memory->destroy(cutforcesq);
595   negativity = new double[ntypes+1];
596   q0 = new double[ntypes+1];
597   memory->create(cutforcesq,ntypes+1,ntypes+1,"pair:cutforcesq");
598   for (i = 1; i <= ntypes; i++) {
599     if (map[i] == -1) {
600       negativity[i]=0.0;
601       q0[i]=0.0;
602     } else {
603       negativity[i]=setfl->negativity[map[i]];
604       q0[i]=setfl->q0[map[i]];
605     }
606   }
607 
608   for (i = 1; i <= ntypes; i++)
609     for (j = 1; j <= ntypes; j++) {
610       if (map[i] == -1 || map[j] == -1) {
611         cutforcesq[i][j] = setfl->cut;
612         cutforcesq[i][j] =  cutforcesq[i][j]*cutforcesq[i][j];
613       } else {
614         cutforcesq[i][j] = setfl->cuts[map[i]][map[j]];
615         cutforcesq[i][j] =  cutforcesq[i][j]*cutforcesq[i][j];
616       }
617     }
618 
619   nr = setfl->nr;
620   dr = setfl->dr;
621 
622   // ------------------------------------------------------------------
623   // setup Fij arrays
624   // ------------------------------------------------------------------
625 
626   nFij = nelements*nelements + 1;
627   memory->destroy(Fij);
628   memory->create(Fij,nFij,nr+1,"pair:Fij");
629 
630   // copy each element's Fij to global Fij
631 
632   n=0;
633   for (i = 0; i < nelements; i++)
634     for (j = 0; j < nelements; j++) {
635       for (m = 1; m <= nr; m++) Fij[n][m] = setfl->Fij[i][j][m];
636       n++;
637     }
638 
639   // add extra Fij of zeroes for non-EIM types to point to (pair hybrid)
640 
641   for (m = 1; m <= nr; m++) Fij[nFij-1][m] = 0.0;
642 
643   // type2Fij[i][j] = which Fij array (0 to nFij-1) each type pair maps to
644   // setfl of Fij arrays
645   // value = n = sum over rows of matrix until reach irow,icol
646   // if atom type doesn't point to element (non-EIM atom in pair hybrid)
647   // then map it to last Fij array of zeroes
648 
649   for (i = 1; i <= ntypes; i++) {
650     for (j = 1; j <= ntypes; j++) {
651       irow = map[i];
652       icol = map[j];
653       if (irow == -1 || icol == -1) {
654         type2Fij[i][j] = nFij-1;
655       } else {
656         n = 0;
657         for (m = 0; m < irow; m++) n += nelements;
658         n += icol;
659         type2Fij[i][j] = n;
660       }
661     }
662   }
663 
664   // ------------------------------------------------------------------
665   // setup Gij arrays
666   // ------------------------------------------------------------------
667 
668   nGij = nelements * (nelements+1) / 2 + 1;
669   memory->destroy(Gij);
670   memory->create(Gij,nGij,nr+1,"pair:Gij");
671 
672   // copy each element's Gij to global Gij, only for I >= J
673 
674   n=0;
675   for (i = 0; i < nelements; i++)
676     for (j = 0; j <= i; j++) {
677       for (m = 1; m <= nr; m++) Gij[n][m] = setfl->Gij[i][j][m];
678       n++;
679     }
680 
681   // add extra Gij of zeroes for non-EIM types to point to (pair hybrid)
682 
683   for (m = 1; m <= nr; m++) Gij[nGij-1][m] = 0.0;
684 
685   // type2Gij[i][j] = which Gij array (0 to nGij-1) each type pair maps to
686   // setfl of Gij arrays only fill lower triangular Nelement matrix
687   // value = n = sum over rows of lower-triangular matrix until reach irow,icol
688   // swap indices when irow < icol to stay lower triangular
689   // if atom type doesn't point to element (non-EIM atom in pair hybrid)
690   // then map it to last Gij array of zeroes
691 
692   for (i = 1; i <= ntypes; i++) {
693     for (j = 1; j <= ntypes; j++) {
694       irow = map[i];
695       icol = map[j];
696       if (irow == -1 || icol == -1) {
697         type2Gij[i][j] = nGij-1;
698       } else {
699         if (irow < icol) {
700           irow = map[j];
701           icol = map[i];
702         }
703         n = 0;
704         for (m = 0; m < irow; m++) n += m + 1;
705         n += icol;
706         type2Gij[i][j] = n;
707       }
708     }
709   }
710 
711   // ------------------------------------------------------------------
712   // setup phiij arrays
713   // ------------------------------------------------------------------
714 
715   nphiij = nelements * (nelements+1) / 2 + 1;
716   memory->destroy(phiij);
717   memory->create(phiij,nphiij,nr+1,"pair:phiij");
718 
719   // copy each element pair phiij to global phiij, only for I >= J
720 
721   n = 0;
722   for (i = 0; i < nelements; i++)
723     for (j = 0; j <= i; j++) {
724       for (m = 1; m <= nr; m++) phiij[n][m] = setfl->phiij[i][j][m];
725       n++;
726     }
727 
728   // add extra phiij of zeroes for non-EIM types to point to (pair hybrid)
729 
730   for (m = 1; m <= nr; m++) phiij[nphiij-1][m] = 0.0;
731 
732   // type2phiij[i][j] = which phiij array (0 to nphiij-1)
733   //                    each type pair maps to
734   // setfl of phiij arrays only fill lower triangular Nelement matrix
735   // value = n = sum over rows of lower-triangular matrix until reach irow,icol
736   // swap indices when irow < icol to stay lower triangular
737   // if atom type doesn't point to element (non-EIM atom in pair hybrid)
738   // then map it to last phiij array of zeroes
739 
740   for (i = 1; i <= ntypes; i++) {
741     for (j = 1; j <= ntypes; j++) {
742       irow = map[i];
743       icol = map[j];
744       if (irow == -1 || icol == -1) {
745         type2phiij[i][j] = nphiij-1;
746       } else {
747         if (irow < icol) {
748           irow = map[j];
749           icol = map[i];
750         }
751         n = 0;
752         for (m = 0; m < irow; m++) n += m + 1;
753         n += icol;
754         type2phiij[i][j] = n;
755       }
756     }
757   }
758 }
759 
760 /* ---------------------------------------------------------------------- */
761 
array2spline()762 void PairEIM::array2spline()
763 {
764   rdr = 1.0/dr;
765 
766   memory->destroy(Fij_spline);
767   memory->destroy(Gij_spline);
768   memory->destroy(phiij_spline);
769 
770   memory->create(Fij_spline,nFij,nr+1,7,"pair:Fij");
771   memory->create(Gij_spline,nGij,nr+1,7,"pair:Gij");
772   memory->create(phiij_spline,nphiij,nr+1,7,"pair:phiij");
773 
774   for (int i = 0; i < nFij; i++)
775     interpolate(nr,dr,Fij[i],Fij_spline[i],0.0);
776 
777   for (int i = 0; i < nGij; i++)
778     interpolate(nr,dr,Gij[i],Gij_spline[i],0.0);
779 
780   for (int i = 0; i < nphiij; i++)
781     interpolate(nr,dr,phiij[i],phiij_spline[i],0.0);
782 }
783 
784 /* ---------------------------------------------------------------------- */
785 
interpolate(int n,double delta,double * f,double ** spline,double)786 void PairEIM::interpolate(int n, double delta, double *f,
787                           double **spline, double /*origin*/)
788 {
789   for (int m = 1; m <= n; m++) spline[m][6] = f[m];
790 
791   spline[1][5] = spline[2][6] - spline[1][6];
792   spline[2][5] = 0.5 * (spline[3][6]-spline[1][6]);
793   spline[n-1][5] = 0.5 * (spline[n][6]-spline[n-2][6]);
794   spline[n][5] = 0.0;
795 
796   for (int m = 3; m <= n-2; m++)
797     spline[m][5] = ((spline[m-2][6]-spline[m+2][6]) +
798                     8.0*(spline[m+1][6]-spline[m-1][6])) / 12.0;
799 
800   for (int m = 1; m <= n-1; m++) {
801     spline[m][4] = 3.0*(spline[m+1][6]-spline[m][6]) -
802       2.0*spline[m][5] - spline[m+1][5];
803     spline[m][3] = spline[m][5] + spline[m+1][5] -
804       2.0*(spline[m+1][6]-spline[m][6]);
805   }
806 
807   spline[n][4] = 0.0;
808   spline[n][3] = 0.0;
809 
810   for (int m = 1; m <= n; m++) {
811     spline[m][2] = spline[m][5]/delta;
812     spline[m][1] = 2.0*spline[m][4]/delta;
813     spline[m][0] = 3.0*spline[m][3]/delta;
814   }
815 }
816 
817 /* ----------------------------------------------------------------------
818    cutoff function
819 ------------------------------------------------------------------------- */
820 
funccutoff(double rp,double rc,double r)821 double PairEIM::funccutoff(double rp, double rc, double r)
822 {
823   double rbig = setfl->rbig;
824   double rsmall = setfl->rsmall;
825 
826   double a = (rsmall-rbig)/(rc-rp)*(r-rp)+rbig;
827   a = erfc(a);
828   double b = erfc(rbig);
829   double c = erfc(rsmall);
830   return (a-c)/(b-c);
831 }
832 
833 /* ----------------------------------------------------------------------
834    pair interaction function phi
835 ------------------------------------------------------------------------- */
836 
funcphi(int i,int j,double r)837 double PairEIM::funcphi(int i, int j, double r)
838 {
839   int ij;
840   double value = 0.0;
841   if (i == j) ij = i;
842   else if (i < j) ij = nelements*(i+1) - (i+1)*(i+2)/2 + j;
843   else ij = nelements*(j+1) - (j+1)*(j+2)/2 + i;
844   if (r < 0.2) r = 0.2;
845   if (setfl->tp[ij] == 1) {
846     double a = setfl->Eb[ij]*setfl->alpha[ij] /
847       (setfl->beta[ij]-setfl->alpha[ij]);
848     double b = setfl->Eb[ij]*setfl->beta[ij] /
849       (setfl->beta[ij]-setfl->alpha[ij]);
850     if (r < setfl->rcutphiA[ij]) {
851       value -= a*exp(-setfl->beta[ij]*(r/setfl->r0[ij]-1.0))*
852         funccutoff(setfl->r0[ij],setfl->rcutphiA[ij],r);
853     }
854     if (r < setfl-> rcutphiR[ij]) {
855       value += b*exp(-setfl->alpha[ij]*(r/setfl->r0[ij]-1.0))*
856         funccutoff(setfl->r0[ij],setfl->rcutphiR[ij],r);
857     }
858   } else if (setfl->tp[ij] == 2) {
859     double a=setfl->Eb[ij]*setfl->alpha[ij]*pow(setfl->r0[ij],setfl->beta[ij])/
860       (setfl->beta[ij]-setfl->alpha[ij]);
861     double b=a*setfl->beta[ij]/setfl->alpha[ij]*
862       pow(setfl->r0[ij],setfl->alpha[ij]-setfl->beta[ij]);
863     if (r < setfl->rcutphiA[ij]) {
864       value -= a/pow(r,setfl->beta[ij])*
865         funccutoff(setfl->r0[ij],setfl->rcutphiA[ij],r);
866     }
867     if (r < setfl-> rcutphiR[ij]) {
868       value += b/pow(r,setfl->alpha[ij])*
869         funccutoff(setfl->r0[ij],setfl->rcutphiR[ij],r);
870     }
871   }
872   return value;
873 }
874 
875 /* ----------------------------------------------------------------------
876    ion propensity function sigma
877 ------------------------------------------------------------------------- */
878 
funcsigma(int i,int j,double r)879 double PairEIM::funcsigma(int i, int j, double r)
880 {
881   int ij;
882   double value = 0.0;
883   if (i == j) ij = i;
884   else if (i < j) ij = nelements*(i+1) - (i+1)*(i+2)/2 + j;
885   else ij = nelements*(j+1) - (j+1)*(j+2)/2 + i;
886   if (r < 0.2) r = 0.2;
887   if (r < setfl->rcutq[ij]) {
888     value = setfl->Asigma[ij]*(setfl->negativity[j]-setfl->negativity[i]) *
889       funccutoff(setfl->rq[ij],setfl->rcutq[ij],r);
890   }
891   return value;
892 }
893 
894 /* ----------------------------------------------------------------------
895    charge-charge interaction function sigma
896 ------------------------------------------------------------------------- */
897 
funccoul(int i,int j,double r)898 double PairEIM::funccoul(int i, int j, double r)
899 {
900   int ij;
901   double value = 0.0;
902   if (i == j) ij = i;
903   else if (i < j) ij = nelements*(i+1) - (i+1)*(i+2)/2 + j;
904   else ij = nelements*(j+1) - (j+1)*(j+2)/2 + i;
905   if (r < 0.2) r = 0.2;
906   if (r < setfl->rcutsigma[ij]) {
907     value = setfl->Ac[ij]*exp(-setfl->zeta[ij]*r)*
908       funccutoff(setfl->rs[ij],setfl->rcutsigma[ij],r);
909   }
910   return value;
911 }
912 
913 /* ---------------------------------------------------------------------- */
914 
pack_forward_comm(int n,int * list,double * buf,int,int *)915 int PairEIM::pack_forward_comm(int n, int *list, double *buf,
916                                int /*pbc_flag*/, int * /*pbc*/)
917 {
918   int i,j,m;
919 
920   m = 0;
921   if (rhofp == 1) {
922     for (i = 0; i < n; i++) {
923       j = list[i];
924       buf[m++] = rho[j];
925     }
926   }
927   if (rhofp == 2) {
928     for (i = 0; i < n; i++) {
929       j = list[i];
930       buf[m++] = fp[j];
931     }
932   }
933   return m;
934 }
935 
936 /* ---------------------------------------------------------------------- */
937 
unpack_forward_comm(int n,int first,double * buf)938 void PairEIM::unpack_forward_comm(int n, int first, double *buf)
939 {
940   int i,m,last;
941 
942   m = 0;
943   last = first + n;
944   if (rhofp == 1) {
945     for (i = first; i < last; i++) rho[i] = buf[m++];
946   }
947   if (rhofp == 2) {
948     for (i = first; i < last; i++) fp[i] = buf[m++];
949   }
950 }
951 
952 /* ---------------------------------------------------------------------- */
953 
pack_reverse_comm(int n,int first,double * buf)954 int PairEIM::pack_reverse_comm(int n, int first, double *buf)
955 {
956   int i,m,last;
957 
958   m = 0;
959   last = first + n;
960   if (rhofp == 1) {
961     for (i = first; i < last; i++) buf[m++] = rho[i];
962   }
963   if (rhofp == 2) {
964     for (i = first; i < last; i++) buf[m++] = fp[i];
965   }
966   return m;
967 }
968 
969 /* ---------------------------------------------------------------------- */
970 
unpack_reverse_comm(int n,int * list,double * buf)971 void PairEIM::unpack_reverse_comm(int n, int *list, double *buf)
972 {
973   int i,j,m;
974 
975   m = 0;
976   if (rhofp == 1) {
977     for (i = 0; i < n; i++) {
978       j = list[i];
979       rho[j] += buf[m++];
980     }
981   }
982   if (rhofp == 2) {
983     for (i = 0; i < n; i++) {
984       j = list[i];
985       fp[j] += buf[m++];
986     }
987   }
988 }
989 
990 /* ----------------------------------------------------------------------
991    memory usage of local atom-based arrays
992 ------------------------------------------------------------------------- */
993 
memory_usage()994 double PairEIM::memory_usage()
995 {
996   double bytes = (double)maxeatom * sizeof(double);
997   bytes += (double)maxvatom*6 * sizeof(double);
998   bytes += (double)2 * nmax * sizeof(double);
999   return bytes;
1000 }
1001 
EIMPotentialFileReader(LAMMPS * lmp,const std::string & filename,const int auto_convert)1002 EIMPotentialFileReader::EIMPotentialFileReader(LAMMPS *lmp,
1003                                                const std::string &filename,
1004                                                const int auto_convert) :
1005   Pointers(lmp), filename(filename)
1006 {
1007   if (comm->me != 0) {
1008     error->one(FLERR, "EIMPotentialFileReader should only be called by proc 0!");
1009   }
1010 
1011   int unit_convert = auto_convert;
1012   FILE *fp = utils::open_potential(filename, lmp, &unit_convert);
1013   conversion_factor = utils::get_conversion_factor(utils::ENERGY,unit_convert);
1014 
1015   if (fp == nullptr) {
1016     error->one(FLERR,"cannot open eim potential file {}", filename);
1017   }
1018 
1019   parse(fp);
1020 
1021   fclose(fp);
1022 }
1023 
get_pair(const std::string & a,const std::string & b)1024 std::pair<std::string, std::string> EIMPotentialFileReader::get_pair(const std::string &a, const std::string &b) {
1025   if (a < b) {
1026     return std::make_pair(a, b);
1027   }
1028   return std::make_pair(b, a);
1029 }
1030 
next_line(FILE * fp)1031 char *EIMPotentialFileReader::next_line(FILE * fp) {
1032   // concatenate lines if they end with '&'
1033   // strip comments after '#'
1034   int n = 0;
1035   int nwords = 0;
1036   bool concat = false;
1037 
1038   char *ptr = fgets(line, MAXLINE, fp);
1039 
1040   if (ptr == nullptr) {
1041     // EOF
1042     return nullptr;
1043   }
1044 
1045   // strip comment
1046   if ((ptr = strchr(line, '#'))) *ptr = '\0';
1047 
1048   // strip ampersand
1049   if ((ptr = strrchr(line, '&'))) {
1050     concat = true;
1051     *ptr = '\0';
1052   }
1053 
1054   nwords = utils::count_words(line);
1055 
1056   if (nwords > 0) {
1057     n = strlen(line);
1058   }
1059 
1060   while (n == 0 || concat) {
1061     ptr = fgets(&line[n], MAXLINE - n, fp);
1062 
1063     if (ptr == nullptr) {
1064       // EOF
1065       return line;
1066     }
1067 
1068     // strip comment
1069     if ((ptr = strchr(line, '#'))) *ptr = '\0';
1070 
1071     // strip ampersand
1072     if ((ptr = strrchr(line, '&'))) {
1073       concat = true;
1074       *ptr = '\0';
1075     } else {
1076       concat = false;
1077     }
1078 
1079     nwords += utils::count_words(&line[n]);
1080 
1081     // skip line if blank
1082     if (nwords > 0) {
1083       n = strlen(line);
1084     }
1085   }
1086 
1087   return line;
1088 }
1089 
parse(FILE * fp)1090 void EIMPotentialFileReader::parse(FILE * fp)
1091 {
1092   char *line = nullptr;
1093   bool found_global = false;
1094 
1095   while ((line = next_line(fp))) {
1096     ValueTokenizer values(line);
1097     std::string type = values.next_string();
1098 
1099     if (type == "global:") {
1100       if (values.count() != 4) {
1101         error->one(FLERR, "Invalid global line in EIM potential file");
1102       }
1103 
1104       division = values.next_double();
1105       rbig     = values.next_double();
1106       rsmall   = values.next_double();
1107 
1108       found_global = true;
1109     } else if (type == "element:") {
1110       if (values.count() != 9) {
1111         error->one(FLERR, "Invalid element line in EIM potential file");
1112       }
1113 
1114       std::string name = values.next_string();
1115 
1116       ElementData data;
1117       data.ielement   = values.next_int();
1118       data.mass       = values.next_double();
1119       data.negativity = values.next_double();
1120       data.ra         = values.next_double();
1121       data.ri         = values.next_double();
1122       data.Ec         = values.next_double();
1123       data.q0         = values.next_double();
1124 
1125       if (elements.find(name) == elements.end()) {
1126         elements[name] = data;
1127       } else {
1128         error->one(FLERR, "Duplicate pair line in EIM potential file");
1129       }
1130 
1131     } else if (type == "pair:") {
1132       if (values.count() != 17) {
1133         error->one(FLERR, "Invalid element line in EIM potential file");
1134       }
1135 
1136       std::string elementA = values.next_string();
1137       std::string elementB = values.next_string();
1138 
1139       PairData data;
1140       data.rcutphiA  = values.next_double();
1141       data.rcutphiR  = values.next_double();
1142       data.Eb        = values.next_double() * conversion_factor;
1143       data.r0        = values.next_double();
1144       data.alpha     = values.next_double();
1145       data.beta      = values.next_double();
1146       data.rcutq     = values.next_double();
1147       data.Asigma    = values.next_double();
1148       data.rq        = values.next_double();
1149       data.rcutsigma = values.next_double();
1150       data.Ac        = values.next_double() * conversion_factor;
1151       data.zeta      = values.next_double();
1152       data.rs        = values.next_double();
1153 
1154       // should be next_int, but since existing potential files have 1.0000e+00 format
1155       // we're doing this instead to keep compatibility
1156       data.tp       = (int)values.next_double();
1157 
1158       auto p = get_pair(elementA, elementB);
1159 
1160       if (pairs.find(p) == pairs.end()) {
1161         pairs[p] = data;
1162       } else {
1163         error->one(FLERR, "Duplicate pair line in EIM potential file");
1164       }
1165     }
1166   }
1167 
1168   if (!found_global) {
1169     error->one(FLERR, "Missing global line in EIM potential file");
1170   }
1171 }
1172 
get_global(PairEIM::Setfl * setfl)1173 void EIMPotentialFileReader::get_global(PairEIM::Setfl *setfl) {
1174   setfl->division  = division;
1175   setfl->rbig      = rbig;
1176   setfl->rsmall    = rsmall;
1177 }
1178 
get_element(PairEIM::Setfl * setfl,int i,const std::string & name)1179 void EIMPotentialFileReader::get_element(PairEIM::Setfl *setfl, int i,
1180                                          const std::string &name) {
1181   if (elements.find(name) == elements.end())
1182     error->one(FLERR,"Element " + name + " not defined in EIM potential file");
1183 
1184   ElementData &data = elements[name];
1185   setfl->ielement[i] = data.ielement;
1186   setfl->mass[i] = data.mass;
1187   setfl->negativity[i] = data.negativity;
1188   setfl->ra[i] = data.ra;
1189   setfl->ri[i] = data.ri;
1190   setfl->Ec[i] = data.Ec;
1191   setfl->q0[i] = data.q0;
1192 }
1193 
get_pair(PairEIM::Setfl * setfl,int ij,const std::string & elemA,const std::string & elemB)1194 void EIMPotentialFileReader::get_pair(PairEIM::Setfl *setfl, int ij,
1195                                       const std::string &elemA,
1196                                       const std::string &elemB) {
1197   auto p = get_pair(elemA, elemB);
1198 
1199   if (pairs.find(p) == pairs.end())
1200     error->one(FLERR,"Element pair (" + elemA + ", " + elemB
1201                + ") is not defined in EIM potential file");
1202 
1203   PairData &data = pairs[p];
1204   setfl->rcutphiA[ij] = data.rcutphiA;
1205   setfl->rcutphiR[ij] = data.rcutphiR;
1206   setfl->Eb[ij] = data.Eb;
1207   setfl->r0[ij] = data.r0;
1208   setfl->alpha[ij] = data.alpha;
1209   setfl->beta[ij] = data.beta;
1210   setfl->rcutq[ij] = data.rcutq;
1211   setfl->Asigma[ij] = data.Asigma;
1212   setfl->rq[ij] = data.rq;
1213   setfl->rcutsigma[ij] = data.rcutsigma;
1214   setfl->Ac[ij] = data.Ac;
1215   setfl->zeta[ij] = data.zeta;
1216   setfl->rs[ij] = data.rs;
1217   setfl->tp[ij] = data.tp;
1218 }
1219