1 // clang-format off
2 /* -*- c++ -*- ----------------------------------------------------------
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    Contributing author: Maxim Shugaev (UVA), mvs9t@virginia.edu
14 ------------------------------------------------------------------------- */
15 
16 #include "pair_mesont_tpm.h"
17 #include "export_mesont.h"
18 
19 
20 #include "atom.h"
21 #include "comm.h"
22 #include "force.h"
23 #include "memory.h"
24 #include "error.h"
25 #include "neighbor.h"
26 #include "neigh_list.h"
27 #include "neigh_request.h"
28 
29 #include <cstring>
30 #include <cmath>
31 #include <array>
32 
33 #include <fstream>
34 #include <algorithm>
35 
36 using namespace LAMMPS_NS;
37 
38 class MESONTList {
39 public:
40   MESONTList(const Atom* atom, const NeighList* nblist);
~MESONTList()41   ~MESONTList() {};
42   //list of segments
43   const std::vector<std::array<int,2>>& get_segments() const;
44   //list of triplets
45   const std::vector<std::array<int,3>>& get_triplets() const;
46   //list of neighbor chains [start,end] for segments
47   //(use idx() to get real indexes)
48   const std::vector<std::vector<std::array<int,2>>>& get_nbs() const;
49   //convert idx from sorted representation to real idx
50   int get_idx(int idx) const;
51   //return list of indexes for conversion from sorted representation
52   const std::vector<int>& get_idx_list() const;
53   //convert idx from real idx to sorted representation
54   int get_idxb(int idx) const;
55   //return list of indexes for conversion to sorted representation
56   const std::vector<int>& get_idxb_list() const;
57   //check if the node is the end of the tube
58   bool is_end(int idx) const;
59 
60   std::array<int,2> get_segment(int idx) const;
61   std::array<int,3> get_triplet(int idx) const;
62 
63   static const int cnt_end = -1;
64   static const int domain_end = -2;
65   static const int not_cnt = -3;
66 private:
67   std::vector<std::array<int,2>> chain_list, segments;
68   std::vector<std::array<int,3>> triplets;
69   std::vector<std::vector<std::array<int,2>>> nb_chains;
70   std::vector<int> index_list, index_list_b;
71 };
72 
73 //=============================================================================
74 
75 inline const std::vector<std::vector<std::array<int,2>>> &
get_nbs() const76  MESONTList::get_nbs() const {
77   return nb_chains;
78 }
79 
get_idx(int idx) const80 inline int MESONTList::get_idx(int idx) const {
81   return index_list[idx];
82 }
83 
get_idx_list() const84 inline const std::vector<int>& MESONTList::get_idx_list() const {
85   return index_list;
86 };
87 
88 
get_idxb(int idx) const89 inline int MESONTList::get_idxb(int idx) const {
90   return index_list_b[idx];
91 }
92 
get_idxb_list() const93 inline const std::vector<int>& MESONTList::get_idxb_list() const {
94   return index_list_b;
95 };
96 
get_segments() const97 inline const std::vector<std::array<int,2>> & MESONTList::get_segments()
98  const {
99   return segments;
100 }
101 
get_triplets() const102 inline const std::vector<std::array<int,3>> & MESONTList::get_triplets()
103  const {
104   return triplets;
105 }
106 
get_segment(int idx) const107 inline std::array<int,2> MESONTList::get_segment(int idx) const {
108   std::array<int,2> result;
109   result[0] = chain_list[idx][0];
110   result[1] = idx;
111   return result;
112 }
113 
get_triplet(int idx) const114 inline std::array<int,3> MESONTList::get_triplet(int idx) const {
115   std::array<int,3> result;
116   result[0] = chain_list[idx][0];
117   result[1] = idx;
118   result[2] = chain_list[idx][1];
119   return result;
120 }
121 
is_end(int idx) const122 inline bool MESONTList::is_end(int idx) const {
123   return chain_list[idx][0] == cnt_end || chain_list[idx][1] == cnt_end;
124 };
125 
126 template<typename T>
vector_union(std::vector<T> & v1,std::vector<T> & v2,std::vector<T> & merged)127 void vector_union(std::vector<T>& v1, std::vector<T>& v2,
128  std::vector<T>& merged) {
129   std::sort(v1.begin(), v1.end());
130   std::sort(v2.begin(), v2.end());
131   merged.reserve(v1.size() + v2.size());
132   typename std::vector<T>::iterator it1 = v1.begin();
133   typename std::vector<T>::iterator it2 = v2.begin();
134 
135   while (it1 != v1.end() && it2 != v2.end()) {
136     if (*it1 < *it2) {
137       if (merged.empty() || merged.back() < *it1) merged.push_back(*it1);
138         ++it1;
139     }
140     else {
141       if (merged.empty() || merged.back() < *it2) merged.push_back(*it2);
142       ++it2;
143     }
144   }
145   while (it1 != v1.end()) {
146     if (merged.empty() || merged.back() < *it1) merged.push_back(*it1);
147     ++it1;
148   }
149 
150   while (it2 != v2.end()) {
151   if (merged.empty() || merged.back() < *it2) merged.push_back(*it2);
152     ++it2;
153   }
154 }
155 
MESONTList(const Atom * atom,const NeighList * nblist)156 MESONTList::MESONTList(const Atom* atom, const NeighList* nblist) {
157   if (atom == nullptr || nblist == nullptr) return;
158   //number of local atoms at the node
159   int nlocal = atom->nlocal;
160   //total number of atoms in the node and ghost shell treated as NTs
161   int nall = nblist->inum + nblist->gnum;
162   //total number of atoms in the node and ghost shell
163   int ntot = atom->nlocal + atom->nghost;
164   tagint* const g_id = atom->tag;
165   tagint** const bonds = atom->bond_nt;
166   tagint* const chain_id = atom->molecule;
167   int* ilist = nblist->ilist;
168 
169   //convert bonds to local id representation
170   chain_list.resize(ntot, {not_cnt,not_cnt});
171   for (int ii = 0; ii < nall; ii++) {
172     int i = ilist[ii];
173     chain_list[i][0] = domain_end;
174     chain_list[i][1] = domain_end;
175   }
176   for (int ii = 0; ii < nall; ii++) {
177     int i = ilist[ii];
178     int nnb = nblist->numneigh[i];
179     for (int m = 0; m < 2; m++)
180       if (bonds[i][m] == cnt_end) chain_list[i][m] = cnt_end;
181     for (int j = 0; j < nnb; j++) {
182       int nb = nblist->firstneigh[i][j];
183       if (bonds[i][0] == g_id[nb]) {
184         chain_list[i][0] = nb;
185         chain_list[nb][1] = i;
186         break;
187       }
188     }
189   }
190 
191   //reorder chains: index list
192   //list of indexes for conversion FROM reordered representation
193   index_list.reserve(nall);
194   index_list_b.resize(ntot, -1); // convert index TO reordered representation
195   for (int i = 0; i < ntot; i++) {
196     if (chain_list[i][0] == cnt_end || chain_list[i][0] == domain_end) {
197       index_list.push_back(i);
198       index_list_b[i] = index_list.size() - 1;
199       int idx = i;
200       while (1) {
201         idx = chain_list[idx][1];
202         if (idx == cnt_end || idx == domain_end) break;
203         else index_list.push_back(idx);
204         index_list_b[idx] = index_list.size() - 1;
205       }
206     }
207   }
208 
209   //segment list
210   for (int i = 0; i < nlocal; i++) {
211     if (chain_list[i][0] == not_cnt) continue;
212     if (chain_list[i][0] != cnt_end && chain_list[i][0] != domain_end &&
213      g_id[i] < g_id[chain_list[i][0]])
214       segments.push_back({i,chain_list[i][0]});
215     if (chain_list[i][1] != cnt_end && chain_list[i][1] != domain_end &&
216      g_id[i] < g_id[chain_list[i][1]])
217       segments.push_back({i,chain_list[i][1]});
218   }
219   int nbonds = segments.size();
220 
221   //triplets
222   for (int i = 0; i < nlocal; i++) {
223     if (chain_list[i][0] == not_cnt) continue;
224     if (chain_list[i][0] != cnt_end && chain_list[i][0] != domain_end &&
225      chain_list[i][1] != cnt_end && chain_list[i][1] != domain_end)
226       triplets.push_back(get_triplet(i));
227   }
228 
229   //segment neighbor list
230   nb_chains.resize(nbonds);
231   std::vector<int> nb_list_i[2], nb_list;
232   for (int i = 0; i < nbonds; i++) {
233     //union of nb lists
234     for (int m = 0; m < 2; m++) {
235       nb_list_i[m].resize(0);
236       int idx = segments[i][m];
237       if (idx >= nlocal) continue;
238       int nnb = nblist->numneigh[idx];
239       for (int j = 0; j < nnb; j++) {
240         int jdx = nblist->firstneigh[idx][j];
241         //no self interactions for nbs within the same tube
242         if (chain_id[jdx] == chain_id[idx] &&
243          std::abs(index_list_b[idx] - index_list_b[jdx]) <= 5) continue;
244         nb_list_i[m].push_back(index_list_b[jdx]);
245       }
246     }
247     vector_union(nb_list_i[0], nb_list_i[1], nb_list);
248 
249     int nnb = nb_list.size();
250     if (nnb > 0) {
251       int idx_s = nb_list[0];
252       for (int j = 0; j < nnb; j++) {
253         //if nodes are not continuous in the sorted representation
254         //or represent chain ends, create a new neighbor chain
255         int idx_next = chain_list[index_list[nb_list[j]]][1];
256         if ((j == nnb - 1) || (nb_list[j] + 1 != nb_list[j+1]) ||
257          (idx_next == cnt_end) || (idx_next == domain_end)) {
258           std::array<int,2> chain;
259           chain[0] = idx_s;
260           chain[1] = nb_list[j];
261           //make sure that segments having at least one node
262           //in the neighbor list are included
263           int idx0 = index_list[chain[0]]; // real id of the ends
264           int idx1 = index_list[chain[1]];
265           if (chain_list[idx0][0] != cnt_end &&
266            chain_list[idx0][0] != domain_end) chain[0] -= 1;
267           if (chain_list[idx1][1] != cnt_end &&
268            chain_list[idx1][1] != domain_end) chain[1] += 1;
269           if (chain[0] != chain[1]) nb_chains[i].push_back(chain);
270           idx_s = (j == nnb - 1) ? -1 : nb_list[j + 1];
271         }
272       }
273     }
274     nb_list.resize(0);
275   }
276 }
277 
278 /* ---------------------------------------------------------------------- */
279 
280 // the cutoff distance between walls of tubes
281 static const double TPBRcutoff  = 3.0*3.4;
282 int PairMESONTTPM::instance_count = 0;
283 /* ---------------------------------------------------------------------- */
284 
PairMESONTTPM(LAMMPS * lmp)285 PairMESONTTPM::PairMESONTTPM(LAMMPS *lmp) : Pair(lmp) {
286   writedata=1;
287   BendingMode = 0;  // Harmonic bending model
288   TPMType = 0;      // Inter-tube segment-segment interaction
289   tab_path = nullptr;
290   tab_path_length = 0;
291 
292   eatom_s = nullptr;
293   eatom_b = nullptr;
294   eatom_t = nullptr;
295   nmax = 0;
296   instance_count++;
297   if (instance_count > 1) error->all(FLERR,
298    "only a single instance of mesont/tpm pair style can be created");
299 }
300 
301 /* ---------------------------------------------------------------------- */
302 
~PairMESONTTPM()303 PairMESONTTPM::~PairMESONTTPM()
304 {
305   if (allocated) {
306     memory->destroy(setflag);
307     memory->destroy(cutsq);
308     memory->destroy(cut);
309 
310     memory->destroy(eatom_s);
311     memory->destroy(eatom_b);
312     memory->destroy(eatom_t);
313   }
314   instance_count--;
315   if (tab_path != nullptr) memory->destroy(tab_path);
316 }
317 
318 /* ---------------------------------------------------------------------- */
319 
compute(int eflag,int vflag)320 void PairMESONTTPM::compute(int eflag, int vflag) {
321   // set per atom values and accumulators
322   // reallocate per-atom arrays if necessary
323   ev_init(eflag,vflag);
324   if (atom->nmax > nmax && eflag_atom) {
325     memory->destroy(eatom_s);
326     memory->create(eatom_s,comm->nthreads*maxeatom,"pair:eatom_s");
327     memory->destroy(eatom_b);
328     memory->create(eatom_b,comm->nthreads*maxeatom,"pair:eatom_b");
329     memory->destroy(eatom_t);
330     memory->create(eatom_t,comm->nthreads*maxeatom,"pair:eatom_t");
331     nmax = atom->nmax;
332   }
333   //total number of atoms in the node and ghost shell treated as NTs
334   int nall = list->inum + list->gnum;
335   //total number of atoms in the node and ghost shell
336   int ntot = atom->nlocal + atom->nghost;
337   int newton_pair = force->newton_pair;
338   if (!newton_pair)
339    error->all(FLERR,"Pair style mesont/tpm requires newton pair on");
340 
341   double **x = atom->x;
342   double **f = atom->f;
343   double *r = atom->radius;
344   double *l = atom->length;
345   int *buckling = atom->buckling;
346   tagint *g_id = atom->tag;
347 
348   //check if cutoff is chosen correctly
349   double RT = mesont_lib_get_R();
350   double Lmax = 0.0;
351   for (int ii = 0; ii < list->inum; ii++) {
352     int i = list->ilist[ii];
353     if (Lmax < l[i]) Lmax = l[i];
354   }
355   double Rcut_min = std::max(2.0*Lmax, std::sqrt(0.5*Lmax*Lmax + std::pow((2.0*RT + TPBRcutoff),2)));
356   if (cut_global < Rcut_min) {
357     error->all(FLERR, "The selected cutoff is too small for the current system : "
358                "L_max = {:.8}, R_max = {:.8}, Rc = {:.8}, Rcut_min = {:.8}",
359                Lmax, RT, cut_global, Rcut_min);
360   }
361 
362   //generate bonds and chain nblist
363   MESONTList ntlist(atom, list);
364 
365   //reorder data to make it contiguous within tubes
366   //and compatible with Fortran functions
367   std::vector<double> x_sort(3*nall), f_sort(3*nall), s_sort(9*nall);
368   std::vector<double> u_ts_sort(nall), u_tb_sort(nall), u_tt_sort(nall);
369   std::vector<int> b_sort(nall);
370   for (int i = 0; i < nall; i++) {
371     int idx = ntlist.get_idx(i);
372     for (int j = 0; j < 3; j++) x_sort[3*i+j] = x[idx][j];
373     b_sort[i] = buckling[idx];
374   }
375 
376   //bending potential
377   int n_triplets = ntlist.get_triplets().size();
378   for (int i = 0; i < n_triplets; i++) {
379     const std::array<int,3>& t = ntlist.get_triplets()[i];
380     //idx of nodes of a triplet in sorted representation
381     int idx_s0 = ntlist.get_idxb(t[0]);
382     int idx_s1 = ntlist.get_idxb(t[1]);
383     int idx_s2 = ntlist.get_idxb(t[2]);
384 
385     double* X1 = &(x_sort[3*idx_s0]);
386     double* X2 = &(x_sort[3*idx_s1]);
387     double* X3 = &(x_sort[3*idx_s2]);
388     double& U1b = u_tb_sort[idx_s0];
389     double& U2b = u_tb_sort[idx_s1];
390     double& U3b = u_tb_sort[idx_s2];
391     double* F1 = &(f_sort[3*idx_s0]);
392     double* F2 = &(f_sort[3*idx_s1]);
393     double* F3 = &(f_sort[3*idx_s2]);
394     double* S1 = &(s_sort[9*idx_s0]);
395     double* S2 = &(s_sort[9*idx_s1]);
396     double* S3 = &(s_sort[9*idx_s2]);
397     double& R123 = r[t[1]];
398     double& L123 = l[t[1]];
399     int& BBF2 = b_sort[idx_s1];
400 
401     mesont_lib_TubeBendingForceField(U1b, U2b, U3b, F1, F2, F3, S1, S2, S3,
402      X1, X2, X3, R123, L123, BBF2);
403   }
404 
405   //share new values of buckling
406   if (BendingMode == 1) {
407     for (int i = 0; i < nall; i++) {
408       int idx = ntlist.get_idx(i);
409       buckling[idx] = b_sort[i];
410     }
411     comm->forward_comm_pair(this);
412     for (int i = 0; i < nall; i++) {
413       int idx = ntlist.get_idx(i);
414       b_sort[i] = buckling[idx];
415     }
416   }
417 
418   //segment-segment and segment-tube interactions
419   int n_segments = ntlist.get_segments().size();
420   double Rmax = 0.0;
421   Lmax = 0.0;
422   for (int i = 0; i < n_segments; i++) {
423     const std::array<int,2>& s = ntlist.get_segments()[i];
424     //idx of a segment end 1 in sorted representation
425     int idx_s0 = ntlist.get_idxb(s[0]);
426     //idx of a segment end 2 in sorted representation
427     int idx_s1 = ntlist.get_idxb(s[1]);
428     double* X1 = &(x_sort[3*idx_s0]);
429     double* X2 = &(x_sort[3*idx_s1]);
430     double length = std::sqrt(std::pow(X1[0]-X2[0],2) +
431      std::pow(X1[1]-X2[1],2) + std::pow(X1[2]-X2[2],2));
432     if (length > Lmax) Lmax = length;
433     double& U1t = u_tt_sort[idx_s0];
434     double& U2t = u_tt_sort[idx_s1];
435     double& U1s = u_ts_sort[idx_s0];
436     double& U2s = u_ts_sort[idx_s1];
437     double* F1 = &(f_sort[3*idx_s0]);
438     double* F2 = &(f_sort[3*idx_s1]);
439     double* S1 = &(s_sort[9*idx_s0]);
440     double* S2 = &(s_sort[9*idx_s1]);
441     double R12 = r[s[0]]; if (R12 > Rmax) Rmax = R12;
442     if (std::abs(R12 - RT) > 1e-3)
443         error->all(FLERR,"Inconsistent input and potential table");
444     //assume that the length of the segment is defined by the node with
445     //smallest global id
446     double L12 = (g_id[s[0]] > g_id[s[1]]) ? l[s[1]] : l[s[0]];
447     mesont_lib_TubeStretchingForceField(U1s, U2s, F1, F2, S1, S2, X1, X2,
448      R12, L12);
449 
450     for (int nc = 0; nc < (int)ntlist.get_nbs()[i].size(); nc++) {
451       //id of the beginning and end of the chain in the sorted representation
452       const std::array<int,2>& chain = ntlist.get_nbs()[i][nc];
453       int N = chain[1] - chain[0] + 1;  //number of elements in the chain
454       int end1 = ntlist.get_idx(chain[0]);  //chain ends (real representation)
455       int end2 = ntlist.get_idx(chain[1]);
456       double* X = &(x_sort[3*chain[0]]);
457       double* Ut = &(u_tt_sort[chain[0]]);
458       double* F = &(f_sort[3*chain[0]]);
459       double* S = &(s_sort[9*chain[0]]);
460       double R = r[end1];
461       int* BBF = &(b_sort[chain[0]]);
462       int E1 = ntlist.is_end(end1);
463       int E2 = ntlist.is_end(end2);
464 
465       int Ee = 0;
466       double* Xe = X; double* Fe = F; double* Se = S;
467       if (!E1 && ntlist.get_triplet(end1)[0] != MESONTList::domain_end &&
468        ntlist.get_triplet(ntlist.get_triplet(end1)[0])[0] ==
469        MESONTList::cnt_end) {
470         Ee = 1;
471         int idx = ntlist.get_idxb(ntlist.get_triplet(end1)[0]);
472         Xe = &(x_sort[3*idx]);
473         Fe = &(f_sort[3*idx]);
474         Se = &(s_sort[9*idx]);
475       }
476       else if (!E2 && ntlist.get_triplet(end2)[2] != MESONTList::domain_end &&
477        ntlist.get_triplet(ntlist.get_triplet(end2)[2])[2] ==
478        MESONTList::cnt_end) {
479         Ee = 2;
480         int idx = ntlist.get_idxb(ntlist.get_triplet(end2)[2]);
481         Xe = &(x_sort[3*idx]);
482         Fe = &(f_sort[3*idx]);
483         Se = &(s_sort[9*idx]);
484       }
485 
486       mesont_lib_SegmentTubeForceField(U1t, U2t, Ut, F1, F2, F, Fe, S1, S2, S,
487        Se, X1, X2, R12, N, X, Xe, BBF, R, E1, E2, Ee, TPMType);
488     }
489   }
490 
491   //check if cutoff is chosen correctly
492   Rcut_min = std::max(2.0*Lmax, std::sqrt(0.5*Lmax*Lmax + std::pow((2.0*Rmax + TPBRcutoff),2)));
493   if (cut_global < Rcut_min) {
494     error->all(FLERR, "The selected cutoff is too small for the current system : "
495                "L_max = {:.8}, R_max = {:.8}, Rc = {:.8}, Rcut_min = {:.8}",
496                Lmax, RT, cut_global, Rcut_min);
497   }
498 
499   //convert from sorted representation
500   for (int i = 0; i < nall; i++) {
501       int idx = ntlist.get_idx(i);
502       for (int j = 0; j < 3; j++) f[idx][j] += f_sort[3*i+j];
503       buckling[idx] = b_sort[i];
504   }
505   if (eflag_global) {
506     energy_s = energy_b = energy_t = 0.0;
507     for (int i = 0; i < nall; i++) {
508       energy_s += u_ts_sort[i];
509       energy_b += u_tb_sort[i];
510       energy_t += u_tt_sort[i];
511     }
512     eng_vdwl += energy_s + energy_b + energy_t;
513   }
514   if (eflag_atom) {
515     for (int i = 0; i < ntot; i++)
516       eatom_s[i] = eatom_b[i] = eatom_t[i] = 0.0;
517 
518     for (int i = 0; i < nall; i++) {
519       int idx = ntlist.get_idx(i);
520       eatom_s[idx] += u_ts_sort[i];
521       eatom_b[idx] += u_tb_sort[i];
522       eatom_t[idx] += u_tt_sort[i];
523       eatom[idx] += u_ts_sort[i] + u_tb_sort[i] + u_tt_sort[i];
524     }
525   }
526   if (vflag_global) {
527     for (int i = 0; i < nall; i++) {
528       virial[0] += s_sort[9*i+0]; //xx
529       virial[1] += s_sort[9*i+4]; //yy
530       virial[2] += s_sort[9*i+8]; //zz
531       virial[3] += s_sort[9*i+1]; //xy
532       virial[4] += s_sort[9*i+2]; //xz
533       virial[5] += s_sort[9*i+5]; //yz
534     }
535   }
536   if (vflag_atom) {
537     for (int i = 0; i < nall; i++) {
538       int idx = ntlist.get_idx(i);
539       vatom[idx][0] += s_sort[9*i+0]; //xx
540       vatom[idx][1] += s_sort[9*i+4]; //yy
541       vatom[idx][2] += s_sort[9*i+8]; //zz
542       vatom[idx][3] += s_sort[9*i+1]; //xy
543       vatom[idx][4] += s_sort[9*i+2]; //xz
544       vatom[idx][5] += s_sort[9*i+5]; //yz
545     }
546   }
547 
548 }
549 
550 /* ----------------------------------------------------------------------
551    allocate all arrays
552 ------------------------------------------------------------------------- */
553 
allocate()554 void PairMESONTTPM::allocate() {
555   allocated = 1;
556   int n = atom->ntypes;
557 
558   memory->create(setflag,n+1,n+1,"pair:setflag");
559   for (int i = 1; i <= n; i++)
560     for (int j = i; j <= n; j++)
561       setflag[i][j] = 0;
562 
563   memory->create(cutsq,n+1,n+1,"pair:cutsq");
564   memory->create(cut,n+1,n+1,"pair:cut");
565 }
566 
567 /* ----------------------------------------------------------------------
568    global settings
569 ------------------------------------------------------------------------- */
570 
settings(int narg,char ** arg)571 void PairMESONTTPM::settings(int narg, char **arg) {
572   if ((narg == 0) || (narg > 4))
573     error->all(FLERR,"Illegal pair_style command");
574   cut_global = utils::numeric(FLERR,arg[0],false,lmp);
575 
576   // reset cutoffs that have been explicitly set
577   if (allocated) {
578     int i,j;
579     for (i = 1; i <= atom->ntypes; i++)
580       for (j = i+1; j <= atom->ntypes; j++)
581         cut[i][j] = cut_global;
582   }
583   std::string TPMAFile = (narg > 1) ? arg[1] : "MESONT-TABTP.xrs";
584   tab_path_length = TPMAFile.length();
585   if (tab_path != nullptr) memory->destroy(tab_path);
586   //c_str returns '\0' terminated string
587   memory->create(tab_path,tab_path_length+1,"pair:path");
588   std::memcpy(tab_path, TPMAFile.c_str(), tab_path_length+1);
589   mesont_lib_SetTablePath(tab_path, tab_path_length);
590 
591   if (narg > 2) {
592     BendingMode = utils::numeric(FLERR,arg[2],false,lmp);
593     if ((BendingMode < 0) || (BendingMode > 1))
594       error->all(FLERR,"Incorrect BendingMode");
595   }
596   if (narg > 3) {
597     TPMType = utils::numeric(FLERR,arg[3],false,lmp);
598     if ((TPMType < 0) || (TPMType > 1))
599       error->all(FLERR,"Incorrect TPMType");
600   }
601 
602   mesont_lib_TPBInit();
603   int M, N;
604   std::ifstream in(TPMAFile);
605   if (!in.is_open()) error->all(FLERR,"Incorrect table path");
606   std::string tmp;
607   std::getline(in,tmp);
608   std::getline(in,tmp);
609   std::getline(in,tmp);
610   in >> M >> N;
611   in.close();
612   mesont_lib_TPMInit(M, N);
613   mesont_lib_InitCNTPotModule(1, 3, 0, BendingMode, mesont_lib_get_R());
614 }
615 
616 /* ----------------------------------------------------------------------
617    set coeffs for one or more type pairs
618 ------------------------------------------------------------------------- */
619 
coeff(int narg,char ** arg)620 void PairMESONTTPM::coeff(int narg, char **arg) {
621   if ((narg < 2) || (narg > 3))
622     error->all(FLERR,"Incorrect args for pair coefficients");
623 
624   if (!allocated) allocate();
625 
626   int ilo,ihi,jlo,jhi;
627   utils::bounds(FLERR,arg[0],1,atom->ntypes,ilo,ihi,error);
628   utils::bounds(FLERR,arg[1],1,atom->ntypes,jlo,jhi,error);
629 
630   double cut_one = cut_global;
631   if (narg == 3) cut_one = utils::numeric(FLERR,arg[2],false,lmp);
632 
633   int count = 0;
634   for (int i = ilo; i <= ihi; i++) {
635     for (int j = MAX(jlo,i); j <= jhi; j++) {
636       cut[i][j] = cut_one;
637       setflag[i][j] = 1;
638       count++;
639     }
640   }
641 
642   if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
643 }
644 
645 /* ----------------------------------------------------------------------
646    init for one type pair i,j and corresponding j,i
647 ------------------------------------------------------------------------- */
648 
init_one(int i,int j)649 double PairMESONTTPM::init_one(int i, int j) {
650   if (setflag[i][j] == 0) {
651     cut[i][j] = mix_distance(cut[i][i],cut[j][j]);
652   }
653 
654   return cut[i][j];
655 }
656 
657 /* ----------------------------------------------------------------------
658    proc 0 writes to restart file
659 ------------------------------------------------------------------------- */
660 
write_restart(FILE * fp)661 void PairMESONTTPM::write_restart(FILE *fp) {
662   write_restart_settings(fp);
663 
664   int i,j;
665   for (i = 1; i <= atom->ntypes; i++)
666     for (j = i; j <= atom->ntypes; j++) {
667       fwrite(&setflag[i][j],sizeof(int),1,fp);
668       if (setflag[i][j]) {
669         fwrite(&cut[i][j],sizeof(double),1,fp);
670       }
671     }
672 }
673 
674 /* ----------------------------------------------------------------------
675    proc 0 reads from restart file, bcasts
676 ------------------------------------------------------------------------- */
677 
read_restart(FILE * fp)678 void PairMESONTTPM::read_restart(FILE *fp) {
679   read_restart_settings(fp);
680   allocate();
681 
682   int i,j;
683   int me = comm->me;
684   for (i = 1; i <= atom->ntypes; i++)
685     for (j = i; j <= atom->ntypes; j++) {
686       if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp);
687       MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world);
688       if (setflag[i][j]) {
689         if (me == 0) {
690           fread(&cut[i][j],sizeof(double),1,fp);
691         }
692         MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world);
693       }
694     }
695 }
696 
697 /* ----------------------------------------------------------------------
698    proc 0 writes to restart file
699 ------------------------------------------------------------------------- */
700 
write_restart_settings(FILE * fp)701 void PairMESONTTPM::write_restart_settings(FILE *fp) {
702   fwrite(&BendingMode,sizeof(int),1,fp);
703   fwrite(&TPMType,sizeof(int),1,fp);
704   fwrite(&cut_global,sizeof(double),1,fp);
705   fwrite(&tab_path_length,sizeof(int),1,fp);
706   fwrite(tab_path,tab_path_length+1,1,fp);
707 }
708 
709 /* ----------------------------------------------------------------------
710    proc 0 reads from restart file, bcasts
711 ------------------------------------------------------------------------- */
712 
read_restart_settings(FILE * fp)713 void PairMESONTTPM::read_restart_settings(FILE *fp) {
714   int me = comm->me;
715   if (me == 0) {
716     fread(&BendingMode,sizeof(int),1,fp);
717     fread(&TPMType,sizeof(int),1,fp);
718     fread(&cut_global,sizeof(double),1,fp);
719     fread(&tab_path_length,sizeof(int),1,fp);
720   }
721   MPI_Bcast(&BendingMode,1,MPI_INT,0,world);
722   MPI_Bcast(&TPMType,1,MPI_INT,0,world);
723   MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world);
724   MPI_Bcast(&tab_path_length,1,MPI_INT,0,world);
725 
726   if (tab_path != nullptr) memory->destroy(tab_path);
727   memory->create(tab_path,tab_path_length+1,"pair:path");
728   if (me == 0) fread(tab_path,tab_path_length+1,1,fp);
729   MPI_Bcast(tab_path,tab_path_length+1,MPI_CHAR,0,world);
730   mesont_lib_SetTablePath(tab_path,tab_path_length);
731   mesont_lib_TPBInit();
732   int M, N;
733   std::ifstream in(tab_path);
734   if (!in.is_open()) error->all(FLERR,"Incorrect table path");
735   std::string tmp;
736   std::getline(in,tmp);
737   std::getline(in,tmp);
738   std::getline(in,tmp);
739   in >> M >> N;
740   in.close();
741   mesont_lib_TPMInit(M, N);
742   mesont_lib_InitCNTPotModule(1, 3, 0, BendingMode, mesont_lib_get_R());
743 }
744 
745 /* ----------------------------------------------------------------------
746    proc 0 writes to data file
747 ------------------------------------------------------------------------- */
748 
write_data(FILE * fp)749 void PairMESONTTPM::write_data(FILE *fp) {
750   for (int i = 1; i <= atom->ntypes; i++)
751     fprintf(fp,"%d\n",i);
752 }
753 
754 /* ----------------------------------------------------------------------
755    proc 0 writes all pairs to data file
756 ------------------------------------------------------------------------- */
757 
write_data_all(FILE * fp)758 void PairMESONTTPM::write_data_all(FILE *fp) {
759   for (int i = 1; i <= atom->ntypes; i++)
760     for (int j = i; j <= atom->ntypes; j++)
761       fprintf(fp,"%d %d %g\n",i,j,cut[i][j]);
762 }
763 
764 /* ---------------------------------------------------------------------- */
765 
init_style()766 void PairMESONTTPM::init_style() {
767   //make sure that a full list is created (including ghost nodes)
768   int r = neighbor->request(this,instance_me);
769   neighbor->requests[r]->half = false;
770   neighbor->requests[r]->full = true;
771   neighbor->requests[r]->ghost = true;
772 }
773 
extract(const char * str,int &)774 void* PairMESONTTPM::extract(const char *str, int &) {
775   if (strcmp(str,"mesonttpm_Es_tot") == 0) return &energy_s;
776   else if (strcmp(str,"mesonttpm_Eb_tot") == 0) return &energy_b;
777   else if (strcmp(str,"mesonttpm_Et_tot") == 0) return &energy_t;
778   else if (strcmp(str,"mesonttpm_Es") == 0) return eatom_s;
779   else if (strcmp(str,"mesonttpm_Eb") == 0) return eatom_b;
780   else if (strcmp(str,"mesonttpm_Et") == 0) return eatom_t;
781   else return nullptr;
782 };
783