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