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