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:
17       Morteza Jalalvand (IASBS)  jalalvand.m AT gmail.com
18 ------------------------------------------------------------------------- */
19 
20 #include "fix_meso_move.h"
21 
22 #include "atom.h"
23 #include "comm.h"
24 #include "domain.h"
25 #include "error.h"
26 #include "force.h"
27 #include "input.h"
28 #include "lattice.h"
29 #include "math_const.h"
30 #include "memory.h"
31 #include "modify.h"
32 #include "update.h"
33 #include "variable.h"
34 
35 #include <cmath>
36 #include <cstring>
37 
38 using namespace LAMMPS_NS;
39 using namespace FixConst;
40 using namespace MathConst;
41 
42 enum{LINEAR,WIGGLE,ROTATE,VARIABLE};
43 enum{EQUAL,ATOM};
44 
45 /* ---------------------------------------------------------------------- */
46 
FixMesoMove(LAMMPS * lmp,int narg,char ** arg)47 FixMesoMove::FixMesoMove (LAMMPS *lmp, int narg, char **arg) :
48   Fix(lmp, narg, arg),
49   xvarstr(nullptr), yvarstr(nullptr), zvarstr(nullptr),
50   vxvarstr(nullptr), vyvarstr(nullptr), vzvarstr(nullptr),
51   xoriginal(nullptr), displace(nullptr), velocity(nullptr) {
52   if ((atom->esph_flag != 1) || (atom->rho_flag != 1))
53     error->all(FLERR,
54         "fix meso/move command requires atom_style with both energy and density");
55 
56   if (narg < 4) error->all(FLERR,"Illegal fix meso/move command");
57 
58   restart_global = 1;
59   restart_peratom = 1;
60   peratom_flag = 1;
61   size_peratom_cols = 3;
62   peratom_freq = 1;
63   time_integrate = 1;
64   create_attribute = 1;
65   displaceflag = 0;
66   velocityflag = 0;
67   maxatom = 0;
68 
69   // parse args
70 
71   int iarg = narg;
72 
73   if (strcmp(arg[3],"linear") == 0) {
74     if (narg < 7) error->all(FLERR,"Illegal fix meso/move command");
75     iarg = 7;
76     mstyle = LINEAR;
77     if (strcmp(arg[4],"NULL") == 0) vxflag = 0;
78     else {
79       vxflag = 1;
80       vx = utils::numeric(FLERR,arg[4],false,lmp);
81     }
82     if (strcmp(arg[5],"NULL") == 0) vyflag = 0;
83     else {
84       vyflag = 1;
85       vy = utils::numeric(FLERR,arg[5],false,lmp);
86     }
87     if (strcmp(arg[6],"NULL") == 0) vzflag = 0;
88     else {
89       vzflag = 1;
90       vz = utils::numeric(FLERR,arg[6],false,lmp);
91     }
92 
93   } else if (strcmp(arg[3],"wiggle") == 0) {
94     if (narg < 8) error->all(FLERR,"Illegal fix meso/move command");
95     iarg = 8;
96     mstyle = WIGGLE;
97     if (strcmp(arg[4],"NULL") == 0) axflag = 0;
98     else {
99       axflag = 1;
100       ax = utils::numeric(FLERR,arg[4],false,lmp);
101     }
102     if (strcmp(arg[5],"NULL") == 0) ayflag = 0;
103     else {
104       ayflag = 1;
105       ay = utils::numeric(FLERR,arg[5],false,lmp);
106     }
107     if (strcmp(arg[6],"NULL") == 0) azflag = 0;
108     else {
109       azflag = 1;
110       az = utils::numeric(FLERR,arg[6],false,lmp);
111     }
112     period = utils::numeric(FLERR,arg[7],false,lmp);
113     if (period <= 0.0) error->all(FLERR,"Illegal fix meso/move command");
114 
115   } else if (strcmp(arg[3],"rotate") == 0) {
116     if (narg < 11) error->all(FLERR,"Illegal fix meso/move command");
117     iarg = 11;
118     mstyle = ROTATE;
119     point[0] = utils::numeric(FLERR,arg[4],false,lmp);
120     point[1] = utils::numeric(FLERR,arg[5],false,lmp);
121     point[2] = utils::numeric(FLERR,arg[6],false,lmp);
122     axis[0] = utils::numeric(FLERR,arg[7],false,lmp);
123     axis[1] = utils::numeric(FLERR,arg[8],false,lmp);
124     axis[2] = utils::numeric(FLERR,arg[9],false,lmp);
125     period = utils::numeric(FLERR,arg[10],false,lmp);
126     if (period <= 0.0) error->all(FLERR,"Illegal fix meso/move command");
127 
128   } else if (strcmp(arg[3],"variable") == 0) {
129     if (narg < 10) error->all(FLERR,"Illegal fix meso/move command");
130     iarg = 10;
131     mstyle = VARIABLE;
132     if (strcmp(arg[4],"NULL") == 0) xvarstr = nullptr;
133     else if (utils::strmatch(arg[4],"^v_")) {
134       xvarstr = utils::strdup(arg[4]+2);
135     } else error->all(FLERR,"Illegal fix meso/move command");
136     if (strcmp(arg[5],"NULL") == 0) yvarstr = nullptr;
137     else if (utils::strmatch(arg[5],"^v_")) {
138       yvarstr = utils::strdup(arg[5]+2);
139     } else error->all(FLERR,"Illegal fix meso/move command");
140     if (strcmp(arg[6],"NULL") == 0) zvarstr = nullptr;
141     else if (utils::strmatch(arg[6],"^v_")) {
142       zvarstr = utils::strdup(arg[6]+2);
143     } else error->all(FLERR,"Illegal fix meso/move command");
144     if (strcmp(arg[7],"NULL") == 0) vxvarstr = nullptr;
145     else if (utils::strmatch(arg[7],"^v_")) {
146       vxvarstr = utils::strdup(arg[7]+2);
147     } else error->all(FLERR,"Illegal fix meso/move command");
148     if (strcmp(arg[8],"NULL") == 0) vyvarstr = nullptr;
149     else if (utils::strmatch(arg[8],"^v_")) {
150       vyvarstr = utils::strdup(arg[8]+2);
151     } else error->all(FLERR,"Illegal fix meso/move command");
152     if (strcmp(arg[9],"NULL") == 0) vzvarstr = nullptr;
153     else if (utils::strmatch(arg[9],"^v_")) {
154       vzvarstr = utils::strdup(arg[9]+2);
155     } else error->all(FLERR,"Illegal fix meso/move command");
156 
157   } else error->all(FLERR,"Illegal fix meso/move command");
158 
159   // optional args
160 
161   int scaleflag = 1;
162 
163   while (iarg < narg) {
164     if (strcmp(arg[iarg],"units") == 0) {
165       if (iarg+2 > narg) error->all(FLERR,"Illegal fix meso/move command");
166       if (strcmp(arg[iarg+1],"box") == 0) scaleflag = 0;
167       else if (strcmp(arg[iarg+1],"lattice") == 0) scaleflag = 1;
168       else error->all(FLERR,"Illegal fix meso/move command");
169       iarg += 2;
170     } else error->all(FLERR,"Illegal fix meso/move command");
171   }
172 
173   // error checks and warnings
174 
175   if (domain->dimension == 2) {
176     if (mstyle == LINEAR && vzflag && vz != 0.0)
177       error->all(FLERR,"Fix meso/move cannot set linear z motion for 2d problem");
178     if (mstyle == WIGGLE && azflag && az != 0.0)
179       error->all(FLERR,"Fix meso/move cannot set wiggle z motion for 2d problem");
180     if (mstyle == ROTATE && (axis[0] != 0.0 || axis[1] != 0.0))
181       error->all(FLERR, "Fix meso/move cannot rotate aroung non z-axis for 2d problem");
182     if (mstyle == VARIABLE && (zvarstr || vzvarstr))
183       error->all(FLERR, "Fix meso/move cannot define z or vz variable for 2d problem");
184   }
185 
186   // setup scaling and apply scaling factors to velocity & amplitude
187 
188   if ((mstyle == LINEAR || mstyle == WIGGLE || mstyle == ROTATE) &&
189       scaleflag) {
190     double xscale = domain->lattice->xlattice;
191     double yscale = domain->lattice->ylattice;
192     double zscale = domain->lattice->zlattice;
193 
194     if (mstyle == LINEAR) {
195       if (vxflag) vx *= xscale;
196       if (vyflag) vy *= yscale;
197       if (vzflag) vz *= zscale;
198     } else if (mstyle == WIGGLE) {
199       if (axflag) ax *= xscale;
200       if (ayflag) ay *= yscale;
201       if (azflag) az *= zscale;
202     } else if (mstyle == ROTATE) {
203       point[0] *= xscale;
204       point[1] *= yscale;
205       point[2] *= zscale;
206     }
207   }
208 
209   // set omega_rotate from period
210 
211   if (mstyle == WIGGLE || mstyle == ROTATE) omega_rotate = MY_2PI / period;
212 
213   // runit = unit vector along rotation axis
214 
215   if (mstyle == ROTATE) {
216     double len = sqrt(axis[0]*axis[0] + axis[1]*axis[1] + axis[2]*axis[2]);
217     if (len == 0.0)
218       error->all(FLERR,"Zero length rotation vector with fix meso/move");
219     runit[0] = axis[0]/len;
220     runit[1] = axis[1]/len;
221     runit[2] = axis[2]/len;
222   }
223 
224   // perform initial allocation of atom-based array
225   // register with Atom class
226 
227   FixMesoMove::grow_arrays(atom->nmax);
228   atom->add_callback(Atom::GROW);
229   atom->add_callback(Atom::RESTART);
230 
231   displace = velocity = nullptr;
232 
233   // xoriginal = initial unwrapped positions of atoms
234 
235   double **x = atom->x;
236   imageint *image = atom->image;
237   int *mask = atom->mask;
238   int nlocal = atom->nlocal;
239 
240   for (int i = 0; i < nlocal; i++) {
241     if (mask[i] & groupbit) domain->unmap(x[i],image[i],xoriginal[i]);
242     else xoriginal[i][0] = xoriginal[i][1] = xoriginal[i][2] = 0.0;
243   }
244 
245   time_origin = update->ntimestep;
246 }
247 
248 /* ---------------------------------------------------------------------- */
249 
~FixMesoMove()250 FixMesoMove::~FixMesoMove () {
251   // unregister callbacks to this fix from Atom class
252 
253   atom->delete_callback(id,Atom::GROW);
254   atom->delete_callback(id,Atom::RESTART);
255 
256   // delete locally stored arrays
257 
258   memory->destroy(xoriginal);
259   memory->destroy(displace);
260   memory->destroy(velocity);
261 
262   delete [] xvarstr;
263   delete [] yvarstr;
264   delete [] zvarstr;
265   delete [] vxvarstr;
266   delete [] vyvarstr;
267   delete [] vzvarstr;
268 }
269 
270 /* ---------------------------------------------------------------------- */
271 
setmask()272 int FixMesoMove::setmask () {
273   int mask = 0;
274   mask |= INITIAL_INTEGRATE;
275   mask |= FINAL_INTEGRATE;
276   mask |= PRE_FORCE;
277   return mask;
278 }
279 
280 /* ---------------------------------------------------------------------- */
281 
init()282 void FixMesoMove::init () {
283   dt = update->dt;
284   dtv = update->dt;
285   dtf = 0.5 * update->dt * force->ftm2v;
286 
287   // set indices and style of all variables
288 
289   displaceflag = velocityflag = 0;
290 
291   if (mstyle == VARIABLE) {
292     if (xvarstr) {
293       xvar = input->variable->find(xvarstr);
294       if (xvar < 0) error->all(FLERR, "Variable name for fix meso/move does not exist");
295       if (input->variable->equalstyle(xvar)) xvarstyle = EQUAL;
296       else if (input->variable->atomstyle(xvar)) xvarstyle = ATOM;
297       else error->all(FLERR,"Variable for fix meso/move is invalid style");
298     }
299     if (yvarstr) {
300       yvar = input->variable->find(yvarstr);
301       if (yvar < 0) error->all(FLERR, "Variable name for fix meso/move does not exist");
302       if (input->variable->equalstyle(yvar)) yvarstyle = EQUAL;
303       else if (input->variable->atomstyle(yvar)) yvarstyle = ATOM;
304       else error->all(FLERR,"Variable for fix meso/move is invalid style");
305     }
306     if (zvarstr) {
307       zvar = input->variable->find(zvarstr);
308       if (zvar < 0) error->all(FLERR, "Variable name for fix meso/move does not exist");
309       if (input->variable->equalstyle(zvar)) zvarstyle = EQUAL;
310       else if (input->variable->atomstyle(zvar)) zvarstyle = ATOM;
311       else error->all(FLERR,"Variable for fix meso/move is invalid style");
312     }
313     if (vxvarstr) {
314       vxvar = input->variable->find(vxvarstr);
315       if (vxvar < 0) error->all(FLERR, "Variable name for fix meso/move does not exist");
316       if (input->variable->equalstyle(vxvar)) vxvarstyle = EQUAL;
317       else if (input->variable->atomstyle(vxvar)) vxvarstyle = ATOM;
318       else error->all(FLERR,"Variable for fix meso/move is invalid style");
319     }
320     if (vyvarstr) {
321       vyvar = input->variable->find(vyvarstr);
322       if (vyvar < 0) error->all(FLERR, "Variable name for fix meso/move does not exist");
323       if (input->variable->equalstyle(vyvar)) vyvarstyle = EQUAL;
324       else if (input->variable->atomstyle(vyvar)) vyvarstyle = ATOM;
325       else error->all(FLERR,"Variable for fix meso/move is invalid style");
326     }
327     if (vzvarstr) {
328       vzvar = input->variable->find(vzvarstr);
329       if (vzvar < 0) error->all(FLERR, "Variable name for fix meso/move does not exist");
330       if (input->variable->equalstyle(vzvar)) vzvarstyle = EQUAL;
331       else if (input->variable->atomstyle(vzvar)) vzvarstyle = ATOM;
332       else error->all(FLERR,"Variable for fix meso/move is invalid style");
333     }
334 
335     if (xvarstr && xvarstyle == ATOM) displaceflag = 1;
336     if (yvarstr && yvarstyle == ATOM) displaceflag = 1;
337     if (zvarstr && zvarstyle == ATOM) displaceflag = 1;
338     if (vxvarstr && vxvarstyle == ATOM) velocityflag = 1;
339     if (vyvarstr && vyvarstyle == ATOM) velocityflag = 1;
340     if (vzvarstr && vzvarstyle == ATOM) velocityflag = 1;
341   }
342 
343   maxatom = atom->nmax;
344   memory->destroy(displace);
345   memory->destroy(velocity);
346   if (displaceflag) memory->create(displace,maxatom,3,"move:displace");
347   else displace = nullptr;
348   if (velocityflag) memory->create(velocity,maxatom,3,"move:velocity");
349   else velocity = nullptr;
350 }
351 
setup_pre_force(int)352 void FixMesoMove::setup_pre_force (int /*vflag*/) {
353   // set vest equal to v
354   double **v = atom->v;
355   double **vest = atom->vest;
356   int *mask = atom->mask;
357   int nlocal = atom->nlocal;
358   if (igroup == atom->firstgroup)
359     nlocal = atom->nfirst;
360 
361   for (int i = 0; i < nlocal; i++) {
362     if (mask[i] & groupbit) {
363       vest[i][0] = v[i][0];
364       vest[i][1] = v[i][1];
365       vest[i][2] = v[i][2];
366     }
367   }
368 }
369 
370 /* ----------------------------------------------------------------------
371    set x,v of particles
372 ------------------------------------------------------------------------- */
373 
initial_integrate(int)374 void FixMesoMove::initial_integrate (int /*vflag*/) {
375   double ddotr,dx,dy,dz;
376   double dtfm;
377   double xold[3],a[3],b[3],c[3],d[3],disp[3],disp_next[3];
378 
379   double delta = (update->ntimestep - time_origin) * dt;
380   double delta_next = (update->ntimestep - time_origin + 1) * dt;
381 
382   double **x = atom->x;
383   double **v = atom->v;
384   double **vest = atom->vest;
385   double *rho = atom->rho;
386   double *drho = atom->drho;
387   double *esph = atom->esph;
388   double *desph = atom->desph;
389   double **f = atom->f;
390   double *rmass = atom->rmass;
391   double *mass = atom->mass;
392   int *type = atom->type;
393   int *mask = atom->mask;
394   int nlocal = atom->nlocal;
395   int rmass_flag = atom->rmass_flag;
396 
397   if (igroup == atom->firstgroup)
398     nlocal = atom->nfirst;
399 
400   // for linear: X = X0 + V*dt
401 
402   if (mstyle == LINEAR) {
403     for (int i = 0; i < nlocal; i++) {
404       if (mask[i] & groupbit) {
405         xold[0] = x[i][0];
406         xold[1] = x[i][1];
407         xold[2] = x[i][2];
408 
409         esph[i] += dtf * desph[i]; // half-step update of particle internal energy
410         rho[i] += dtf * drho[i]; // ... and density
411 
412         if (vxflag) {
413           vest[i][0] = v[i][0] = vx;
414           x[i][0] = xoriginal[i][0] + vx*delta;
415         } else {
416           dtfm = rmass_flag ? dtf / rmass[i] : dtf / mass[type[i]];
417           vest[i][0] = v[i][0] + 2.0 * dtfm * f[i][0];
418           v[i][0] += dtfm * f[i][0];
419           x[i][0] += dtv * v[i][0];
420         }
421 
422         if (vyflag) {
423           vest[i][1] = v[i][1] = vy;
424           x[i][1] = xoriginal[i][1] + vy*delta;
425         } else {
426           dtfm = rmass_flag ? dtf / rmass[i] : dtf / mass[type[i]];
427           vest[i][1] = v[i][1] + 2.0 * dtfm * f[i][1];
428           v[i][1] += dtfm * f[i][1];
429           x[i][1] += dtv * v[i][1];
430         }
431 
432         if (vzflag) {
433           vest[i][2] = v[i][2] = vz;
434           x[i][2] = xoriginal[i][2] + vz*delta;
435         } else {
436           dtfm = rmass_flag ? dtf / rmass[i] : dtf / mass[type[i]];
437           vest[i][2] = v[i][2] + 2.0 * dtfm * f[i][2];
438           v[i][2] += dtfm * f[i][2];
439           x[i][2] += dtv * v[i][2];
440         }
441 
442         domain->remap_near(x[i],xold);
443       }
444     }
445 
446   // for wiggle: X = X0 + A sin(w*dt)
447 
448   } else if (mstyle == WIGGLE) {
449     double arg = omega_rotate * delta;
450     double arg_next = omega_rotate * delta_next;
451     double sine = sin(arg);
452     double cosine = cos(arg);
453     double cosine_next = cos(arg_next);
454 
455     for (int i = 0; i < nlocal; i++) {
456       if (mask[i] & groupbit) {
457         xold[0] = x[i][0];
458         xold[1] = x[i][1];
459         xold[2] = x[i][2];
460 
461         esph[i] += dtf * desph[i]; // half-step update of particle internal energy
462         rho[i] += dtf * drho[i]; // ... and density
463 
464         if (axflag) {
465           v[i][0] = ax*omega_rotate*cosine;
466           vest[i][0] = ax*omega_rotate*cosine_next;
467           x[i][0] = xoriginal[i][0] + ax*sine;
468         } else {
469           dtfm = rmass_flag ? dtf / rmass[i] : dtf / mass[type[i]];
470           vest[i][0] = v[i][0] + 2.0 * dtfm * f[i][0];
471           v[i][0] += dtfm * f[i][0];
472           x[i][0] += dtv * v[i][0];
473         }
474 
475         if (ayflag) {
476           v[i][1] = ay*omega_rotate*cosine;
477           vest[i][1] = ay*omega_rotate*cosine_next;
478           x[i][1] = xoriginal[i][1] + ay*sine;
479         } else {
480           dtfm = rmass_flag ? dtf / rmass[i] : dtf / mass[type[i]];
481           vest[i][1] = v[i][1] + 2.0 * dtfm * f[i][1];
482           v[i][1] += dtfm * f[i][1];
483           x[i][1] += dtv * v[i][1];
484         }
485 
486         if (azflag) {
487           v[i][2] = az*omega_rotate*cosine;
488           vest[i][2] = az*omega_rotate*cosine_next;
489           x[i][2] = xoriginal[i][2] + az*sine;
490         } else {
491           dtfm = rmass_flag ? dtf / rmass[i] : dtf / mass[type[i]];
492           vest[i][2] = v[i][2] + 2.0 * dtfm * f[i][2];
493           v[i][2] += dtfm * f[i][2];
494           x[i][2] += dtv * v[i][2];
495         }
496 
497         domain->remap_near(x[i],xold);
498       }
499     }
500 
501   // for rotate by right-hand rule around omega:
502   // P = point = vector = point of rotation
503   // R = vector = axis of rotation
504   // w = omega of rotation (from period)
505   // X0 = xoriginal = initial coord of atom
506   // R0 = runit = unit vector for R
507   // D = X0 - P = vector from P to X0
508   // C = (D dot R0) R0 = projection of atom coord onto R line
509   // A = D - C = vector from R line to X0
510   // B = R0 cross A = vector perp to A in plane of rotation
511   // A,B define plane of circular rotation around R line
512   // X = P + C + A cos(w*dt) + B sin(w*dt)
513   // V = w R0 cross (A cos(w*dt) + B sin(w*dt))
514 
515   } else if (mstyle == ROTATE) {
516     double arg = omega_rotate * delta;
517     double arg_next = omega_rotate * delta_next;
518     double sine = sin(arg);
519     double cosine = cos(arg);
520     double sine_next = sin(arg_next);
521     double cosine_next = cos(arg_next);
522 
523     for (int i = 0; i < nlocal; i++) {
524       if (mask[i] & groupbit) {
525         xold[0] = x[i][0];
526         xold[1] = x[i][1];
527         xold[2] = x[i][2];
528 
529         esph[i] += dtf * desph[i]; // half-step update of particle internal energy
530         rho[i] += dtf * drho[i]; // ... and density
531 
532         d[0] = xoriginal[i][0] - point[0];
533         d[1] = xoriginal[i][1] - point[1];
534         d[2] = xoriginal[i][2] - point[2];
535         ddotr = d[0]*runit[0] + d[1]*runit[1] + d[2]*runit[2];
536         c[0] = ddotr*runit[0];
537         c[1] = ddotr*runit[1];
538         c[2] = ddotr*runit[2];
539         a[0] = d[0] - c[0];
540         a[1] = d[1] - c[1];
541         a[2] = d[2] - c[2];
542         b[0] = runit[1]*a[2] - runit[2]*a[1];
543         b[1] = runit[2]*a[0] - runit[0]*a[2];
544         b[2] = runit[0]*a[1] - runit[1]*a[0];
545         disp[0] = a[0]*cosine  + b[0]*sine;
546         disp[1] = a[1]*cosine  + b[1]*sine;
547         disp[2] = a[2]*cosine  + b[2]*sine;
548         disp_next[0] = a[0]*cosine_next  + b[0]*sine_next;
549         disp_next[1] = a[1]*cosine_next  + b[1]*sine_next;
550         disp_next[2] = a[2]*cosine_next  + b[2]*sine_next;
551 
552         x[i][0] = point[0] + c[0] + disp[0];
553         x[i][1] = point[1] + c[1] + disp[1];
554         x[i][2] = point[2] + c[2] + disp[2];
555         v[i][0] = omega_rotate * (runit[1]*disp[2] - runit[2]*disp[1]);
556         v[i][1] = omega_rotate * (runit[2]*disp[0] - runit[0]*disp[2]);
557         v[i][2] = omega_rotate * (runit[0]*disp[1] - runit[1]*disp[0]);
558         vest[i][0] = omega_rotate * (runit[1]*disp_next[2] - runit[2]*disp_next[1]);
559         vest[i][1] = omega_rotate * (runit[2]*disp_next[0] - runit[0]*disp_next[2]);
560         vest[i][2] = omega_rotate * (runit[0]*disp_next[1] - runit[1]*disp_next[0]);
561 
562         domain->remap_near(x[i],xold);
563       }
564     }
565 
566   // for variable: compute x,v from variables
567 
568   } else if (mstyle == VARIABLE) {
569 
570     // reallocate displace and velocity arrays as necessary
571 
572     if ((displaceflag || velocityflag) && atom->nmax > maxatom) {
573       maxatom = atom->nmax;
574       if (displaceflag) {
575         memory->destroy(displace);
576         memory->create(displace,maxatom,3,"move:displace");
577       }
578       if (velocityflag) {
579         memory->destroy(velocity);
580         memory->create(velocity,maxatom,3,"move:velocity");
581       }
582     }
583 
584     // pre-compute variable values, wrap with clear/add
585 
586     modify->clearstep_compute();
587 
588     if (xvarstr) {
589       if (xvarstyle == EQUAL) dx = input->variable->compute_equal(xvar);
590       else input->variable->compute_atom(xvar,igroup,&displace[0][0],3,0);
591     }
592     if (yvarstr) {
593       if (yvarstyle == EQUAL) dy = input->variable->compute_equal(yvar);
594       else input->variable->compute_atom(yvar,igroup,&displace[0][1],3,0);
595     }
596     if (zvarstr) {
597       if (zvarstyle == EQUAL) dz = input->variable->compute_equal(zvar);
598       else input->variable->compute_atom(zvar,igroup,&displace[0][2],3,0);
599     }
600     if (vxvarstr) {
601       if (vxvarstyle == EQUAL) vx = input->variable->compute_equal(vxvar);
602       else input->variable->compute_atom(vxvar,igroup,&velocity[0][0],3,0);
603     }
604     if (vyvarstr) {
605       if (vyvarstyle == EQUAL) vy = input->variable->compute_equal(vyvar);
606       else input->variable->compute_atom(vyvar,igroup,&velocity[0][1],3,0);
607     }
608     if (vzvarstr) {
609       if (vzvarstyle == EQUAL) vz = input->variable->compute_equal(vzvar);
610       else input->variable->compute_atom(vzvar,igroup,&velocity[0][2],3,0);
611     }
612 
613     modify->addstep_compute(update->ntimestep + 1);
614 
615     // update x,v
616     // vest (velocity in next step) could be different from v in the next
617     // step, but this is the best we could do
618 
619     for (int i = 0; i < nlocal; i++) {
620       if (mask[i] & groupbit) {
621         xold[0] = x[i][0];
622         xold[1] = x[i][1];
623         xold[2] = x[i][2];
624 
625         if (xvarstr && vxvarstr) {
626           if (vxvarstyle == EQUAL) {
627             vest[i][0] = 2*vx - v[i][0];
628             v[i][0] = vx;
629           }
630           else {
631             vest[i][0] = 2*velocity[i][0] - v[i][0];
632             v[i][0] = velocity[i][0];
633           }
634           if (xvarstyle == EQUAL) x[i][0] = xoriginal[i][0] + dx;
635           else x[i][0] = xoriginal[i][0] + displace[i][0];
636         } else if (xvarstr) {
637           if (xvarstyle == EQUAL) x[i][0] = xoriginal[i][0] + dx;
638           else x[i][0] = xoriginal[i][0] + displace[i][0];
639         } else if (vxvarstr) {
640           if (vxvarstyle == EQUAL) {
641             vest[i][0] = 2*vx - v[i][0];
642             v[i][0] = vx;
643           }
644           else {
645             vest[i][0] = 2*velocity[i][0] - v[i][0];
646             v[i][0] = velocity[i][0];
647           }
648           x[i][0] += dtv * v[i][0];
649         } else {
650           dtfm = rmass_flag ? dtf / rmass[i] : dtf / mass[type[i]];
651           vest[i][0] = v[i][0] + 2.0 * dtfm * f[i][0];
652           v[i][0] += dtfm * f[i][0];
653           x[i][0] += dtv * v[i][0];
654         }
655 
656         if (yvarstr && vyvarstr) {
657           if (vyvarstyle == EQUAL) {
658             vest[i][1] = 2*vy - v[i][1];
659             v[i][1] = vy;
660           }
661           else {
662             vest[i][1] = 2*velocity[i][1] - v[i][1];
663             v[i][1] = velocity[i][1];
664           }
665           if (yvarstyle == EQUAL) x[i][1] = xoriginal[i][1] + dy;
666           else x[i][1] = xoriginal[i][1] + displace[i][1];
667         } else if (yvarstr) {
668           if (yvarstyle == EQUAL) x[i][1] = xoriginal[i][1] + dy;
669           else x[i][1] = xoriginal[i][1] + displace[i][1];
670         } else if (vyvarstr) {
671           if (vyvarstyle == EQUAL) {
672             vest[i][1] = 2*vy - v[i][1];
673             v[i][1] = vy;
674           }
675           else {
676             vest[i][1] = 2*velocity[i][1] - v[i][1];
677             v[i][1] = velocity[i][1];
678           }
679           x[i][1] += dtv * v[i][1];
680         } else {
681           dtfm = rmass_flag ? dtf / rmass[i] : dtf / mass[type[i]];
682           vest[i][1] = v[i][1] + 2.0 * dtfm * f[i][1];
683           v[i][1] += dtfm * f[i][1];
684           x[i][1] += dtv * v[i][1];
685         }
686 
687         if (zvarstr && vzvarstr) {
688           if (vzvarstyle == EQUAL) {
689             vest[i][2] = 2*vz - v[i][2];
690             v[i][2] = vz;
691           }
692           else {
693             vest[i][2] = 2*velocity[i][2] - v[i][2];
694             v[i][2] = velocity[i][2];
695           }
696           if (zvarstyle == EQUAL) x[i][2] = xoriginal[i][2] + dz;
697           else x[i][2] = xoriginal[i][2] + displace[i][2];
698         } else if (zvarstr) {
699           if (zvarstyle == EQUAL) x[i][2] = xoriginal[i][2] + dz;
700           else x[i][2] = xoriginal[i][2] + displace[i][2];
701         } else if (vzvarstr) {
702           if (vzvarstyle == EQUAL) {
703             vest[i][2] = 2*vz - v[i][2];
704             v[i][2] = vz;
705           }
706           else {
707             vest[i][2] = 2*velocity[i][2] - v[i][2];
708             v[i][2] = velocity[i][2];
709           }
710           x[i][2] += dtv * v[i][2];
711         } else {
712           dtfm = rmass_flag ? dtf / rmass[i] : dtf / mass[type[i]];
713           vest[i][2] = v[i][2] + 2.0 * dtfm * f[i][2];
714           v[i][2] += dtfm * f[i][2];
715           x[i][2] += dtv * v[i][2];
716         }
717 
718         domain->remap_near(x[i],xold);
719       }
720     }
721   }
722 }
723 
724 /* ----------------------------------------------------------------------
725    final NVE of particles with nullptr components
726 ------------------------------------------------------------------------- */
727 
final_integrate()728 void FixMesoMove::final_integrate () {
729   double dtfm;
730 
731   int xflag = 1;
732   if (mstyle == LINEAR && vxflag) xflag = 0;
733   else if (mstyle == WIGGLE && axflag) xflag = 0;
734   else if (mstyle == ROTATE) xflag = 0;
735   else if (mstyle == VARIABLE && (xvarstr || vxvarstr)) xflag = 0;
736 
737   int yflag = 1;
738   if (mstyle == LINEAR && vyflag) yflag = 0;
739   else if (mstyle == WIGGLE && ayflag) yflag = 0;
740   else if (mstyle == ROTATE) yflag = 0;
741   else if (mstyle == VARIABLE && (yvarstr || vyvarstr)) yflag = 0;
742 
743   int zflag = 1;
744   if (mstyle == LINEAR && vzflag) zflag = 0;
745   else if (mstyle == WIGGLE && azflag) zflag = 0;
746   else if (mstyle == ROTATE) zflag = 0;
747   else if (mstyle == VARIABLE && (zvarstr || vzvarstr)) zflag = 0;
748 
749   double **v = atom->v;
750   double **f = atom->f;
751   double *esph = atom->esph;
752   double *desph = atom->desph;
753   double *rho = atom->rho;
754   double *drho = atom->drho;
755   double *rmass = atom->rmass;
756   double *mass = atom->mass;
757   int *type = atom->type;
758   int *mask = atom->mask;
759   int nlocal = atom->nlocal;
760   int rmass_flag = atom->rmass_flag;
761 
762   if (igroup == atom->firstgroup)
763     nlocal = atom->nfirst;
764 
765   for (int i = 0; i < nlocal; i++) {
766     if (mask[i] & groupbit) {
767       esph[i] += dtf * desph[i];
768       rho[i] += dtf * drho[i];
769 
770       if (xflag) {
771         dtfm = rmass_flag ? dtf / rmass[i] : dtf / mass[type[i]];
772         v[i][0] += dtfm * f[i][0];
773       }
774 
775       if (yflag) {
776         dtfm = rmass_flag ? dtf / rmass[i] : dtf / mass[type[i]];
777         v[i][1] += dtfm * f[i][1];
778       }
779 
780       if (zflag) {
781         dtfm = rmass_flag ? dtf / rmass[i] : dtf / mass[type[i]];
782         v[i][2] += dtfm * f[i][2];
783       }
784     }
785   }
786 }
787 
788 /* ----------------------------------------------------------------------
789    memory usage of local atom-based array
790 ------------------------------------------------------------------------- */
791 
memory_usage()792 double FixMesoMove::memory_usage () {
793   double bytes = (double)atom->nmax*3 * sizeof(double);
794   if (displaceflag) bytes += (double)atom->nmax*3 * sizeof(double);
795   if (velocityflag) bytes += (double)atom->nmax*3 * sizeof(double);
796   return bytes;
797 }
798 
799 /* ----------------------------------------------------------------------
800    pack entire state of Fix into one write
801 ------------------------------------------------------------------------- */
802 
write_restart(FILE * fp)803 void FixMesoMove::write_restart (FILE *fp) {
804   int n = 0;
805   double list[1];
806   list[n++] = time_origin;
807 
808   if (comm->me == 0) {
809     int size = n * sizeof(double);
810     fwrite(&size,sizeof(int),1,fp);
811     fwrite(list,sizeof(double),n,fp);
812   }
813 }
814 
815 /* ----------------------------------------------------------------------
816    use state info from restart file to restart the Fix
817 ------------------------------------------------------------------------- */
818 
restart(char * buf)819 void FixMesoMove::restart (char *buf) {
820   int n = 0;
821   double *list = (double *) buf;
822 
823   time_origin = static_cast<int> (list[n++]);
824 }
825 
826 /* ----------------------------------------------------------------------
827    allocate atom-based array
828 ------------------------------------------------------------------------- */
829 
grow_arrays(int nmax)830 void FixMesoMove::grow_arrays (int nmax) {
831   memory->grow(xoriginal,nmax,3,"move:xoriginal");
832   array_atom = xoriginal;
833 }
834 
835 /* ----------------------------------------------------------------------
836    copy values within local atom-based array
837 ------------------------------------------------------------------------- */
838 
copy_arrays(int i,int j,int)839 void FixMesoMove::copy_arrays (int i, int j, int /*delflag*/) {
840   xoriginal[j][0] = xoriginal[i][0];
841   xoriginal[j][1] = xoriginal[i][1];
842   xoriginal[j][2] = xoriginal[i][2];
843 }
844 
845 /* ----------------------------------------------------------------------
846    initialize one atom's array values, called when atom is created
847 ------------------------------------------------------------------------- */
848 
set_arrays(int i)849 void FixMesoMove::set_arrays (int i) {
850   double **x = atom->x;
851   imageint *image = atom->image;
852   int *mask = atom->mask;
853 
854   // particle not in group
855 
856   if (!(mask[i] & groupbit)) {
857     xoriginal[i][0] = xoriginal[i][1] = xoriginal[i][2] = 0.0;
858     return;
859   }
860 
861   // current time still equal fix creation time
862 
863   if (update->ntimestep == time_origin) {
864     domain->unmap(x[i],image[i],xoriginal[i]);
865     return;
866   }
867 
868   // backup particle to time_origin
869 
870   if (mstyle == VARIABLE)
871     error->all(FLERR,"Cannot add atoms to fix meso/move variable");
872 
873   domain->unmap(x[i],image[i],xoriginal[i]);
874   double delta = (update->ntimestep - time_origin) * update->dt;
875 
876   if (mstyle == LINEAR) {
877     if (vxflag) xoriginal[i][0] -= vx * delta;
878     if (vyflag) xoriginal[i][1] -= vy * delta;
879     if (vzflag) xoriginal[i][2] -= vz * delta;
880   } else if (mstyle == WIGGLE) {
881     double arg = omega_rotate * delta;
882     double sine = sin(arg);
883     if (axflag) xoriginal[i][0] -= ax*sine;
884     if (ayflag) xoriginal[i][1] -= ay*sine;
885     if (azflag) xoriginal[i][2] -= az*sine;
886   } else if (mstyle == ROTATE) {
887     double a[3],b[3],c[3],d[3],disp[3],ddotr;
888     double arg = - omega_rotate * delta;
889     double sine = sin(arg);
890     double cosine = cos(arg);
891     d[0] = x[i][0] - point[0];
892     d[1] = x[i][1] - point[1];
893     d[2] = x[i][2] - point[2];
894     ddotr = d[0]*runit[0] + d[1]*runit[1] + d[2]*runit[2];
895     c[0] = ddotr*runit[0];
896     c[1] = ddotr*runit[1];
897     c[2] = ddotr*runit[2];
898 
899     a[0] = d[0] - c[0];
900     a[1] = d[1] - c[1];
901     a[2] = d[2] - c[2];
902     b[0] = runit[1]*a[2] - runit[2]*a[1];
903     b[1] = runit[2]*a[0] - runit[0]*a[2];
904     b[2] = runit[0]*a[1] - runit[1]*a[0];
905     disp[0] = a[0]*cosine  + b[0]*sine;
906     disp[1] = a[1]*cosine  + b[1]*sine;
907     disp[2] = a[2]*cosine  + b[2]*sine;
908 
909     xoriginal[i][0] = point[0] + c[0] + disp[0];
910     xoriginal[i][1] = point[1] + c[1] + disp[1];
911     xoriginal[i][2] = point[2] + c[2] + disp[2];
912   }
913 }
914 
915 /* ----------------------------------------------------------------------
916    pack values in local atom-based array for exchange with another proc
917 ------------------------------------------------------------------------- */
918 
pack_exchange(int i,double * buf)919 int FixMesoMove::pack_exchange (int i, double *buf) {
920   buf[0] = xoriginal[i][0];
921   buf[1] = xoriginal[i][1];
922   buf[2] = xoriginal[i][2];
923   return 3;
924 }
925 
926 /* ----------------------------------------------------------------------
927    unpack values in local atom-based array from exchange with another proc
928 ------------------------------------------------------------------------- */
929 
unpack_exchange(int nlocal,double * buf)930 int FixMesoMove::unpack_exchange (int nlocal, double *buf) {
931   xoriginal[nlocal][0] = buf[0];
932   xoriginal[nlocal][1] = buf[1];
933   xoriginal[nlocal][2] = buf[2];
934   return 3;
935 }
936 
937 /* ----------------------------------------------------------------------
938    pack values in local atom-based arrays for restart file
939 ------------------------------------------------------------------------- */
940 
pack_restart(int i,double * buf)941 int FixMesoMove::pack_restart (int i, double *buf) {
942   // pack buf[0] this way because other fixes unpack it
943   buf[0] = 4;
944   buf[1] = xoriginal[i][0];
945   buf[2] = xoriginal[i][1];
946   buf[3] = xoriginal[i][2];
947   return 4;
948 }
949 
950 /* ----------------------------------------------------------------------
951    unpack values from atom->extra array to restart the fix
952 ------------------------------------------------------------------------- */
953 
unpack_restart(int nlocal,int nth)954 void FixMesoMove::unpack_restart (int nlocal, int nth) {
955   double **extra = atom->extra;
956 
957   // skip to Nth set of extra values
958   // unpack the Nth first values this way because other fixes pack them
959 
960   int m = 0;
961   for (int i = 0; i < nth; i++) m += static_cast<int> (extra[nlocal][m]);
962   m++;
963 
964   xoriginal[nlocal][0] = extra[nlocal][m++];
965   xoriginal[nlocal][1] = extra[nlocal][m++];
966   xoriginal[nlocal][2] = extra[nlocal][m++];
967 }
968 
969 /* ----------------------------------------------------------------------
970    maxsize of any atom's restart data
971 ------------------------------------------------------------------------- */
972 
maxsize_restart()973 int FixMesoMove::maxsize_restart () {
974   return 4;
975 }
976 
977 /* ----------------------------------------------------------------------
978    size of atom nlocal's restart data
979 ------------------------------------------------------------------------- */
980 
size_restart(int)981 int FixMesoMove::size_restart (int /* nlocal */) {
982   return 4;
983 }
984 
985 /* ---------------------------------------------------------------------- */
986 
reset_dt()987 void FixMesoMove::reset_dt () {
988   error->all(FLERR,"Resetting timestep size is not allowed with fix meso/move");
989 }
990