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