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