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 authors: Frances Mackay, Santtu Ollila, Colin Denniston (UWO)
17 Based on fix_rigid (version from 2008).
18 ------------------------------------------------------------------------- */
19
20 #include "fix_lb_rigid_pc_sphere.h"
21
22 #include <cmath>
23
24 #include <cstring>
25 #include "atom.h"
26 #include "domain.h"
27 #include "update.h"
28 #include "modify.h"
29 #include "group.h"
30 #include "comm.h"
31 #include "force.h"
32 #include "memory.h"
33 #include "error.h"
34 #include "fix_lb_fluid.h"
35
36 using namespace LAMMPS_NS;
37 using namespace FixConst;
38
39 /* -------------------------------------------------------------------------- */
40
FixLbRigidPCSphere(LAMMPS * lmp,int narg,char ** arg)41 FixLbRigidPCSphere::FixLbRigidPCSphere(LAMMPS *lmp, int narg, char **arg) :
42 Fix(lmp, narg, arg)
43 {
44 int i, ibody;
45
46 scalar_flag = 1;
47 extscalar = 0;
48 time_integrate = 1;
49 rigid_flag = 1;
50 create_attribute = 1;
51 virial_global_flag = virial_peratom_flag = 1;
52 thermo_virial = 1;
53
54 // perform initial allocation of atom-based arrays
55 // register with Atom class
56
57 body = nullptr;
58 up = nullptr;
59 grow_arrays(atom->nmax);
60 atom->add_callback(Atom::GROW);
61
62 // by default assume all of the particles interact with the fluid.
63 inner_nodes = 0;
64
65 // parse command-line args
66 // set nbody and body[i] for each atom
67
68 if (narg < 4) error->all(FLERR,"Illegal fix lb/rigid/pc/sphere command");
69
70 // single rigid body
71 // nbody = 1
72 // all atoms in fix group are part of body
73
74 int iarg;
75
76 if (strcmp(arg[3],"single") == 0) {
77 iarg = 4;
78 nbody = 1;
79
80 int *mask = atom->mask;
81 int nlocal = atom->nlocal;
82
83 for (i = 0; i < nlocal; i++) {
84 body[i] = -1;
85 if (mask[i] & groupbit) body[i] = 0;
86 }
87
88 // each molecule in fix group is a rigid body
89 // maxmol = largest molecule #
90 // ncount = # of atoms in each molecule (have to sum across procs)
91 // nbody = # of non-zero ncount values
92 // use nall as incremented ptr to set body[] values for each atom
93
94 } else if (strcmp(arg[3],"molecule") == 0) {
95 iarg = 4;
96 if (atom->molecular == Atom::ATOMIC)
97 error->all(FLERR,"Must use a molecular atom style with "
98 "fix lb/rigid/pc/sphere molecule");
99
100 int *mask = atom->mask;
101 tagint *molecule = atom->molecule;
102 int nlocal = atom->nlocal;
103
104 tagint maxmol_tag = -1;
105 for (i = 0; i < nlocal; i++)
106 if (mask[i] & groupbit) maxmol_tag = MAX(maxmol_tag,molecule[i]);
107
108 tagint itmp;
109 MPI_Allreduce(&maxmol_tag,&itmp,1,MPI_LMP_TAGINT,MPI_MAX,world);
110 if (itmp+1 > MAXSMALLINT)
111 error->all(FLERR,"Too many molecules for fix lb/rigid/pc/sphere");
112 int maxmol = (int) itmp;
113
114 int *ncount;
115 memory->create(ncount,maxmol+1,"rigid:ncount");
116 for (i = 0; i <= maxmol; i++) ncount[i] = 0;
117
118 for (i = 0; i < nlocal; i++)
119 if (mask[i] & groupbit) ncount[molecule[i]]++;
120
121 int *nall;
122 memory->create(nall,maxmol+1,"rigid:ncount");
123 MPI_Allreduce(ncount,nall,maxmol+1,MPI_LMP_TAGINT,MPI_SUM,world);
124
125 nbody = 0;
126 for (i = 0; i <= maxmol; i++)
127 if (nall[i]) nall[i] = nbody++;
128 else nall[i] = -1;
129
130 for (i = 0; i < nlocal; i++) {
131 body[i] = -1;
132 if (mask[i] & groupbit) body[i] = nall[molecule[i]];
133 }
134
135 memory->destroy(ncount);
136 memory->destroy(nall);
137
138 // each listed group is a rigid body
139 // check if all listed groups exist
140 // an atom must belong to fix group and listed group to be in rigid body
141 // error if atom belongs to more than 1 rigid body
142
143 } else if (strcmp(arg[3],"group") == 0) {
144 if (narg < 5) error->all(FLERR,"Illegal fix lb/rigid/pc/sphere command");
145 nbody = atoi(arg[4]);
146 if (nbody <= 0) error->all(FLERR,"Illegal fix lb/rigid/pc/sphere command");
147 if (narg < 5+nbody)
148 error->all(FLERR,"Illegal fix lb/rigid/pc/sphere command");
149 iarg = 5 + nbody;
150
151 int *igroups = new int[nbody];
152 for (ibody = 0; ibody < nbody; ibody++) {
153 igroups[ibody] = group->find(arg[5+ibody]);
154 if (igroups[ibody] == -1)
155 error->all(FLERR,"Could not find fix lb/rigid/pc/sphere group ID");
156 }
157
158 int *mask = atom->mask;
159 int nlocal = atom->nlocal;
160
161 int flag = 0;
162 for (i = 0; i < nlocal; i++) {
163 body[i] = -1;
164 if (mask[i] & groupbit)
165 for (ibody = 0; ibody < nbody; ibody++)
166 if (mask[i] & group->bitmask[igroups[ibody]]) {
167 if (body[i] >= 0) flag = 1;
168 body[i] = ibody;
169 }
170 }
171
172 int flagall;
173 MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,world);
174 if (flagall)
175 error->all(FLERR,"One or more atoms belong to multiple rigid bodies");
176
177 delete [] igroups;
178
179 } else error->all(FLERR,"Illegal fix lb/rigid/pc/sphere command");
180
181 // error check on nbody
182
183 if (nbody == 0) error->all(FLERR,"No rigid bodies defined");
184
185 // create all nbody-length arrays
186
187 memory->create(nrigid,nbody,"lb/rigid/pc/sphere:nrigid");
188 memory->create(nrigid_shell,nbody,"lb/rigid/pc/sphere:nrigid_shell");
189 memory->create(masstotal,nbody,"lb/rigid/pc/sphere:masstotal");
190 memory->create(masstotal_shell,nbody,"lb/rigid/pc/sphere:masstotal_shell");
191 memory->create(sphereradius,nbody,"lb/rigid/pc/sphere:sphereradius");
192 memory->create(xcm,nbody,3,"lb/rigid/pc/sphere:xcm");
193 memory->create(xcm_old,nbody,3,"lb/rigid/pc/sphere:xcm_old");
194 memory->create(vcm,nbody,3,"lb/rigid/pc/sphere:vcm");
195 memory->create(ucm,nbody,3,"lb/rigid/pc/sphere:ucm");
196 memory->create(ucm_old,nbody,3,"lb/rigid/pc/sphere:ucm_old");
197 memory->create(fcm,nbody,3,"lb/rigid/pc/sphere:fcm");
198 memory->create(fcm_old,nbody,3,"lb/rigid/pc/sphere:fcm_old");
199 memory->create(fcm_fluid,nbody,3,"lb/rigid/pc/sphere:fcm_fluid");
200 memory->create(omega,nbody,3,"lb/rigid/pc/sphere:omega");
201 memory->create(torque,nbody,3,"lb/rigid/pc/sphere:torque");
202 memory->create(torque_old,nbody,3,"lb/rigid/pc/sphere:torque_old");
203 memory->create(torque_fluid,nbody,3,"lb/rigid/pc/sphere:torque_fluid");
204 memory->create(torque_fluid_old,nbody,3,"lb/rigid/pc/sphere:torque_fluid_old");
205 memory->create(rotate,nbody,3,"lb/rigid/pc/sphere:rotate");
206 memory->create(imagebody,nbody,"lb/rigid/pc/sphere:imagebody");
207 memory->create(fflag,nbody,3,"lb/rigid/pc/sphere:fflag");
208 memory->create(tflag,nbody,3,"lb/rigid/pc/sphere:tflag");
209
210 memory->create(sum,nbody,6,"lb/rigid/pc/sphere:sum");
211 memory->create(all,nbody,6,"lb/rigid/pc/sphere:all");
212 memory->create(remapflag,nbody,4,"lb/rigid/pc/sphere:remapflag");
213
214
215 Gamma_MD = new double[nbody];
216
217 // initialize force/torque flags to default = 1.0
218
219 array_flag = 1;
220 size_array_rows = nbody;
221 size_array_cols = 15;
222 global_freq = 1;
223 extarray = 0;
224
225 for (i = 0; i < nbody; i++) {
226 fflag[i][0] = fflag[i][1] = fflag[i][2] = 1.0;
227 tflag[i][0] = tflag[i][1] = tflag[i][2] = 1.0;
228 }
229
230 // parse optional args that set fflag and tflag
231
232 while (iarg < narg) {
233 if (strcmp(arg[iarg],"force") == 0) {
234 if (iarg+5 > narg) error->all(FLERR,"Illegal fix lb/rigid/pc/sphere command");
235
236 int mlo,mhi;
237 utils::bounds(FLERR,arg[iarg+1],1,nbody,mlo,mhi,error);
238
239 double xflag,yflag,zflag;
240 if (strcmp(arg[iarg+2],"off") == 0) xflag = 0.0;
241 else if (strcmp(arg[iarg+2],"on") == 0) xflag = 1.0;
242 else error->all(FLERR,"Illegal fix lb/rigid/pc/sphere command");
243 if (strcmp(arg[iarg+2],"off") == 0) yflag = 0.0;
244 else if (strcmp(arg[iarg+3],"on") == 0) yflag = 1.0;
245 else error->all(FLERR,"Illegal fix lb/rigid/pc/sphere command");
246 if (strcmp(arg[iarg+4],"off") == 0) zflag = 0.0;
247 else if (strcmp(arg[iarg+4],"on") == 0) zflag = 1.0;
248 else error->all(FLERR,"Illegal fix lb/rigid/pc/sphere command");
249
250 int count = 0;
251 for (int m = mlo; m <= mhi; m++) {
252 fflag[m-1][0] = xflag;
253 fflag[m-1][1] = yflag;
254 fflag[m-1][2] = zflag;
255 count++;
256 }
257 if (count == 0) error->all(FLERR,"Illegal fix lb/rigid/pc/sphere command");
258
259 iarg += 5;
260 } else if (strcmp(arg[iarg],"torque") == 0) {
261 if (iarg+5 > narg) error->all(FLERR,"Illegal fix lb/rigid/pc/sphere command");
262
263 int mlo,mhi;
264 utils::bounds(FLERR,arg[iarg+1],1,nbody,mlo,mhi,error);
265
266 double xflag,yflag,zflag;
267 if (strcmp(arg[iarg+2],"off") == 0) xflag = 0.0;
268 else if (strcmp(arg[iarg+2],"on") == 0) xflag = 1.0;
269 else error->all(FLERR,"Illegal fix lb/rigid/pc/sphere command");
270 if (strcmp(arg[iarg+3],"off") == 0) yflag = 0.0;
271 else if (strcmp(arg[iarg+3],"on") == 0) yflag = 1.0;
272 else error->all(FLERR,"Illegal fix lb/rigid/pc/sphere command");
273 if (strcmp(arg[iarg+4],"off") == 0) zflag = 0.0;
274 else if (strcmp(arg[iarg+4],"on") == 0) zflag = 1.0;
275 else error->all(FLERR,"Illegal fix lb/rigid/pc/sphere command");
276
277 int count = 0;
278 for (int m = mlo; m <= mhi; m++) {
279 tflag[m-1][0] = xflag;
280 tflag[m-1][1] = yflag;
281 tflag[m-1][2] = zflag;
282 count++;
283 }
284 if (count == 0) error->all(FLERR,"Illegal fix lb/rigid/pc/sphere command");
285
286 iarg += 5;
287 // specify if certain particles are inside the rigid spherical body,
288 // and therefore should not
289 } else if (strcmp(arg[iarg],"innerNodes")==0) {
290 inner_nodes = 1;
291 igroupinner = group->find(arg[iarg+1]);
292 if (igroupinner == -1)
293 error->all(FLERR,"Could not find fix lb/rigid/pc/sphere innerNodes group ID");
294 iarg += 2;
295 } else error->all(FLERR,"Illegal fix lb/rigid/pc/sphere command");
296 }
297
298 // initialize vector output quantities in case accessed before run
299
300 for (i = 0; i < nbody; i++) {
301 xcm[i][0] = xcm[i][1] = xcm[i][2] = 0.0;
302 xcm_old[i][0] = xcm_old[i][1] = xcm_old[i][2] = 0.0;
303 vcm[i][0] = vcm[i][1] = vcm[i][2] = 0.0;
304 ucm[i][0] = ucm[i][1] = ucm[i][2] = 0.0;
305 ucm_old[i][0] = ucm_old[i][1] = ucm_old[i][2] = 0.0;
306 fcm[i][0] = fcm[i][1] = fcm[i][2] = 0.0;
307 fcm_old[i][0] = fcm_old[i][1] = fcm_old[i][2] = 0.0;
308 fcm_fluid[i][0] = fcm_fluid[i][1] = fcm_fluid[i][2] = 0.0;
309 torque[i][0] = torque[i][1] = torque[i][2] = 0.0;
310 torque_old[i][0] = torque_old[i][1] = torque_old[i][2] = 0.0;
311 torque_fluid[i][0] = torque_fluid[i][1] = torque_fluid[i][2] = 0.0;
312 torque_fluid_old[i][0] = torque_fluid_old[i][1] = torque_fluid_old[i][2] = 0.0;
313 }
314
315 // nrigid[n] = # of atoms in Nth rigid body
316 // error if one or zero atoms
317
318 int *ncount = new int[nbody];
319 for (ibody = 0; ibody < nbody; ibody++) ncount[ibody] = 0;
320
321 int nlocal = atom->nlocal;
322
323 for (i = 0; i < nlocal; i++)
324 if (body[i] >= 0) ncount[body[i]]++;
325
326 MPI_Allreduce(ncount,nrigid,nbody,MPI_INT,MPI_SUM,world);
327
328 //count the number of atoms in the shell.
329 if (inner_nodes == 1) {
330 int *mask = atom->mask;
331 for (ibody=0; ibody<nbody; ibody++) ncount[ibody] = 0;
332 for (i=0; i<nlocal; i++) {
333 if (!(mask[i] & group->bitmask[igroupinner])) {
334 if (body[i] >= 0) ncount[body[i]]++;
335 }
336 }
337
338 MPI_Allreduce(ncount,nrigid_shell,nbody,MPI_INT,MPI_SUM,world);
339 } else {
340 for (ibody=0; ibody < nbody; ibody++) nrigid_shell[ibody]=nrigid[ibody];
341 }
342
343 delete [] ncount;
344
345 for (ibody = 0; ibody < nbody; ibody++)
346 if (nrigid[ibody] <= 1) error->all(FLERR,"One or zero atoms in rigid body");
347
348 // set image flags for each rigid body to default values
349 // will be reset during init() based on xcm and then by pre_neighbor()
350 // set here, so image value will persist from run to run
351
352 for (ibody = 0; ibody < nbody; ibody++)
353 imagebody[ibody] = ((imageint) IMGMAX << IMG2BITS) |
354 ((imageint) IMGMAX << IMGBITS) | IMGMAX;
355
356 // print statistics
357
358 int nsum = 0;
359 for (ibody = 0; ibody < nbody; ibody++) nsum += nrigid[ibody];
360
361 if (comm->me == 0) {
362 if (screen) fprintf(screen,"%d rigid bodies with %d atoms\n",nbody,nsum);
363 if (logfile) fprintf(logfile,"%d rigid bodies with %d atoms\n",nbody,nsum);
364 }
365
366 int groupbit_lb_fluid = 0;
367
368 for (int ifix=0; ifix<modify->nfix; ifix++)
369 if (strcmp(modify->fix[ifix]->style,"lb/fluid")==0) {
370 fix_lb_fluid = (FixLbFluid *)modify->fix[ifix];
371 groupbit_lb_fluid = group->bitmask[modify->fix[ifix]->igroup];
372 }
373
374 if (groupbit_lb_fluid == 0)
375 error->all(FLERR,"the lb/fluid fix must also be used if using the lb/rigid/pc/sphere fix");
376
377 int *mask = atom->mask;
378 if (inner_nodes == 1) {
379 for (int j=0; j<nlocal; j++) {
380 if ((mask[j] & groupbit) && !(mask[j] & group->bitmask[igroupinner]) && !(mask[j] & groupbit_lb_fluid))
381 error->one(FLERR,"use the innerNodes keyword in the lb/rigid/pc/sphere fix for atoms which do not interact with the lb/fluid");
382
383 // If inner nodes are present, which should not interact with the fluid, make
384 // sure these are not used by the lb/fluid fix to apply a force to the fluid.
385 if ((mask[j] & groupbit) && (mask[j] & groupbit_lb_fluid) && (mask[j] & group->bitmask[igroupinner]))
386 error->one(FLERR,"the inner nodes specified in lb/rigid/pc/sphere should not be included in the lb/fluid fix");
387 }
388 } else {
389 for (int j=0; j<nlocal; j++) {
390 if ((mask[j] & groupbit) && !(mask[j] & groupbit_lb_fluid))
391 error->one(FLERR,"use the innerNodes keyword in the lb/rigid/pc/sphere fix for atoms which do not interact with the lb/fluid");
392 }
393 }
394
395 }
396
397 /* ---------------------------------------------------------------------- */
398
~FixLbRigidPCSphere()399 FixLbRigidPCSphere::~FixLbRigidPCSphere()
400 {
401 // unregister callbacks to this fix from Atom class
402
403 atom->delete_callback(id,Atom::GROW);
404
405 // delete locally stored arrays
406
407 memory->destroy(body);
408 memory->destroy(up);
409
410 // delete nbody-length arrays
411
412 memory->destroy(nrigid);
413 memory->destroy(nrigid_shell);
414 memory->destroy(masstotal);
415 memory->destroy(masstotal_shell);
416 memory->destroy(sphereradius);
417 memory->destroy(xcm);
418 memory->destroy(xcm_old);
419 memory->destroy(vcm);
420 memory->destroy(ucm);
421 memory->destroy(ucm_old);
422 memory->destroy(fcm);
423 memory->destroy(fcm_old);
424 memory->destroy(fcm_fluid);
425 memory->destroy(omega);
426 memory->destroy(torque);
427 memory->destroy(torque_old);
428 memory->destroy(torque_fluid);
429 memory->destroy(torque_fluid_old);
430 memory->destroy(rotate);
431 memory->destroy(imagebody);
432 memory->destroy(fflag);
433 memory->destroy(tflag);
434
435 memory->destroy(sum);
436 memory->destroy(all);
437 memory->destroy(remapflag);
438
439 delete [] Gamma_MD;
440 }
441
442 /* ---------------------------------------------------------------------- */
443
setmask()444 int FixLbRigidPCSphere::setmask()
445 {
446 int mask = 0;
447 mask |= INITIAL_INTEGRATE;
448 mask |= FINAL_INTEGRATE;
449 mask |= PRE_NEIGHBOR;
450 return mask;
451 }
452
453 /* ---------------------------------------------------------------------- */
454
init()455 void FixLbRigidPCSphere::init()
456 {
457 int i,ibody;
458
459 // warn if more than one rigid fix
460
461 int count = 0;
462 for (int i = 0; i < modify->nfix; i++)
463 if (strcmp(modify->fix[i]->style,"lb/rigid/pc/sphere") == 0) count++;
464 if (count > 1 && comm->me == 0) error->warning(FLERR,"More than one fix lb/rigid/pc/sphere");
465
466 // timestep info
467
468 dtv = update->dt;
469 dtf = 0.5 * update->dt * force->ftm2v;
470
471 int *type = atom->type;
472 int nlocal = atom->nlocal;
473 double **x = atom->x;
474 imageint *image = atom->image;
475 double *rmass = atom->rmass;
476 double *mass = atom->mass;
477 int *periodicity = domain->periodicity;
478 double xprd = domain->xprd;
479 double yprd = domain->yprd;
480 double zprd = domain->zprd;
481
482 double **mu = atom->mu;
483 double *radius = atom->radius;
484 int *ellipsoid = atom->ellipsoid;
485 int extended = 0;
486 int *mask = atom->mask;
487
488 // Warn if any extended particles are included.
489 if (atom->radius_flag || atom->ellipsoid_flag || atom->mu_flag) {
490 int flag = 0;
491 for (i = 0; i < nlocal; i++) {
492 if (body[i] < 0) continue;
493 if (radius && radius[i] > 0.0) flag = 1;
494 if (ellipsoid && ellipsoid[i] >= 0) flag = 1;
495 if (mu && mu[i][3] > 0.0) flag = 1;
496 }
497
498 MPI_Allreduce(&flag,&extended,1,MPI_INT,MPI_MAX,world);
499 }
500 if (extended)
501 error->warning(FLERR,"Fix lb/rigid/pc/sphere assumes point particles");
502
503 // compute masstotal & center-of-mass of each rigid body
504
505 for (ibody = 0; ibody < nbody; ibody++)
506 for (i = 0; i < 6; i++) sum[ibody][i] = 0.0;
507 int xbox,ybox,zbox;
508 double massone,xunwrap,yunwrap,zunwrap;
509
510 for (i = 0; i < nlocal; i++) {
511 if (body[i] < 0) continue;
512 ibody = body[i];
513
514 xbox = (image[i] & IMGMASK) - IMGMAX;
515 ybox = (image[i] >> IMGBITS & IMGMASK) - IMGMAX;
516 zbox = (image[i] >> IMG2BITS) - IMGMAX;
517 if (rmass) massone = rmass[i];
518 else massone = mass[type[i]];
519
520 if ((xbox && !periodicity[0]) || (ybox && !periodicity[1]) ||
521 (zbox && !periodicity[2]))
522 error->one(FLERR,"Fix lb/rigid/pc/sphere atom has non-zero image flag "
523 "in a non-periodic dimension");
524
525 xunwrap = x[i][0] + xbox*xprd;
526 yunwrap = x[i][1] + ybox*yprd;
527 zunwrap = x[i][2] + zbox*zprd;
528
529 sum[ibody][0] += xunwrap * massone;
530 sum[ibody][1] += yunwrap * massone;
531 sum[ibody][2] += zunwrap * massone;
532 sum[ibody][3] += massone;
533 if (inner_nodes == 1) {
534 if (!(mask[i] & group->bitmask[igroupinner])) {
535 sum[ibody][4] += massone;
536 }
537 } else {
538 sum[ibody][4] += massone;
539 }
540 }
541
542 MPI_Allreduce(sum[0],all[0],6*nbody,MPI_DOUBLE,MPI_SUM,world);
543
544 for (ibody = 0; ibody < nbody; ibody++) {
545 masstotal[ibody] = all[ibody][3];
546 masstotal_shell[ibody] = all[ibody][4];
547 xcm[ibody][0] = all[ibody][0]/masstotal[ibody];
548 xcm[ibody][1] = all[ibody][1]/masstotal[ibody];
549 xcm[ibody][2] = all[ibody][2]/masstotal[ibody];
550 }
551
552 // Calculate the radius of the rigid body, and assign the value for gamma:
553 double dx,dy,dz;
554 double *Gamma = fix_lb_fluid->Gamma;
555 double dm_lb = fix_lb_fluid->dm_lb;
556 double dt_lb = fix_lb_fluid->dt_lb;
557
558 for (ibody = 0; ibody < nbody; ibody++)
559 for (i = 0; i < 6; i++) sum[ibody][i] = 0.0;
560
561 for (i=0; i<nlocal; i++) {
562 if (body[i] < 0) continue;
563 if (inner_nodes == 1) {
564 if (!(mask[i] & group->bitmask[igroupinner])) {
565 ibody = body[i];
566
567 xbox = (image[i] & IMGMASK) - IMGMAX;
568 ybox = (image[i] >> IMGBITS & IMGMASK) - IMGMAX;
569 zbox = (image[i] >> IMG2BITS) - IMGMAX;
570
571 xunwrap = x[i][0] + xbox*xprd;
572 yunwrap = x[i][1] + ybox*yprd;
573 zunwrap = x[i][2] + zbox*zprd;
574
575 dx = xunwrap - xcm[ibody][0];
576 dy = yunwrap - xcm[ibody][1];
577 dz = zunwrap - xcm[ibody][2];
578
579 sum[ibody][0] += dx*dx + dy*dy + dz*dz;
580 sum[ibody][1] += Gamma[type[i]];
581 }
582 } else {
583 ibody = body[i];
584
585 xbox = (image[i] & IMGMASK) - IMGMAX;
586 ybox = (image[i] >> IMGBITS & IMGMASK) - IMGMAX;
587 zbox = (image[i] >> IMG2BITS) - IMGMAX;
588
589 xunwrap = x[i][0] + xbox*xprd;
590 yunwrap = x[i][1] + ybox*yprd;
591 zunwrap = x[i][2] + zbox*zprd;
592
593 dx = xunwrap - xcm[ibody][0];
594 dy = yunwrap - xcm[ibody][1];
595 dz = zunwrap - xcm[ibody][2];
596
597 sum[ibody][0] += dx*dx + dy*dy + dz*dz;
598 sum[ibody][1] += Gamma[type[i]];
599 }
600 }
601
602 MPI_Allreduce(sum[0],all[0],6*nbody,MPI_DOUBLE,MPI_SUM,world);
603
604 for (ibody=0; ibody < nbody; ibody++) {
605 sphereradius[ibody] = sqrt(all[ibody][0]/nrigid_shell[ibody]);
606 Gamma_MD[ibody] = all[ibody][1]*dm_lb/dt_lb/nrigid_shell[ibody];
607 }
608
609 // Check that all atoms in the rigid body have the same value of gamma.
610 double eps = 1.0e-7;
611 for (i=0; i<nlocal; i++) {
612 if (body[i] < 0) continue;
613 if (inner_nodes == 1) {
614 if (!(mask[i] & group->bitmask[igroupinner])) {
615 ibody = body[i];
616
617 if (Gamma_MD[ibody]*dt_lb/dm_lb - Gamma[type[i]] > eps)
618 error->one(FLERR,"All atoms in a rigid body must have the same gamma value");
619 }
620 } else {
621 ibody = body[i];
622
623 if (Gamma_MD[ibody]*dt_lb/dm_lb - Gamma[type[i]] > eps)
624 error->one(FLERR,"All atoms in a rigid body must have the same gamma value");
625 }
626 }
627
628
629 // remap the xcm of each body back into simulation box if needed
630 // only really necessary the 1st time a run is performed
631
632 pre_neighbor();
633
634
635 // temperature scale factor
636
637 double ndof = 0.0;
638 for (ibody = 0; ibody < nbody; ibody++) {
639 ndof += fflag[ibody][0] + fflag[ibody][1] + fflag[ibody][2];
640 ndof += tflag[ibody][0] + tflag[ibody][1] + tflag[ibody][2];
641 }
642 if (ndof > 0.0) tfactor = force->mvv2e / (ndof * force->boltz);
643 else tfactor = 0.0;
644
645 }
646 /* ---------------------------------------------------------------------- */
647
setup(int vflag)648 void FixLbRigidPCSphere::setup(int vflag)
649 {
650 int i,n,ibody;
651 double massone;
652
653 // vcm = velocity of center-of-mass of each rigid body
654 // fcm = force on center-of-mass of each rigid body
655
656 double **x = atom->x;
657 double **v = atom->v;
658 double **f = atom->f;
659 double *rmass = atom->rmass;
660 double *mass = atom->mass;
661 int *type = atom->type;
662 int nlocal = atom->nlocal;
663
664 imageint *image = atom->image;
665
666 double unwrap[3];
667 double dx,dy,dz;
668
669
670
671 for (ibody = 0; ibody < nbody; ibody++)
672 for (i = 0; i < 6; i++) sum[ibody][i] = 0.0;
673
674 for (i = 0; i < nlocal; i++) {
675 if (body[i] < 0) continue;
676 ibody = body[i];
677 if (rmass) massone = rmass[i];
678 else massone = mass[type[i]];
679
680 sum[ibody][0] += v[i][0] * massone;
681 sum[ibody][1] += v[i][1] * massone;
682 sum[ibody][2] += v[i][2] * massone;
683 sum[ibody][3] += f[i][0];
684 sum[ibody][4] += f[i][1];
685 sum[ibody][5] += f[i][2];
686 }
687
688 MPI_Allreduce(sum[0],all[0],6*nbody,MPI_DOUBLE,MPI_SUM,world);
689
690 for (ibody = 0; ibody < nbody; ibody++) {
691 vcm[ibody][0] = all[ibody][0]/masstotal[ibody];
692 vcm[ibody][1] = all[ibody][1]/masstotal[ibody];
693 vcm[ibody][2] = all[ibody][2]/masstotal[ibody];
694 fcm[ibody][0] = all[ibody][3];
695 fcm[ibody][1] = all[ibody][4];
696 fcm[ibody][2] = all[ibody][5];
697 }
698
699 // omega = angular velocity of each rigid body
700 // Calculated as the average of the angular velocities of the
701 // individual atoms comprising the rigid body.
702 // torque = torque on each rigid body
703 for (ibody = 0; ibody < nbody; ibody++)
704 for (i = 0; i < 6; i++) sum[ibody][i] = 0.0;
705
706 for (i = 0; i < nlocal; i++) {
707 if (body[i] < 0) continue;
708 ibody = body[i];
709
710 domain->unmap(x[i],image[i],unwrap);
711
712 dx = unwrap[0] - xcm[ibody][0];
713 dy = unwrap[1] - xcm[ibody][1];
714 dz = unwrap[2] - xcm[ibody][2];
715
716 if (rmass) massone = rmass[i];
717 else massone = mass[type[i]];
718
719 sum[ibody][0] += (dy * (v[i][2]-vcm[ibody][2]) - dz * (v[i][1]-vcm[ibody][1]))/(dx*dx+dy*dy+dz*dz);
720 sum[ibody][1] += (dz * (v[i][0]-vcm[ibody][0]) - dx * (v[i][2]-vcm[ibody][2]))/(dx*dx+dy*dy+dz*dz);
721 sum[ibody][2] += (dx * (v[i][1]-vcm[ibody][1]) - dy * (v[i][0]-vcm[ibody][0]))/(dx*dx+dy*dy+dz*dz);
722 sum[ibody][3] += dy * f[i][2] - dz * f[i][1];
723 sum[ibody][4] += dz * f[i][0] - dx * f[i][2];
724 sum[ibody][5] += dx * f[i][1] - dy * f[i][0];
725 }
726
727 MPI_Allreduce(sum[0],all[0],6*nbody,MPI_DOUBLE,MPI_SUM,world);
728
729 for (ibody = 0; ibody < nbody; ibody++) {
730 omega[ibody][0] = all[ibody][0]/nrigid[ibody];
731 omega[ibody][1] = all[ibody][1]/nrigid[ibody];
732 omega[ibody][2] = all[ibody][2]/nrigid[ibody];
733 torque[ibody][0] = all[ibody][3];
734 torque[ibody][1] = all[ibody][4];
735 torque[ibody][2] = all[ibody][5];
736 }
737
738 // virial setup before call to set_v
739
740 v_init(vflag);
741
742 // Set the velocities
743 set_v();
744
745 if (evflag) {
746 if (vflag_global)
747 for (n = 0; n < 6; n++) virial[n] *= 2.0;
748 if (vflag_atom) {
749 for (i = 0; i < nlocal; i++)
750 for (n = 0; n < 6; n++)
751 vatom[i][n] *= 2.0;
752 }
753 }
754 }
755
756 /* ---------------------------------------------------------------------- */
757
initial_integrate(int vflag)758 void FixLbRigidPCSphere::initial_integrate(int vflag)
759 {
760 double dtfm;
761
762 int i,ibody;
763
764 double massone;
765 double **x = atom->x;
766 double **v = atom->v;
767 double *rmass = atom->rmass;
768 double *mass = atom->mass;
769 int *type = atom->type;
770 int nlocal = atom->nlocal;
771
772 imageint *image = atom->image;
773
774 double unwrap[3];
775 double dx,dy,dz;
776
777 int *mask = atom->mask;
778
779 // compute the fluid velocity at the initial particle positions
780 compute_up();
781
782 for (ibody = 0; ibody < nbody; ibody++)
783 for (i = 0; i < 6; i++) sum[ibody][i] = 0.0;
784 // Store the fluid velocity at the center of mass
785
786 for (i = 0; i < nlocal; i++) {
787 if (body[i] < 0) continue;
788 ibody = body[i];
789 if (rmass) massone = rmass[i];
790 else massone = mass[type[i]];
791
792 if (inner_nodes == 1) {
793 if (!(mask[i] & group->bitmask[igroupinner])) {
794 sum[ibody][0] += up[i][0]*massone;
795 sum[ibody][1] += up[i][1]*massone;
796 sum[ibody][2] += up[i][2]*massone;
797 }
798 } else {
799 sum[ibody][0] += up[i][0]*massone;
800 sum[ibody][1] += up[i][1]*massone;
801 sum[ibody][2] += up[i][2]*massone;
802 }
803 }
804 MPI_Allreduce(sum[0],all[0],6*nbody,MPI_DOUBLE,MPI_SUM,world);
805
806 for (ibody = 0; ibody < nbody; ibody++) {
807 ucm[ibody][0] = all[ibody][0]/masstotal_shell[ibody];
808 ucm[ibody][1] = all[ibody][1]/masstotal_shell[ibody];
809 ucm[ibody][2] = all[ibody][2]/masstotal_shell[ibody];
810 }
811
812 //Store the total torque due to the fluid.
813 for (ibody = 0; ibody < nbody; ibody++)
814 for (i = 0; i < 6; i++) sum[ibody][i] = 0.0;
815
816 for (i = 0; i<nlocal; i++) {
817 if (body[i] < 0) continue;
818 ibody = body[i];
819
820 domain->unmap(x[i],image[i],unwrap);
821
822 dx = unwrap[0] - xcm[ibody][0];
823 dy = unwrap[1] - xcm[ibody][1];
824 dz = unwrap[2] - xcm[ibody][2];
825
826 if (rmass) massone = rmass[i];
827 else massone = mass[type[i]];
828
829 if (inner_nodes == 1) {
830 if (!(mask[i] & group->bitmask[igroupinner])) {
831 sum[ibody][0] += Gamma_MD[ibody]*(dy * ((up[i][2]-vcm[ibody][2])) -
832 dz * ((up[i][1]-vcm[ibody][1])));
833 sum[ibody][1] += Gamma_MD[ibody]*(dz * ((up[i][0]-vcm[ibody][0])) -
834 dx * ((up[i][2]-vcm[ibody][2])));
835 sum[ibody][2] += Gamma_MD[ibody]*(dx * ((up[i][1]-vcm[ibody][1])) -
836 dy * ((up[i][0]-vcm[ibody][0])));
837 sum[ibody][3] += -Gamma_MD[ibody]*(v[i][0]-up[i][0]);
838 sum[ibody][4] += -Gamma_MD[ibody]*(v[i][1]-up[i][1]);
839 sum[ibody][5] += -Gamma_MD[ibody]*(v[i][2]-up[i][2]);
840 }
841 } else {
842 sum[ibody][0] += Gamma_MD[ibody]*(dy * ((up[i][2]-vcm[ibody][2])) -
843 dz * ((up[i][1]-vcm[ibody][1])));
844 sum[ibody][1] += Gamma_MD[ibody]*(dz * ((up[i][0]-vcm[ibody][0])) -
845 dx * ((up[i][2]-vcm[ibody][2])));
846 sum[ibody][2] += Gamma_MD[ibody]*(dx * ((up[i][1]-vcm[ibody][1])) -
847 dy * ((up[i][0]-vcm[ibody][0])));
848 sum[ibody][3] += -Gamma_MD[ibody]*(v[i][0]-up[i][0]);
849 sum[ibody][4] += -Gamma_MD[ibody]*(v[i][1]-up[i][1]);
850 sum[ibody][5] += -Gamma_MD[ibody]*(v[i][2]-up[i][2]);
851 }
852 }
853
854 MPI_Allreduce(sum[0],all[0],6*nbody,MPI_DOUBLE,MPI_SUM,world);
855
856 for (ibody = 0; ibody < nbody; ibody++) {
857 torque_fluid[ibody][0] = all[ibody][0];
858 torque_fluid[ibody][1] = all[ibody][1];
859 torque_fluid[ibody][2] = all[ibody][2];
860 fcm_fluid[ibody][0] = all[ibody][3];
861 fcm_fluid[ibody][1] = all[ibody][4];
862 fcm_fluid[ibody][2] = all[ibody][5];
863 }
864
865 for (int ibody = 0; ibody < nbody; ibody++) {
866 fcm_old[ibody][0] = fcm[ibody][0];
867 fcm_old[ibody][1] = fcm[ibody][1];
868 fcm_old[ibody][2] = fcm[ibody][2];
869 torque_old[ibody][0] = torque[ibody][0];
870 torque_old[ibody][1] = torque[ibody][1];
871 torque_old[ibody][2] = torque[ibody][2];
872 torque_fluid_old[ibody][0] = torque_fluid[ibody][0];
873 torque_fluid_old[ibody][1] = torque_fluid[ibody][1];
874 torque_fluid_old[ibody][2] = torque_fluid[ibody][2];
875 ucm_old[ibody][0] = ucm[ibody][0];
876 ucm_old[ibody][1] = ucm[ibody][1];
877 ucm_old[ibody][2] = ucm[ibody][2];
878 xcm_old[ibody][0] = xcm[ibody][0];
879 xcm_old[ibody][1] = xcm[ibody][1];
880 xcm_old[ibody][2] = xcm[ibody][2];
881
882 // update xcm by full step
883
884 dtfm = dtf / masstotal[ibody];
885 xcm[ibody][0] += dtv * vcm[ibody][0]+(fcm[ibody][0]+fcm_fluid[ibody][0]/force->ftm2v)*fflag[ibody][0]*dtfm*dtv;
886 xcm[ibody][1] += dtv * vcm[ibody][1]+(fcm[ibody][1]+fcm_fluid[ibody][1]/force->ftm2v)*fflag[ibody][1]*dtfm*dtv;
887 xcm[ibody][2] += dtv * vcm[ibody][2]+(fcm[ibody][2]+fcm_fluid[ibody][2]/force->ftm2v)*fflag[ibody][2]*dtfm*dtv;
888
889 rotate[ibody][0] = omega[ibody][0]*dtv + tflag[ibody][0]*(torque[ibody][0]*force->ftm2v+torque_fluid[ibody][0])*
890 dtv*dtv*5.0/(4.0*masstotal[ibody]*sphereradius[ibody]*sphereradius[ibody]);
891 rotate[ibody][1] = omega[ibody][1]*dtv + tflag[ibody][1]*(torque[ibody][1]*force->ftm2v+torque_fluid[ibody][1])*
892 dtv*dtv*5.0/(4.0*masstotal[ibody]*sphereradius[ibody]*sphereradius[ibody]);
893 rotate[ibody][2] = omega[ibody][2]*dtv + tflag[ibody][2]*(torque[ibody][2]*force->ftm2v+torque_fluid[ibody][2])*
894 dtv*dtv*5.0/(4.0*masstotal[ibody]*sphereradius[ibody]*sphereradius[ibody]);
895
896 // Approximate vcm
897 expminusdttimesgamma = exp(-Gamma_MD[ibody]*dtv*nrigid_shell[ibody]/masstotal[ibody]);
898 force_factor = force->ftm2v/Gamma_MD[ibody]/nrigid_shell[ibody];
899
900 if (fflag[ibody][0]==1) {
901 vcm[ibody][0] = expminusdttimesgamma*(vcm[ibody][0] - ucm[ibody][0] - fcm[ibody][0]*force_factor)
902 + ucm[ibody][0] + fcm[ibody][0]*force_factor;
903 }
904 if (fflag[ibody][1]==1) {
905 vcm[ibody][1] = expminusdttimesgamma*(vcm[ibody][1] - ucm[ibody][1] - fcm[ibody][1]*force_factor) +
906 ucm[ibody][1] + fcm[ibody][1]*force_factor;
907 }
908 if (fflag[ibody][2]==1) {
909 vcm[ibody][2] = expminusdttimesgamma*(vcm[ibody][2] - ucm[ibody][2] - fcm[ibody][2]*force_factor) +
910 ucm[ibody][2] + fcm[ibody][2]*force_factor;
911 }
912
913 // Approximate angmom
914 torque_factor = 5.0*Gamma_MD[ibody]*nrigid_shell[ibody]/(3.0*masstotal[ibody]);
915 expminusdttimesgamma = exp(-dtv*torque_factor);
916
917
918 if (tflag[ibody][0]==1) {
919 omega[ibody][0] = expminusdttimesgamma*(omega[ibody][0] - (3.0/(2.0*nrigid_shell[ibody]*sphereradius[ibody]*sphereradius[ibody]*Gamma_MD[ibody]))*
920 (force->ftm2v*torque[ibody][0] + torque_fluid[ibody][0])) +
921 (3.0/(2.0*nrigid_shell[ibody]*sphereradius[ibody]*sphereradius[ibody]*Gamma_MD[ibody]))*
922 (force->ftm2v*torque[ibody][0] + torque_fluid[ibody][0]);
923 }
924 if (tflag[ibody][1]==1) {
925 omega[ibody][1] = expminusdttimesgamma*(omega[ibody][1] - (3.0/(2.0*nrigid_shell[ibody]*sphereradius[ibody]*sphereradius[ibody]*Gamma_MD[ibody]))*
926 (force->ftm2v*torque[ibody][1] + torque_fluid[ibody][1])) +
927 (3.0/(2.0*nrigid_shell[ibody]*sphereradius[ibody]*sphereradius[ibody]*Gamma_MD[ibody]))*
928 (force->ftm2v*torque[ibody][1] + torque_fluid[ibody][1]);
929 }
930 if (tflag[ibody][2]==1) {
931 omega[ibody][2] = expminusdttimesgamma*(omega[ibody][2] - (3.0/(2.0*nrigid_shell[ibody]*sphereradius[ibody]*sphereradius[ibody]*Gamma_MD[ibody]))*
932 (force->ftm2v*torque[ibody][2] + torque_fluid[ibody][2])) +
933 (3.0/(2.0*nrigid_shell[ibody]*sphereradius[ibody]*sphereradius[ibody]*Gamma_MD[ibody]))*
934 (force->ftm2v*torque[ibody][2] + torque_fluid[ibody][2]);
935 }
936
937 }
938 // virial setup before call to set_xv
939
940 v_init(vflag);
941
942 set_xv();
943 }
944
945 /* ---------------------------------------------------------------------- */
946
final_integrate()947 void FixLbRigidPCSphere::final_integrate()
948 {
949 int i,ibody;
950
951 // sum over atoms to get force and torque on rigid body
952 double massone;
953 imageint *image = atom->image;
954 double **x = atom->x;
955 double **f = atom->f;
956 double *rmass = atom->rmass;
957 double *mass = atom->mass;
958 int *type = atom->type;
959 int nlocal = atom->nlocal;
960
961 double unwrap[3];
962 double dx,dy,dz;
963
964 int *mask = atom->mask;
965
966 for (ibody = 0; ibody < nbody; ibody++)
967 for (i = 0; i < 6; i++) sum[ibody][i] = 0.0;
968
969 for (i = 0; i < nlocal; i++) {
970 if (body[i] < 0) continue;
971 ibody = body[i];
972
973 sum[ibody][0] += f[i][0];
974 sum[ibody][1] += f[i][1];
975 sum[ibody][2] += f[i][2];
976
977 domain->unmap(x[i],image[i],unwrap);
978
979 dx = unwrap[0] - xcm[ibody][0];
980 dy = unwrap[1] - xcm[ibody][1];
981 dz = unwrap[2] - xcm[ibody][2];
982
983 sum[ibody][3] += dy*f[i][2] - dz*f[i][1];
984 sum[ibody][4] += dz*f[i][0] - dx*f[i][2];
985 sum[ibody][5] += dx*f[i][1] - dy*f[i][0];
986 }
987
988 MPI_Allreduce(sum[0],all[0],6*nbody,MPI_DOUBLE,MPI_SUM,world);
989
990 //Compute the correction to the velocity and angular momentum due to the non-fluid forces:
991 for (ibody = 0; ibody < nbody; ibody++) {
992 fcm[ibody][0] = all[ibody][0];
993 fcm[ibody][1] = all[ibody][1];
994 fcm[ibody][2] = all[ibody][2];
995 torque[ibody][0] = all[ibody][3];
996 torque[ibody][1] = all[ibody][4];
997 torque[ibody][2] = all[ibody][5];
998
999 expminusdttimesgamma = exp(-dtv*Gamma_MD[ibody]*nrigid_shell[ibody]/masstotal[ibody]);
1000 DMDcoeff= (dtv - (masstotal[ibody]/nrigid_shell[ibody])*(1.0-expminusdttimesgamma)/Gamma_MD[ibody]);
1001
1002 vcm[ibody][0] += fflag[ibody][0]*DMDcoeff*force->ftm2v*(fcm[ibody][0]-fcm_old[ibody][0])/Gamma_MD[ibody]/dtv/nrigid_shell[ibody];
1003 vcm[ibody][1] += fflag[ibody][1]*DMDcoeff*force->ftm2v*(fcm[ibody][1]-fcm_old[ibody][1])/Gamma_MD[ibody]/dtv/nrigid_shell[ibody];
1004 vcm[ibody][2] += fflag[ibody][2]*DMDcoeff*force->ftm2v*(fcm[ibody][2]-fcm_old[ibody][2])/Gamma_MD[ibody]/dtv/nrigid_shell[ibody];
1005
1006 torque_factor = 5.0*Gamma_MD[ibody]*nrigid_shell[ibody]/(3.0*masstotal[ibody]);
1007 expminusdttimesgamma = exp(-dtv*torque_factor);
1008 DMDcoeff = (dtv - (1.0-expminusdttimesgamma)/torque_factor);
1009
1010 omega[ibody][0] += tflag[ibody][0]*(3.0/(2.0*nrigid_shell[ibody]*sphereradius[ibody]*sphereradius[ibody]*Gamma_MD[ibody]))*DMDcoeff*
1011 force->ftm2v*(torque[ibody][0] - torque_old[ibody][0])/dtv;
1012 omega[ibody][1] += tflag[ibody][1]*(3.0/(2.0*nrigid_shell[ibody]*sphereradius[ibody]*sphereradius[ibody]*Gamma_MD[ibody]))*DMDcoeff*
1013 force->ftm2v*(torque[ibody][1] - torque_old[ibody][1])/dtv;
1014 omega[ibody][2] += tflag[ibody][2]*(3.0/(2.0*nrigid_shell[ibody]*sphereradius[ibody]*sphereradius[ibody]*Gamma_MD[ibody]))*DMDcoeff*
1015 force->ftm2v*(torque[ibody][2] - torque_old[ibody][2])/dtv;
1016 }
1017
1018 //Next, calculate the correction to the velocity and angular momentum due to the fluid forces:
1019 //Calculate the fluid velocity at the new particle locations.
1020 compute_up();
1021
1022 // store fluid quantities for the total body
1023 for (ibody = 0; ibody < nbody; ibody++)
1024 for (i = 0; i < 6; i++) sum[ibody][i] = 0.0;
1025 // Store the fluid velocity at the center of mass, and the total force
1026 // due to the fluid.
1027 for (i = 0; i < nlocal; i++) {
1028 if (body[i] < 0) continue;
1029 ibody = body[i];
1030 if (rmass) massone = rmass[i];
1031 else massone = mass[type[i]];
1032
1033 domain->unmap(x[i],image[i],unwrap);
1034
1035 dx = unwrap[0] - xcm[ibody][0];
1036 dy = unwrap[1] - xcm[ibody][1];
1037 dz = unwrap[2] - xcm[ibody][2];
1038
1039 if (inner_nodes == 1) {
1040 if (!(mask[i] & group->bitmask[igroupinner])) {
1041 sum[ibody][0] += up[i][0]*massone;
1042 sum[ibody][1] += up[i][1]*massone;
1043 sum[ibody][2] += up[i][2]*massone;
1044 sum[ibody][3] += Gamma_MD[ibody]*(dy * ((up[i][2]-vcm[ibody][2])) -
1045 dz * ((up[i][1]-vcm[ibody][1])));
1046 sum[ibody][4] += Gamma_MD[ibody]*(dz * ((up[i][0]-vcm[ibody][0])) -
1047 dx * ((up[i][2]-vcm[ibody][2])));
1048 sum[ibody][5] += Gamma_MD[ibody]*(dx * ((up[i][1]-vcm[ibody][1])) -
1049 dy * ((up[i][0]-vcm[ibody][0])));
1050 }
1051 } else {
1052 sum[ibody][0] += up[i][0]*massone;
1053 sum[ibody][1] += up[i][1]*massone;
1054 sum[ibody][2] += up[i][2]*massone;
1055 sum[ibody][3] += Gamma_MD[ibody]*(dy * ((up[i][2]-vcm[ibody][2])) -
1056 dz * ((up[i][1]-vcm[ibody][1])));
1057 sum[ibody][4] += Gamma_MD[ibody]*(dz * ((up[i][0]-vcm[ibody][0])) -
1058 dx * ((up[i][2]-vcm[ibody][2])));
1059 sum[ibody][5] += Gamma_MD[ibody]*(dx * ((up[i][1]-vcm[ibody][1])) -
1060 dy * ((up[i][0]-vcm[ibody][0])));
1061 }
1062 }
1063
1064 MPI_Allreduce(sum[0],all[0],6*nbody,MPI_DOUBLE,MPI_SUM,world);
1065
1066 for (ibody = 0; ibody < nbody; ibody++) {
1067 ucm[ibody][0] = all[ibody][0]/masstotal_shell[ibody];
1068 ucm[ibody][1] = all[ibody][1]/masstotal_shell[ibody];
1069 ucm[ibody][2] = all[ibody][2]/masstotal_shell[ibody];
1070 torque_fluid[ibody][0] = all[ibody][3];
1071 torque_fluid[ibody][1] = all[ibody][4];
1072 torque_fluid[ibody][2] = all[ibody][5];
1073 }
1074
1075 for (ibody = 0; ibody < nbody; ibody++) {
1076
1077 expminusdttimesgamma = exp(-dtv*Gamma_MD[ibody]*nrigid_shell[ibody]/masstotal[ibody]);
1078 DMDcoeff= (dtv - (masstotal[ibody]/nrigid_shell[ibody])*(1.0-expminusdttimesgamma)/Gamma_MD[ibody]);
1079
1080 vcm[ibody][0] += DMDcoeff*fflag[ibody][0]*(ucm[ibody][0]-ucm_old[ibody][0])/dtv;
1081 vcm[ibody][1] += DMDcoeff*fflag[ibody][1]*(ucm[ibody][1]-ucm_old[ibody][1])/dtv;
1082 vcm[ibody][2] += DMDcoeff*fflag[ibody][2]*(ucm[ibody][2]-ucm_old[ibody][2])/dtv;
1083
1084 torque_factor = 5.0*Gamma_MD[ibody]*nrigid_shell[ibody]/(3.0*masstotal[ibody]);
1085 expminusdttimesgamma = exp(-dtv*torque_factor);
1086 DMDcoeff = (dtv - (1.0-expminusdttimesgamma)/torque_factor);
1087
1088 omega[ibody][0] += tflag[ibody][0]*(3.0/(2.0*nrigid_shell[ibody]*sphereradius[ibody]*sphereradius[ibody]*Gamma_MD[ibody]))*
1089 DMDcoeff*(torque_fluid[ibody][0] - torque_fluid_old[ibody][0])/dtv;
1090 omega[ibody][1] += tflag[ibody][1]*(3.0/(2.0*nrigid_shell[ibody]*sphereradius[ibody]*sphereradius[ibody]*Gamma_MD[ibody]))*
1091 DMDcoeff*(torque_fluid[ibody][1] - torque_fluid_old[ibody][1])/dtv;
1092 omega[ibody][2] += tflag[ibody][2]*(3.0/(2.0*nrigid_shell[ibody]*sphereradius[ibody]*sphereradius[ibody]*Gamma_MD[ibody]))*
1093 DMDcoeff*(torque_fluid[ibody][2] - torque_fluid_old[ibody][2])/dtv;
1094 }
1095
1096 set_v();
1097
1098 }
1099
1100 /* ----------------------------------------------------------------------
1101 set space-frame velocity of each atom in a rigid body
1102 set omega and angmom of extended particles
1103 v = Vcm + (W cross (x - Xcm))
1104 ------------------------------------------------------------------------- */
1105
set_v()1106 void FixLbRigidPCSphere::set_v()
1107 {
1108 int ibody;
1109 int xbox,ybox,zbox;
1110 double dx,dy,dz;
1111 double x0,x1,x2,v0,v1,v2,fc0,fc1,fc2,massone;
1112 double vr[6];
1113
1114 double **x = atom->x;
1115 double **v = atom->v;
1116 double **f = atom->f;
1117 double *rmass = atom->rmass;
1118 double *mass = atom->mass;
1119 int *type = atom->type;
1120 imageint *image = atom->image;
1121 int nlocal = atom->nlocal;
1122
1123 double xprd = domain->xprd;
1124 double yprd = domain->yprd;
1125 double zprd = domain->zprd;
1126 double xunwrap,yunwrap,zunwrap;
1127
1128 // set v of each atom
1129
1130 for (int i = 0; i < nlocal; i++) {
1131 if (body[i] < 0) continue;
1132 ibody = body[i];
1133
1134 xbox = (image[i] & IMGMASK) - IMGMAX;
1135 ybox = (image[i] >> IMGBITS & IMGMASK) - IMGMAX;
1136 zbox = (image[i] >> IMG2BITS) - IMGMAX;
1137
1138 xunwrap = x[i][0] + xbox*xprd;
1139 yunwrap = x[i][1] + ybox*yprd;
1140 zunwrap = x[i][2] + zbox*zprd;
1141
1142 dx = xunwrap - xcm[ibody][0];
1143 dy = yunwrap - xcm[ibody][1];
1144 dz = zunwrap - xcm[ibody][2];
1145
1146 // save old velocities for virial.
1147 if (evflag) {
1148 v0 = v[i][0];
1149 v1 = v[i][1];
1150 v2 = v[i][2];
1151 }
1152
1153 v[i][0] = (omega[ibody][1]*dz - omega[ibody][2]*dy) + vcm[ibody][0];
1154 v[i][1] = (omega[ibody][2]*dx - omega[ibody][0]*dz) + vcm[ibody][1];
1155 v[i][2] = (omega[ibody][0]*dy - omega[ibody][1]*dx) + vcm[ibody][2];
1156
1157 // virial = unwrapped coords dotted into body constraint force
1158 // body constraint force = implied force due to v change minus f external
1159 // assume f does not include forces internal to body
1160 // 1/2 factor b/c initial_integrate contributes other half
1161 // assume per-atom contribution is due to constraint force on that atom
1162
1163 if (evflag) {
1164 if (rmass) massone = rmass[i];
1165 else massone = mass[type[i]];
1166 fc0 = massone*(v[i][0] - v0)/dtf - f[i][0] + Gamma_MD[ibody]*(v0-up[i][0]);
1167 fc1 = massone*(v[i][1] - v1)/dtf - f[i][1] + Gamma_MD[ibody]*(v1-up[i][1]);
1168 fc2 = massone*(v[i][2] - v2)/dtf - f[i][2] + Gamma_MD[ibody]*(v2-up[i][2]);
1169
1170 xbox = (image[i] & IMGMASK) - IMGMAX;
1171 ybox = (image[i] >> IMGBITS & IMGMASK) - IMGMAX;
1172 zbox = (image[i] >> IMG2BITS) - IMGMAX;
1173
1174 x0 = x[i][0] + xbox*xprd;
1175 x1 = x[i][1] + ybox*yprd;
1176 x2 = x[i][2] + zbox*zprd;
1177
1178 vr[0] = 0.5*x0*fc0;
1179 vr[1] = 0.5*x1*fc1;
1180 vr[2] = 0.5*x2*fc2;
1181 vr[3] = 0.5*x0*fc1;
1182 vr[4] = 0.5*x0*fc2;
1183 vr[5] = 0.5*x1*fc2;
1184
1185 v_tally(1,&i,1.0,vr);
1186 }
1187 }
1188
1189 }
1190 /* ----------------------------------------------------------------------
1191 set space-frame coords and velocity of each atom in each rigid body
1192 set orientation and rotation of extended particles
1193 x = Q displace + Xcm, mapped back to periodic box
1194 v = Vcm + (W cross (x - Xcm))
1195 ------------------------------------------------------------------------- */
1196
set_xv()1197 void FixLbRigidPCSphere::set_xv()
1198 {
1199 int ibody;
1200 int xbox,ybox,zbox;
1201 double x0,x1,x2,v0,v1,v2,fc0,fc1,fc2,massone;
1202 double vr[6];
1203
1204 double **x = atom->x;
1205 double **v = atom->v;
1206 double **f = atom->f;
1207 double *rmass = atom->rmass;
1208 double *mass = atom->mass;
1209 int *type = atom->type;
1210 imageint *image = atom->image;
1211 int nlocal = atom->nlocal;
1212
1213 double xprd = domain->xprd;
1214 double yprd = domain->yprd;
1215 double zprd = domain->zprd;
1216 double xunwrap,yunwrap,zunwrap;
1217 double dx,dy,dz;
1218
1219
1220 // set x and v of each atom
1221
1222 for (int i = 0; i < nlocal; i++) {
1223 if (body[i] < 0) continue;
1224 ibody = body[i];
1225
1226 xbox = (image[i] & IMGMASK) - IMGMAX;
1227 ybox = (image[i] >> IMGBITS & IMGMASK) - IMGMAX;
1228 zbox = (image[i] >> IMG2BITS) - IMGMAX;
1229
1230 xunwrap = x[i][0] + xbox*xprd;
1231 yunwrap = x[i][1] + ybox*yprd;
1232 zunwrap = x[i][2] + zbox*zprd;
1233
1234 dx = xunwrap - xcm_old[ibody][0];
1235 dy = yunwrap - xcm_old[ibody][1];
1236 dz = zunwrap - xcm_old[ibody][2];
1237
1238 // save old positions and velocities for virial
1239 if (evflag) {
1240 x0 = xunwrap;
1241 x1 = yunwrap;
1242 x2 = zunwrap;
1243 v0 = v[i][0];
1244 v1 = v[i][1];
1245 v2 = v[i][2];
1246 }
1247
1248 // x = displacement from center-of-mass, based on body orientation
1249 // v = vcm + omega around center-of-mass
1250
1251 x[i][0] = dx;
1252 x[i][1] = dy;
1253 x[i][2] = dz;
1254
1255 //Perform the rotations:
1256 dx = x[i][0];
1257 dy = x[i][1];
1258 dz = x[i][2];
1259 x[i][0] = cos(rotate[ibody][2])*dx - sin(rotate[ibody][2])*dy;
1260 x[i][1] = sin(rotate[ibody][2])*dx + cos(rotate[ibody][2])*dy;
1261
1262 dx = x[i][0];
1263 dy = x[i][1];
1264 dz = x[i][2];
1265 x[i][0] = cos(rotate[ibody][1])*dx + sin(rotate[ibody][1])*dz;
1266 x[i][2] = -sin(rotate[ibody][1])*dx + cos(rotate[ibody][1])*dz;
1267
1268 dx = x[i][0];
1269 dy = x[i][1];
1270 dz = x[i][2];
1271 x[i][1] = cos(rotate[ibody][0])*dy - sin(rotate[ibody][0])*dz;
1272 x[i][2] = sin(rotate[ibody][0])*dy + cos(rotate[ibody][0])*dz;
1273
1274 v[i][0] = (omega[ibody][1]*x[i][2] - omega[ibody][2]*x[i][1]) + vcm[ibody][0];
1275 v[i][1] = (omega[ibody][2]*x[i][0] - omega[ibody][0]*x[i][2]) + vcm[ibody][1];
1276 v[i][2] = (omega[ibody][0]*x[i][1] - omega[ibody][1]*x[i][0]) + vcm[ibody][2];
1277
1278 // add center of mass to displacement
1279 // map back into periodic box via xbox,ybox,zbox
1280 // for triclinic, add in box tilt factors as well
1281 x[i][0] += xcm[ibody][0] - xbox*xprd;
1282 x[i][1] += xcm[ibody][1] - ybox*yprd;
1283 x[i][2] += xcm[ibody][2] - zbox*zprd;
1284
1285 // virial = unwrapped coords dotted into body constraint force
1286 // body constraint force = implied force due to v change minus f external
1287 // assume f does not include forces internal to body
1288 // 1/2 factor b/c final_integrate contributes other half
1289 // assume per-atom contribution is due to constraint force on that atom
1290
1291 if (evflag) {
1292 if (rmass) massone = rmass[i];
1293 else massone = mass[type[i]];
1294 fc0 = massone*(v[i][0] - v0)/dtf - f[i][0] + Gamma_MD[ibody]*(v0-up[i][0]);
1295 fc1 = massone*(v[i][1] - v1)/dtf - f[i][1] + Gamma_MD[ibody]*(v1-up[i][1]);
1296 fc2 = massone*(v[i][2] - v2)/dtf - f[i][2] + Gamma_MD[ibody]*(v2-up[i][2]);
1297
1298 vr[0] = 0.5*x0*fc0;
1299 vr[1] = 0.5*x1*fc1;
1300 vr[2] = 0.5*x2*fc2;
1301 vr[3] = 0.5*x0*fc1;
1302 vr[4] = 0.5*x0*fc2;
1303 vr[5] = 0.5*x1*fc2;
1304
1305 v_tally(1,&i,1.0,vr);
1306 }
1307 }
1308 }
1309
1310 /* ----------------------------------------------------------------------
1311 remap xcm of each rigid body back into periodic simulation box
1312 done during pre_neighbor so will be after call to pbc()
1313 and after fix_deform::pre_exchange() may have flipped box
1314 use domain->remap() in case xcm is far away from box
1315 due to 1st definition of rigid body or due to box flip
1316 if don't do this, then atoms of a body which drifts far away
1317 from a triclinic box will be remapped back into box
1318 with huge displacements when the box tilt changes via set_x()
1319 ------------------------------------------------------------------------- */
1320
pre_neighbor()1321 void FixLbRigidPCSphere::pre_neighbor()
1322 {
1323 imageint original,oldimage,newimage;
1324
1325 for (int ibody = 0; ibody < nbody; ibody++) {
1326 original = imagebody[ibody];
1327 domain->remap(xcm[ibody],imagebody[ibody]);
1328
1329 if (original == imagebody[ibody]) {
1330 remapflag[ibody][3] = 0;
1331 } else {
1332 oldimage = original & IMGMASK;
1333 newimage = imagebody[ibody] & IMGMASK;
1334 remapflag[ibody][0] = newimage - oldimage;
1335 oldimage = (original >> IMGBITS) & IMGMASK;
1336 newimage = (imagebody[ibody] >> IMGBITS) & IMGMASK;
1337 remapflag[ibody][1] = newimage - oldimage;
1338 oldimage = original >> IMG2BITS;
1339 newimage = imagebody[ibody] >> IMG2BITS;
1340 remapflag[ibody][2] = newimage - oldimage;
1341 remapflag[ibody][3] = 1;
1342 }
1343 }
1344
1345 // adjust image flags of any atom in a rigid body whose xcm was remapped
1346
1347 imageint *atomimage = atom->image;
1348 int nlocal = atom->nlocal;
1349
1350 int ibody;
1351 imageint idim,otherdims;
1352
1353 for (int i = 0; i < nlocal; i++) {
1354 if (body[i] == -1) continue;
1355 if (remapflag[body[i]][3] == 0) continue;
1356 ibody = body[i];
1357
1358 if (remapflag[ibody][0]) {
1359 idim = atomimage[i] & IMGMASK;
1360 otherdims = atomimage[i] ^ idim;
1361 idim -= remapflag[ibody][0];
1362 idim &= IMGMASK;
1363 atomimage[i] = otherdims | idim;
1364 }
1365 if (remapflag[ibody][1]) {
1366 idim = (atomimage[i] >> IMGBITS) & IMGMASK;
1367 otherdims = atomimage[i] ^ (idim << IMGBITS);
1368 idim -= remapflag[ibody][1];
1369 idim &= IMGMASK;
1370 atomimage[i] = otherdims | (idim << IMGBITS);
1371 }
1372 if (remapflag[ibody][2]) {
1373 idim = atomimage[i] >> IMG2BITS;
1374 otherdims = atomimage[i] ^ (idim << IMG2BITS);
1375 idim -= remapflag[ibody][2];
1376 idim &= IMGMASK;
1377 atomimage[i] = otherdims | (idim << IMG2BITS);
1378 }
1379 }
1380 }
1381 /* ----------------------------------------------------------------------
1382 count # of degrees-of-freedom removed by fix_rigid for atoms in igroup
1383 ------------------------------------------------------------------------- */
1384
dof(int igroup)1385 int FixLbRigidPCSphere::dof(int igroup)
1386 {
1387 int groupbit = group->bitmask[igroup];
1388
1389 // ncount = # of atoms in each rigid body that are also in group
1390
1391 int *mask = atom->mask;
1392 int nlocal = atom->nlocal;
1393
1394 int *ncount = new int[nbody];
1395 for (int ibody = 0; ibody < nbody; ibody++) ncount[ibody] = 0;
1396
1397 for (int i = 0; i < nlocal; i++)
1398 if (body[i] >= 0 && mask[i] & groupbit) ncount[body[i]]++;
1399
1400 int *nall = new int[nbody];
1401 MPI_Allreduce(ncount,nall,nbody,MPI_INT,MPI_SUM,world);
1402
1403 // remove 3N - 6 dof for each rigid body if more than 2 atoms in igroup
1404 // remove 3N - 5 dof for each diatomic rigid body in igroup
1405
1406 int n = 0;
1407 for (int ibody = 0; ibody < nbody; ibody++) {
1408 if (nall[ibody] > 2) n += 3*nall[ibody] - 6;
1409 else if (nall[ibody] == 2) n++;
1410 }
1411
1412 delete [] ncount;
1413 delete [] nall;
1414
1415 return n;
1416 }
1417
1418 /* ----------------------------------------------------------------------
1419 memory usage of local atom-based arrays
1420 ------------------------------------------------------------------------- */
1421
memory_usage()1422 double FixLbRigidPCSphere::memory_usage()
1423 {
1424 int nmax = atom->nmax;
1425 double bytes = (double)nmax * sizeof(int);
1426 bytes += (double)nmax*3 * sizeof(double);
1427 bytes += (double)maxvatom*6 * sizeof(double);
1428
1429 return bytes;
1430 }
1431
1432 /* ----------------------------------------------------------------------
1433 allocate local atom-based arrays
1434 ------------------------------------------------------------------------- */
1435
grow_arrays(int nmax)1436 void FixLbRigidPCSphere::grow_arrays(int nmax)
1437 {
1438
1439 memory->grow(body,nmax,"rigid:body");
1440 memory->grow(up,nmax,3,"rigid:up");
1441
1442 }
1443
1444 /* ----------------------------------------------------------------------
1445 copy values within local atom-based arrays
1446 ------------------------------------------------------------------------- */
1447
copy_arrays(int i,int j,int)1448 void FixLbRigidPCSphere::copy_arrays(int i, int j, int /*delflag*/)
1449 {
1450 body[j] = body[i];
1451 up[j][0] = up[i][0];
1452 up[j][1] = up[i][1];
1453 up[j][2] = up[i][2];
1454 }
1455
1456 /* ----------------------------------------------------------------------
1457 initialize one atom's array values, called when atom is created
1458 ------------------------------------------------------------------------- */
1459
set_arrays(int i)1460 void FixLbRigidPCSphere::set_arrays(int i)
1461 {
1462 body[i] = -1;
1463 up[i][0] = 0.0;
1464 up[i][1] = 0.0;
1465 up[i][2] = 0.0;
1466
1467 }
1468
1469 /* ----------------------------------------------------------------------
1470 pack values in local atom-based arrays for exchange with another proc
1471 ------------------------------------------------------------------------- */
1472
pack_exchange(int i,double * buf)1473 int FixLbRigidPCSphere::pack_exchange(int i, double *buf)
1474 {
1475 buf[0] = body[i];
1476 buf[1] = up[i][0];
1477 buf[2] = up[i][1];
1478 buf[3] = up[i][2];
1479 return 4;
1480
1481 }
1482
1483 /* ----------------------------------------------------------------------
1484 unpack values in local atom-based arrays from exchange with another proc
1485 ------------------------------------------------------------------------- */
1486
unpack_exchange(int nlocal,double * buf)1487 int FixLbRigidPCSphere::unpack_exchange(int nlocal, double *buf)
1488 {
1489 body[nlocal] = static_cast<int> (buf[0]);
1490 up[nlocal][0] = buf[1];
1491 up[nlocal][1] = buf[2];
1492 up[nlocal][2] = buf[3];
1493 return 4;
1494 }
1495
1496 /* ---------------------------------------------------------------------- */
1497
reset_dt()1498 void FixLbRigidPCSphere::reset_dt()
1499 {
1500 dtv = update->dt;
1501 dtf = 0.5 * update->dt * force->ftm2v;
1502 }
1503
1504 /* ----------------------------------------------------------------------
1505 return temperature of collection of rigid bodies
1506 non-active DOF are removed by fflag/tflag and in tfactor
1507 ------------------------------------------------------------------------- */
1508
compute_scalar()1509 double FixLbRigidPCSphere::compute_scalar()
1510 {
1511
1512 double inertia;
1513 double t = 0.0;
1514
1515 for (int i = 0; i < nbody; i++) {
1516 t += masstotal[i] * (fflag[i][0]*vcm[i][0]*vcm[i][0] +
1517 fflag[i][1]*vcm[i][1]*vcm[i][1] + \
1518 fflag[i][2]*vcm[i][2]*vcm[i][2]);
1519
1520 // wbody = angular velocity in body frame
1521
1522 inertia = 2.0*masstotal[i]*sphereradius[i]*sphereradius[i]/5.0;
1523
1524 t += tflag[i][0]*inertia*omega[i][0]*omega[i][0] +
1525 tflag[i][1]*inertia*omega[i][1]*omega[i][1] +
1526 tflag[i][2]*inertia*omega[i][2]*omega[i][2];
1527 }
1528
1529 t *= tfactor;
1530 return t;
1531 }
1532
1533
1534 /* ----------------------------------------------------------------------
1535 return attributes of a rigid body
1536 15 values per body
1537 xcm = 0,1,2; vcm = 3,4,5; fcm = 6,7,8; torque = 9,10,11; image = 12,13,14
1538 ------------------------------------------------------------------------- */
1539
compute_array(int i,int j)1540 double FixLbRigidPCSphere::compute_array(int i, int j)
1541 {
1542 if (j < 3) return xcm[i][j];
1543 if (j < 6) return vcm[i][j-3];
1544 if (j < 9) return (fcm[i][j-6]+fcm_fluid[i][j-6]);
1545 if (j < 12) return (torque[i][j-9]+torque_fluid[i][j-9]);
1546 if (j == 12) return (imagebody[i] & IMGMASK) - IMGMAX;
1547 if (j == 13) return (imagebody[i] >> IMGBITS & IMGMASK) - IMGMAX;
1548 return (imagebody[i] >> IMG2BITS) - IMGMAX;
1549 }
1550
1551 /* ---------------------------------------------------------------------- */
compute_up(void)1552 void FixLbRigidPCSphere::compute_up(void)
1553 {
1554 int *mask = atom->mask;
1555 int nlocal = atom->nlocal;
1556 double **x = atom->x;
1557 int i,k;
1558 int ix,iy,iz;
1559 int ixp,iyp,izp;
1560 double dx1,dy1,dz1;
1561 int isten,ii,jj,kk;
1562 double r,rsq,weightx,weighty,weightz;
1563 double ****u_lb = fix_lb_fluid->u_lb;
1564 int subNbx = fix_lb_fluid->subNbx;
1565 int subNby = fix_lb_fluid->subNby;
1566 int subNbz = fix_lb_fluid->subNbz;
1567 double dx_lb = fix_lb_fluid->dx_lb;
1568 double dt_lb = fix_lb_fluid->dt_lb;
1569 int trilinear_stencil = fix_lb_fluid->trilinear_stencil;
1570 double FfP[64];
1571
1572
1573 for (i=0; i<nlocal; i++) {
1574 if (mask[i] & groupbit) {
1575
1576 //Calculate nearest leftmost grid point.
1577 //Since array indices from 1 to subNb-2 correspond to the
1578 // local subprocessor domain (not indices from 0), use the
1579 // ceiling value.
1580 ix = (int)ceil((x[i][0]-domain->sublo[0])/dx_lb);
1581 iy = (int)ceil((x[i][1]-domain->sublo[1])/dx_lb);
1582 iz = (int)ceil((x[i][2]-domain->sublo[2])/dx_lb);
1583
1584 //Calculate distances to the nearest points.
1585 dx1 = x[i][0] - (domain->sublo[0] + (ix-1)*dx_lb);
1586 dy1 = x[i][1] - (domain->sublo[1] + (iy-1)*dx_lb);
1587 dz1 = x[i][2] - (domain->sublo[2] + (iz-1)*dx_lb);
1588
1589 // Need to convert these to lattice units:
1590 dx1 = dx1/dx_lb;
1591 dy1 = dy1/dx_lb;
1592 dz1 = dz1/dx_lb;
1593
1594
1595 up[i][0]=0.0; up[i][1]=0.0; up[i][2]=0.0;
1596
1597 if (trilinear_stencil==0) {
1598 isten=0;
1599 for (ii=-1; ii<3; ii++) {
1600 rsq=(-dx1+ii)*(-dx1+ii);
1601
1602 if (rsq>=4) {
1603 weightx=0.0;
1604 } else {
1605 r=sqrt(rsq);
1606 if (rsq>1) {
1607 weightx=(5.0-2.0*r-sqrt(-7.0+12.0*r-4.0*rsq))/8.;
1608 } else {
1609 weightx=(3.0-2.0*r+sqrt(1.0+4.0*r-4.0*rsq))/8.;
1610 }
1611 }
1612 for (jj=-1; jj<3; jj++) {
1613 rsq=(-dy1+jj)*(-dy1+jj);
1614 if (rsq>=4) {
1615 weighty=0.0;
1616 } else {
1617 r=sqrt(rsq);
1618 if (rsq>1) {
1619 weighty=(5.0-2.0*r-sqrt(-7.0+12.0*r-4.0*rsq))/8.;
1620 } else {
1621 weighty=(3.0-2.0*r+sqrt(1.0+4.0*r-4.0*rsq))/8.;
1622 }
1623 }
1624 for (kk=-1; kk<3; kk++) {
1625 rsq=(-dz1+kk)*(-dz1+kk);
1626 if (rsq>=4) {
1627 weightz=0.0;
1628 } else {
1629 r=sqrt(rsq);
1630 if (rsq>1) {
1631 weightz=(5.0-2.0*r-sqrt(-7.0+12.0*r-4.0*rsq))/8.;
1632 } else {
1633 weightz=(3.0-2.0*r+sqrt(1.0+4.0*r-4.0*rsq))/8.;
1634 }
1635 }
1636 ixp = ix+ii;
1637 iyp = iy+jj;
1638 izp = iz+kk;
1639
1640
1641 if (ixp==-1) ixp=subNbx+2;
1642 if (iyp==-1) iyp=subNby+2;
1643 if (izp==-1) izp=subNbz+2;
1644
1645 FfP[isten] = weightx*weighty*weightz;
1646 // interpolated velocity based on delta function.
1647 for (k=0; k<3; k++) {
1648 up[i][k] += u_lb[ixp][iyp][izp][k]*FfP[isten];
1649 }
1650 }
1651 }
1652 }
1653 } else {
1654 FfP[0] = (1.-dx1)*(1.-dy1)*(1.-dz1);
1655 FfP[1] = (1.-dx1)*(1.-dy1)*dz1;
1656 FfP[2] = (1.-dx1)*dy1*(1.-dz1);
1657 FfP[3] = (1.-dx1)*dy1*dz1;
1658 FfP[4] = dx1*(1.-dy1)*(1.-dz1);
1659 FfP[5] = dx1*(1.-dy1)*dz1;
1660 FfP[6] = dx1*dy1*(1.-dz1);
1661 FfP[7] = dx1*dy1*dz1;
1662
1663 ixp = (ix+1);
1664 iyp = (iy+1);
1665 izp = (iz+1);
1666
1667 for (k=0; k<3; k++) { // tri-linearly interpolated velocity at node
1668 up[i][k] = u_lb[ix][iy][iz][k]*FfP[0]
1669 + u_lb[ix][iy][izp][k]*FfP[1]
1670 + u_lb[ix][iyp][iz][k]*FfP[2]
1671 + u_lb[ix][iyp][izp][k]*FfP[3]
1672 + u_lb[ixp][iy][iz][k]*FfP[4]
1673 + u_lb[ixp][iy][izp][k]*FfP[5]
1674 + u_lb[ixp][iyp][iz][k]*FfP[6]
1675 + u_lb[ixp][iyp][izp][k]*FfP[7];
1676 }
1677 }
1678 for (k=0; k<3; k++)
1679 up[i][k] = up[i][k]*dx_lb/dt_lb;
1680
1681 }
1682 }
1683
1684 }
1685