1 /* ----------------------------------------------------------------------
2    SPARTA - Stochastic PArallel Rarefied-gas Time-accurate Analyzer
3    http://sparta.sandia.gov
4    Steve Plimpton, sjplimp@sandia.gov, Michael Gallis, magalli@sandia.gov
5    Sandia National Laboratories
6 
7    Copyright (2014) 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 SPARTA directory.
13 ------------------------------------------------------------------------- */
14 
15 #include "spatype.h"
16 #include "stdlib.h"
17 #include "string.h"
18 #include "fix_ablate.h"
19 #include "update.h"
20 #include "grid.h"
21 #include "domain.h"
22 #include "comm.h"
23 #include "modify.h"
24 #include "compute.h"
25 #include "fix.h"
26 #include "output.h"
27 #include "input.h"
28 #include "variable.h"
29 #include "dump.h"
30 #include "cut2d.h"     // remove if fix particles-inside-surfs issue
31 #include "cut3d.h"
32 #include "marching_squares.h"
33 #include "marching_cubes.h"
34 #include "random_mars.h"
35 #include "random_knuth.h"
36 #include "memory.h"
37 #include "error.h"
38 
39 using namespace SPARTA_NS;
40 
41 enum{COMPUTE,FIX,VARIABLE,RANDOM};
42 enum{CVALUE,CDELTA};
43 
44 #define INVOKED_PER_GRID 16
45 #define DELTAGRID 1024            // must be bigger than split cells per cell
46 #define DELTASEND 1024
47 #define EPSILON 1.0e-4            // this is on a scale of 0 to 255
48 
49 enum{XLO,XHI,YLO,YHI,ZLO,ZHI,INTERIOR};         // same as Domain
50 enum{NCHILD,NPARENT,NUNKNOWN,NPBCHILD,NPBPARENT,NPBUNKNOWN,NBOUND};  // Update
51 
52 // remove if fix particles-inside-surfs issue
53 enum{PKEEP,PINSERT,PDONE,PDISCARD,PENTRY,PEXIT,PSURF};  // several files
54 
55 // NOTES
56 // should I store one value or 8 per cell
57 // how to preserve svalues and set type of new surfs,
58 //   maybe need local per-cell type
59 // after create new surfs, need to assign group, sc, sr
60 // how to impose sgroup like ReadIsurf does after surfs created
61 // how to prevent adaptation of any cells in the implicit grid group(s)?
62 //   just testing for surfs is not enough, since it may have no surfs
63 // need to update neigh corner points even if neigh cell is not in group?
64 // do a run-time test for gridcut = 0.0 ?
65 // worry about array_grid having updated values for sub cells?  line in store()
66 // can I output both per-grid and global values?
67 
68 /* ---------------------------------------------------------------------- */
69 
FixAblate(SPARTA * sparta,int narg,char ** arg)70 FixAblate::FixAblate(SPARTA *sparta, int narg, char **arg) :
71   Fix(sparta, narg, arg)
72 {
73   MPI_Comm_rank(world,&me);
74 
75   if (narg < 6) error->all(FLERR,"Illegal fix ablate command");
76 
77   igroup = grid->find_group(arg[2]);
78   if (igroup < 0) error->all(FLERR,"Could not find fix ablate group ID");
79   groupbit = grid->bitmask[igroup];
80 
81   nevery = atoi(arg[3]);
82   if (nevery < 0) error->all(FLERR,"Illegal fix ablate command");
83 
84   idsource = NULL;
85 
86   scale = atof(arg[4]);
87   if (scale < 0.0) error->all(FLERR,"Illegal fix ablate command");
88 
89   if ((strncmp(arg[5],"c_",2) == 0) || (strncmp(arg[5],"f_",2) == 0)) {
90     if (arg[5][0] == 'c') which = COMPUTE;
91     else if (arg[5][0] == 'f') which = FIX;
92 
93     int n = strlen(arg[5]);
94     char *suffix = new char[n];
95     strcpy(suffix,&arg[5][2]);
96 
97     char *ptr = strchr(suffix,'[');
98     if (ptr) {
99       if (suffix[strlen(suffix)-1] != ']')
100         error->all(FLERR,"Illegal fix ablate command");
101       argindex = atoi(ptr+1);
102       *ptr = '\0';
103     } else argindex = 0;
104 
105     n = strlen(suffix) + 1;
106     idsource = new char[n];
107     strcpy(idsource,suffix);
108     delete [] suffix;
109 
110   } else if (strncmp(arg[5],"v_",2) == 0) {
111     which = VARIABLE;
112 
113     int n = strlen(arg[5]);
114     char *idsource = new char[n];
115     strcpy(idsource,&arg[5][2]);
116 
117   } else if (strcmp(arg[5],"random") == 0) {
118     if (narg != 7) error->all(FLERR,"Illegal fix ablate command");
119     which = RANDOM;
120     maxrandom = atoi(arg[6]);
121 
122   } else error->all(FLERR,"Illegal fix ablate command");
123 
124   // error check
125 
126   if (which == COMPUTE) {
127     icompute = modify->find_compute(idsource);
128     if (icompute < 0)
129       error->all(FLERR,"Compute ID for fix ablate does not exist");
130     if (modify->compute[icompute]->per_grid_flag == 0)
131       error->all(FLERR,
132                  "Fix ablate compute does not calculate per-grid values");
133     if (modify->compute[icompute]->post_process_isurf_grid_flag == 0)
134       error->all(FLERR,
135                  "Fix ablate compute does not calculate isurf per-grid values");
136     if (argindex == 0 &&
137         modify->compute[icompute]->size_per_grid_cols != 0)
138       error->all(FLERR,"Fix ablate compute does not "
139                  "calculate per-grid vector");
140     if (argindex && modify->compute[icompute]->size_per_grid_cols == 0)
141       error->all(FLERR,"Fix ablate compute does not "
142                  "calculate per-grid array");
143     if (argindex && argindex > modify->compute[icompute]->size_per_grid_cols)
144       error->all(FLERR,"Fix ablate compute array is accessed out-of-range");
145 
146   } else if (which == FIX) {
147     ifix = modify->find_fix(idsource);
148     if (ifix < 0)
149       error->all(FLERR,"Fix ID for fix ablate does not exist");
150     if (modify->fix[ifix]->per_grid_flag == 0)
151       error->all(FLERR,"Fix ablate fix does not calculate per-grid values");
152     if (argindex == 0 && modify->fix[ifix]->size_per_grid_cols != 0)
153       error->all(FLERR,
154                  "Fix ablate fix does not calculate per-grid vector");
155     if (argindex && modify->fix[ifix]->size_per_grid_cols == 0)
156       error->all(FLERR,
157                  "Fix ablate fix does not calculate per-grid array");
158     if (argindex && argindex > modify->fix[ifix]->size_per_grid_cols)
159       error->all(FLERR,"Fix ablate fix array is accessed out-of-range");
160     if (nevery % modify->fix[ifix]->per_grid_freq)
161       error->all(FLERR,
162                  "Fix for fix ablate not computed at compatible time");
163 
164   } else if (which == VARIABLE) {
165     ivariable = input->variable->find(idsource);
166     if (ivariable < 0)
167       error->all(FLERR,"Could not find fix ablate variable name");
168     if (input->variable->grid_style(ivariable) == 0)
169       error->all(FLERR,"Fix ablate variable is not grid-style variable");
170   }
171 
172   // this fix produces a per-grid array and a scalar
173 
174   dim = domain->dimension;
175 
176   per_grid_flag = 1;
177   if (dim == 2) size_per_grid_cols = 4;
178   else size_per_grid_cols = 8;
179   per_grid_freq = 1;
180   gridmigrate = 1;
181 
182   scalar_flag = 1;
183   vector_flag = 1;
184   size_vector = 2;
185   global_freq = 1;
186   sum_delta = 0.0;
187   ndelete = 0;
188 
189   storeflag = 0;
190   array_grid = cvalues = NULL;
191   tvalues = NULL;
192   ncorner = size_per_grid_cols;
193 
194   // local storage
195 
196   ixyz = NULL;
197   mcflags = NULL;
198   celldelta = NULL;
199   cdelta = NULL;
200   cdelta_ghost = NULL;
201   numsend = NULL;
202   maxgrid = maxghost = 0;
203 
204   proclist = NULL;
205   locallist = NULL;
206   maxsend = 0;
207 
208   sbuf = NULL;
209   maxbuf = 0;
210 
211   vbuf = NULL;
212   maxvar = 0;
213 
214   ms = NULL;
215   mc = NULL;
216 
217   // RNG for random decrements
218   // for now, use same RNG on every proc
219   // uncomment two lines if want to change that
220   // b/c set_delta_random() is decrementing the same no matter who owns a cell
221 
222   random = NULL;
223   if (which == RANDOM) {
224     random = new RanKnuth(update->ranmaster->uniform());
225     //double seed = update->ranmaster->uniform();
226     //random->reset(seed,comm->me,100);
227   }
228 
229   // nvalid = next step on which end_of_step does something
230   // add nvalid to all computes that store invocation times
231   // since don't know a priori which are invoked by this fix
232   // once in end_of_step() can set timestep for ones actually invoked
233 
234   if (nevery) {
235     bigint nvalid = (update->ntimestep/nevery)*nevery + nevery;
236     modify->addstep_compute_all(nvalid);
237   }
238 }
239 
240 /* ---------------------------------------------------------------------- */
241 
~FixAblate()242 FixAblate::~FixAblate()
243 {
244   delete [] idsource;
245   memory->destroy(cvalues);
246   memory->destroy(tvalues);
247 
248   memory->destroy(ixyz);
249   memory->destroy(mcflags);
250   memory->destroy(celldelta);
251   memory->destroy(cdelta);
252   memory->destroy(cdelta_ghost);
253   memory->destroy(numsend);
254 
255   memory->destroy(proclist);
256   memory->destroy(locallist);
257 
258   memory->destroy(sbuf);
259   memory->destroy(vbuf);
260 
261   delete ms;
262   delete mc;
263 
264   delete random;
265 }
266 
267 /* ---------------------------------------------------------------------- */
268 
setmask()269 int FixAblate::setmask()
270 {
271   int mask = 0;
272   if (nevery) mask |= END_OF_STEP;
273   return mask;
274 }
275 
276 /* ----------------------------------------------------------------------
277    store grid corner point and type values in cvalues and tvalues
278    then create implicit surfaces
279    called by ReadIsurf when corner point grid is read in
280 ------------------------------------------------------------------------- */
281 
store_corners(int nx_caller,int ny_caller,int nz_caller,double * cornerlo_caller,double * xyzsize_caller,double ** cvalues_caller,int * tvalues_caller,double thresh_caller,char * sgroupID,int pushflag)282 void FixAblate::store_corners(int nx_caller, int ny_caller, int nz_caller,
283                               double *cornerlo_caller, double *xyzsize_caller,
284                               double **cvalues_caller, int *tvalues_caller,
285                               double thresh_caller, char *sgroupID, int pushflag)
286 {
287   storeflag = 1;
288 
289   nx = nx_caller;
290   ny = ny_caller;
291   nz = nz_caller;
292   cornerlo[0] = cornerlo_caller[0];
293   cornerlo[1] = cornerlo_caller[1];
294   cornerlo[2] = cornerlo_caller[2];
295   xyzsize[0] = xyzsize_caller[0];
296   xyzsize[1] = xyzsize_caller[1];
297   xyzsize[2] = xyzsize_caller[2];
298   thresh = thresh_caller;
299 
300   tvalues_flag = 0;
301   if (tvalues_caller) tvalues_flag = 1;
302 
303   if (sgroupID) {
304     int sgroup = surf->find_group(sgroupID);
305     if (sgroup < 0) sgroup = surf->add_group(sgroupID);
306     sgroupbit = surf->bitmask[sgroup];
307   } else sgroupbit = 0;
308 
309   // allocate per-grid cell data storage
310 
311   Grid::ChildCell *cells = grid->cells;
312   Grid::ChildInfo *cinfo = grid->cinfo;
313   Grid::SplitInfo *sinfo = grid->sinfo;
314   nglocal = grid->nlocal;
315 
316   grow_percell(0);
317 
318   // copy caller values into local values of FixAblate
319 
320   for (int icell = 0; icell < nglocal; icell++) {
321     for (int m = 0; m < ncorner; m++)
322       cvalues[icell][m] = cvalues_caller[icell][m];
323     if (tvalues_flag) tvalues[icell] = tvalues_caller[icell];
324   }
325 
326   // set ix,iy,iz indices from 1 to Nxyz for each of my owned grid cells
327   // same logic as ReadIsurf::create_hash()
328 
329   for (int i = 0; i < nglocal; i++)
330     ixyz[i][0] = ixyz[i][1] = ixyz[i][2] = 0;
331 
332   for (int icell = 0; icell < nglocal; icell++) {
333     if (!(cinfo[icell].mask & groupbit)) continue;
334     if (cells[icell].nsplit <= 0) continue;
335 
336     ixyz[icell][0] =
337       static_cast<int> ((cells[icell].lo[0]-cornerlo[0]) / xyzsize[0] + 0.5) + 1;
338     ixyz[icell][1] =
339       static_cast<int> ((cells[icell].lo[1]-cornerlo[1]) / xyzsize[1] + 0.5) + 1;
340     ixyz[icell][2] =
341       static_cast<int> ((cells[icell].lo[2]-cornerlo[2]) / xyzsize[2] + 0.5) + 1;
342   }
343 
344   // push corner pt values that are fully external/internal to 0 or 255
345 
346   if (pushflag) push_lohi();
347   epsilon_adjust();
348 
349   // create marching squares/cubes classes, now that have group & threshold
350 
351   if (dim == 2) ms = new MarchingSquares(sparta,igroup,thresh);
352   else mc = new MarchingCubes(sparta,igroup,thresh);
353 
354   // create implicit surfaces
355 
356   create_surfs(1);
357 }
358 
359 /* ---------------------------------------------------------------------- */
360 
init()361 void FixAblate::init()
362 {
363   if (!storeflag)
364     error->all(FLERR,"Fix ablate corner point values not stored");
365 
366   if (which == COMPUTE) {
367     icompute = modify->find_compute(idsource);
368     if (icompute < 0)
369       error->all(FLERR,"Compute ID for fix ablate does not exist");
370   } else if (which == FIX) {
371     ifix = modify->find_fix(idsource);
372     if (ifix < 0)
373       error->all(FLERR,"Fix ID for fix ablate does not exist");
374   } else if (which == VARIABLE) {
375     ivariable = input->variable->find(idsource);
376     if (ivariable < 0)
377       error->all(FLERR,"Variable ID for fix ablate does not exist");
378   }
379 
380   // reallocate per-grid data if necessary
381 
382   nglocal = grid->nlocal;
383   grow_percell(0);
384 }
385 
386 /* ---------------------------------------------------------------------- */
387 
end_of_step()388 void FixAblate::end_of_step()
389 {
390   // set per-cell delta vector randomly or from compute/fix source
391 
392   if (which == RANDOM) set_delta_random();
393   else set_delta();
394 
395   // decrement corner point values for each owned grid cell
396 
397   decrement();
398 
399   // sync shared corner point values
400 
401   sync();
402   epsilon_adjust();
403 
404   // re-create implicit surfs
405 
406   create_surfs(0);
407 }
408 
409 /* ---------------------------------------------------------------------- */
410 
create_surfs(int outflag)411 void FixAblate::create_surfs(int outflag)
412 {
413   // DEBUG
414   // store copy of last ablation's per-cell MC flags before a new ablation
415 
416   int **mcflags_old = mcflags;
417   memory->create(mcflags,maxgrid,4,"ablate:mcflags");
418   for (int i = 0; i < maxgrid; i++)
419     mcflags[i][0] = mcflags[i][1] = mcflags[i][2] = mcflags[i][3] = -1;
420 
421   // sort existing particles since may be clearing split cells
422 
423   if (!particle->sorted) particle->sort();
424 
425   // reassign particles in sub cells to all be in parent split cell
426 
427   if (grid->nsplitlocal) {
428     Grid::ChildCell *cells = grid->cells;
429     for (int icell = 0; icell < nglocal; icell++)
430       if (cells[icell].nsplit > 1)
431 	grid->combine_split_cell_particles(icell,1);
432   }
433 
434   // call clear_surf before create new surfs, so cell/corner flags are all set
435 
436   grid->unset_neighbors();
437   grid->remove_ghosts();
438   grid->clear_surf();
439   surf->clear();
440 
441   // perform Marching Squares/Cubes to create new implicit surfs
442   // cvalues = corner point values
443   // tvalues = surf type for surfs in each grid cell
444 
445   if (dim == 2) ms->invoke(cvalues,tvalues);
446   else mc->invoke(cvalues,tvalues,mcflags);
447 
448   // set surf->nsurf and surf->nown
449 
450   surf->nown = surf->nlocal;
451   bigint nlocal = surf->nlocal;
452   MPI_Allreduce(&nlocal,&surf->nsurf,1,MPI_SPARTA_BIGINT,MPI_SUM,world);
453 
454   // output extent of implicit surfs, some may be tiny
455 
456   if (outflag) {
457     if (dim == 2) surf->output_extent(0);
458     else surf->output_extent(0);
459   }
460 
461   // compute normals of new surfs
462 
463   if (dim == 2) surf->compute_line_normal(0);
464   else surf->compute_tri_normal(0);
465 
466   // MC->cleanup() checks for consistent triangles on grid cell faces
467   // needs to come after normals are computed
468   // it requires neighbor indices and ghost cell info
469   // so first acquire ghosts (which will also grab surfs),
470   //   then remove ghost surfs and ghost grid cells again
471 
472   if (dim == 3) {
473     grid->acquire_ghosts(0);
474     grid->reset_neighbors();
475     mc->cleanup();
476     surf->remove_ghosts();
477     grid->unset_neighbors();
478     grid->remove_ghosts();
479   }
480 
481   // assign optional surf group to masks of new surfs
482 
483   if (sgroupbit) {
484     int nsurf = surf->nlocal;
485     if (dim == 3) {
486       Surf::Tri *tris = surf->tris;
487       for (int i = 0; i < nsurf; i++) tris[i].mask |= sgroupbit;
488     } else {
489       Surf::Line *lines = surf->lines;
490       for (int i = 0; i < nsurf; i++) lines[i].mask |= sgroupbit;
491     }
492   }
493 
494   // assign surf collision/reaction models to newly created surfs
495   // this assignment can be made in input script via surf_modify
496   //   after implicit surfs are created
497   // for active ablation, must be re-assigned at every ablation atep
498   // for now just assume all surfs are assigned to first collide/react model
499   // NOTE: need a more flexible way to do this
500 
501   int nslocal = surf->nlocal;
502 
503   if (dim == 2) {
504     Surf::Line *lines = surf->lines;
505     if (surf->nsc)
506       for (int i = 0; i < nslocal; i++)
507         lines[i].isc = 0;
508     if (surf->nsr)
509       for (int i = 0; i < nslocal; i++)
510         lines[i].isr = 0;
511   } else {
512     Surf::Tri *tris = surf->tris;
513     if (surf->nsc)
514       for (int i = 0; i < nslocal; i++)
515         tris[i].isc = 0;
516     if (surf->nsr)
517       for (int i = 0; i < nslocal; i++)
518         tris[i].isr = 0;
519   }
520 
521   // watertight check can be done before surfs are mapped to grid cells
522 
523   if (dim == 2) surf->check_watertight_2d();
524   else surf->check_watertight_3d();
525 
526   // if no surfs created, use clear_surf to set all celltypes = OUTSIDE
527 
528   if (surf->nsurf == 0) {
529     surf->exist = 0;
530     grid->clear_surf();
531   }
532 
533   // -----------------------
534   // map surfs to grid cells
535   // -----------------------
536 
537   // surfs are already assigned to grid cells
538   // create split cells due to new surfs
539 
540   grid->surf2grid_implicit(1,outflag);
541 
542   // re-setup grid ghosts and neighbors
543 
544   grid->setup_owned();
545   grid->acquire_ghosts();
546   grid->reset_neighbors();
547   comm->reset_neighbors();
548 
549   // flag cells and corners as OUTSIDE or INSIDE
550 
551   grid->set_inout();
552   grid->type_check(outflag);
553 
554   // reassign particles in a split cell to sub cell owner
555   // particles are unsorted afterwards, within new sub cells
556 
557   if (grid->nsplitlocal) {
558     Grid::ChildCell *cells = grid->cells;
559     for (int icell = 0; icell < nglocal; icell++)
560       if (cells[icell].nsplit > 1)
561 	grid->assign_split_cell_particles(icell);
562     particle->sorted = 0;
563   }
564 
565   // notify all classes that store per-grid data that grid has changed
566 
567   grid->notify_changed();
568 
569   // ------------------------------------------------------------------------
570   // DEBUG - should not have to do any of this once marching cubes is perfect
571   // only necessary for 3d
572 
573   if (dim == 2) {
574     memory->destroy(mcflags_old);
575     return;
576   }
577 
578   // DEBUG - if this line is uncommented, code will do delete no particles
579   //         eventually this should work
580 
581   // if (dim == 3) {
582   //   memory->destroy(mcflags_old);
583   //   return;
584   // }
585 
586   // DEBUG - remove all particles
587   // if these lines are uncommented, all particles are wiped out
588 
589   // particle->nlocal = 0;
590   // memory->destroy(mcflags_old);
591   // return;
592 
593   // DEBUG - remove only the particles that are inside the surfs
594   //         after ablation
595   // similar code as in fix grid/check
596 
597   Cut3d *cut3d = new Cut3d(sparta);
598   Cut2d *cut2d = NULL;
599 
600   Grid::ChildCell *cells = grid->cells;
601   Grid::ChildInfo *cinfo = grid->cinfo;
602   Grid::SplitInfo *sinfo = grid->sinfo;
603   Particle::OnePart *particles = particle->particles;
604   int pnlocal = particle->nlocal;
605 
606   int ncount;
607   int icell,splitcell,subcell,flag;
608   double *x;
609 
610   ncount = 0;
611   for (int i = 0; i < pnlocal; i++) {
612     particles[i].flag = PKEEP;
613     icell = particles[i].icell;
614     if (cells[icell].nsurf == 0) continue;
615 
616     int mcell = icell;
617     x = particles[i].x;
618     flag = 1;
619     if (cells[icell].nsplit <= 0) {
620       mcell = splitcell = sinfo[cells[icell].isplit].icell;
621       flag = grid->outside_surfs(splitcell,x,cut3d,cut2d);
622     } else flag = grid->outside_surfs(icell,x,cut3d,cut2d);
623 
624     if (!flag) {
625       particles[i].flag = PDISCARD;
626       // DEBUG - print message about MC flags for cell of deleted particle
627       /*
628       printf("INSIDE PART: me %d id %d coords %g %g %g "
629              "cellID %d celltype %d nsplit %d MCflags old %d %d %d %d "
630              "MCflags now %d %d %d %d corners %g %g %g %g %g %g %g %g\n",
631              comm->me,particles[i].id,x[0],x[1],x[2],
632              cells[mcell].id,cinfo[mcell].type,cells[mcell].nsplit,
633              mcflags_old[mcell][0],
634              mcflags_old[mcell][1],
635              mcflags_old[mcell][2],
636              mcflags_old[mcell][3],
637              mcflags[mcell][0],
638              mcflags[mcell][1],
639              mcflags[mcell][2],
640              mcflags[mcell][3],
641              cvalues[mcell][0],
642              cvalues[mcell][1],
643              cvalues[mcell][2],
644              cvalues[mcell][3],
645              cvalues[mcell][4],
646              cvalues[mcell][5],
647              cvalues[mcell][6],
648              cvalues[mcell][7]);
649       */
650       ncount++;
651     }
652   }
653 
654   delete cut3d;
655   memory->destroy(mcflags_old);
656 
657   // compress out the deleted particles
658   // NOTE: if end up keeping this section, need logic for custom particle vectors
659   //       see Particle::compress_rebalance()
660 
661   int nbytes = sizeof(Particle::OnePart);
662 
663   int i = 0;
664   while (i < pnlocal) {
665     if (particles[i].flag == PDISCARD) {
666       memcpy(&particles[i],&particles[pnlocal-1],nbytes);
667       pnlocal--;
668     } else i++;
669   }
670 
671   MPI_Allreduce(&ncount,&ndelete,1,MPI_INT,MPI_SUM,world);
672 
673   particle->nlocal = pnlocal;
674   particle->sorted = 0;
675 }
676 
677 /* ----------------------------------------------------------------------
678    set per-cell delta vector randomly
679    celldelta = random integer between 0 and maxrandom
680    scale = fraction of cells that are decremented
681 ------------------------------------------------------------------------- */
682 
set_delta_random()683 void FixAblate::set_delta_random()
684 {
685   Grid::ChildCell *cells = grid->cells;
686   Grid::ChildInfo *cinfo = grid->cinfo;
687 
688   // enforce same decrement no matter who owns which cells
689   // NOTE: could change this at some point, use differnet RNG for each proc
690 
691   if (!grid->hashfilled) grid->rehash();
692   Grid::MyHash *hash = grid->hash;
693   cellint cellID;
694   int rn2,icell;
695   double rn1;
696   for (int i = 0; i < grid->ncell; i++) {
697     rn1 = random->uniform();
698     rn2 = static_cast<int> (random->uniform()*maxrandom) + 1.0;
699     cellID = i+1;
700     if (hash->find(cellID) == hash->end()) continue;
701     icell = (*hash)[cellID];
702     if (icell >= nglocal) continue;     // ghost cell
703     if (rn1 > scale) celldelta[icell] = 0.0;
704     else celldelta[icell] = rn2;
705   }
706 
707   // total decrement for output
708 
709   double sum = 0.0;
710   for (int icell = 0; icell < nglocal; icell++) {
711     if (!(cinfo[icell].mask & groupbit)) continue;
712     if (cells[icell].nsplit <= 0) continue;
713     sum += celldelta[icell];
714   }
715 
716   MPI_Allreduce(&sum,&sum_delta,1,MPI_DOUBLE,MPI_SUM,world);
717 }
718 
719 /* ----------------------------------------------------------------------
720    set per-cell delta vector from compute/fix/variable source
721    celldelta = nevery * scale * source-value
722    // NOTE: how does this work for split cells? should only do parent split?
723 ------------------------------------------------------------------------- */
724 
set_delta()725 void FixAblate::set_delta()
726 {
727   int i;
728 
729   double prefactor = nevery*scale;
730 
731   // compute/fix may invoke computes so wrap with clear/add
732 
733   modify->clearstep_compute();
734 
735   if (which == COMPUTE) {
736     Compute *c = modify->compute[icompute];
737 
738     if (!(c->invoked_flag & INVOKED_PER_GRID)) {
739       c->compute_per_grid();
740       c->invoked_flag |= INVOKED_PER_GRID;
741     }
742     c->post_process_isurf_grid();
743 
744     if (argindex == 0) {
745       double *cvec = c->vector_grid;
746       for (i = 0; i < nglocal; i++)
747         celldelta[i] = prefactor * cvec[i];
748     } else {
749       double **carray = c->array_grid;
750       int im1 = argindex - 1;
751       for (i = 0; i < nglocal; i++)
752         celldelta[i] = prefactor * carray[i][im1];
753     }
754 
755   } else if (which == FIX) {
756     Fix *f = modify->fix[ifix];
757 
758     if (argindex == 0) {
759       double *fvec = f->vector_grid;
760       for (i = 0; i < nglocal; i++) {
761         celldelta[i] = prefactor * fvec[i];
762       }
763     } else {
764       double **farray = f->array_grid;
765       int im1 = argindex - 1;
766       for (i = 0; i < nglocal; i++)
767         celldelta[i] = prefactor * farray[i][im1];
768     }
769 
770   } else if (which == VARIABLE) {
771     if (nglocal > maxvar) {
772       maxvar = grid->maxlocal;
773       memory->destroy(vbuf);
774       memory->create(vbuf,maxvar,"ablate:vbuf");
775     }
776 
777     input->variable->compute_grid(ivariable,vbuf,1,0);
778     for (i = 0; i < nglocal; i++)
779       celldelta[i] = prefactor * vbuf[i];
780   }
781 
782   // NOTE: this does not get invoked on step 100,
783   //   b/c needs to also be done in constructor
784   //   ditto for fix adapt?
785   //   they need nextvalid() methods like fix_ave_time
786   //   or do it how output calcs next_stats for next thermo step
787 
788   modify->addstep_compute(update->ntimestep + nevery);
789 
790   Grid::ChildCell *cells = grid->cells;
791   Grid::ChildInfo *cinfo = grid->cinfo;
792 
793   double sum = 0.0;
794   for (int icell = 0; icell < nglocal; icell++) {
795     if (!(cinfo[icell].mask & groupbit)) continue;
796     if (cells[icell].nsplit <= 0) continue;
797     sum += celldelta[icell];
798   }
799 
800   MPI_Allreduce(&sum,&sum_delta,1,MPI_DOUBLE,MPI_SUM,world);
801 }
802 
803 /* ----------------------------------------------------------------------
804    decrement corner points of each owned grid cell
805    skip cells not in group, with no surfs, and sub-cells
806    algorithm:
807      no corner pt value can be < 0.0
808      decrement smallest corner pt by full delta
809      if cannot, decrement to 0.0, decrement next smallest by remainder, etc
810 ------------------------------------------------------------------------- */
811 
decrement()812 void FixAblate::decrement()
813 {
814   Grid::ChildCell *cells = grid->cells;
815   Grid::ChildInfo *cinfo = grid->cinfo;
816 
817   int i,imin;
818   double minvalue,total;
819   double *corners;
820 
821   // total = full amount to decrement from cell
822   // cdelta[icell] = amount to decrement from each corner point of icell
823 
824   for (int icell = 0; icell < nglocal; icell++) {
825     if (!(cinfo[icell].mask & groupbit)) continue;
826     if (cells[icell].nsplit <= 0) continue;
827 
828     for (i = 0; i < ncorner; i++) cdelta[icell][i] = 0.0;
829 
830     total = celldelta[icell];
831     corners = cvalues[icell];
832     while (total > 0.0) {
833       imin = -1;
834       minvalue = 256.0;
835       for (i = 0; i < ncorner; i++) {
836         if (corners[i] > 0.0 && corners[i] < minvalue &&
837             cdelta[icell][i] == 0.0) {
838           imin = i;
839           minvalue = corners[i];
840         }
841       }
842       if (imin == -1) break;
843       if (total < corners[imin]) {
844         cdelta[icell][imin] += total;
845         total = 0.0;
846       } else {
847         cdelta[icell][imin] = corners[imin];
848         total -= corners[imin];
849       }
850     }
851   }
852 }
853 
854 /* ----------------------------------------------------------------------
855    sync all copies of corner points values for all owned grid cells
856    algorithm:
857      comm my cdelta values that are shared by neighbor
858      each corner point is shared by N cells, less on borders
859      dsum = sum of decrements to that point by all N cells
860      newvalue = MAX(oldvalue-dsum,0)
861    all N copies of corner pt are set to newvalue
862      in numerically consistent manner (same order of operations)
863 ------------------------------------------------------------------------- */
864 
sync()865 void FixAblate::sync()
866 {
867   int i,ix,iy,iz,jx,jy,jz,ixfirst,iyfirst,izfirst,jcorner;
868   int icell,jcell;
869   double total;
870 
871   comm_neigh_corners(CDELTA);
872 
873   // perform update of corner pts for all my owned grid cells
874   //   using contributions from all cells that share the corner point
875   // insure order of numeric operations will give exact same answer
876   //   for all Ncorner duplicates of a corner point (stored by other cells)
877 
878   Grid::ChildCell *cells = grid->cells;
879   Grid::ChildInfo *cinfo = grid->cinfo;
880 
881   for (icell = 0; icell < nglocal; icell++) {
882     if (!(cinfo[icell].mask & groupbit)) continue;
883     if (cells[icell].nsplit <= 0) continue;
884 
885     ix = ixyz[icell][0];
886     iy = ixyz[icell][1];
887     iz = ixyz[icell][2];
888 
889     // loop over corner points
890 
891     for (i = 0; i < ncorner; i++) {
892 
893       // ixyz first = offset from icell of lower left cell of 2x2x2 stencil
894       //              that shares the Ith corner point
895 
896       ixfirst = (i % 2) - 1;
897       iyfirst = (i/2 % 2) - 1;
898       if (dim == 2) izfirst = 0;
899       else izfirst = (i / 4) - 1;
900 
901       // loop over 2x2x2 stencil of cells that share the corner point
902       // also works for 2d, since izfirst = 0
903 
904       total = 0.0;
905       jcorner = ncorner;
906 
907       for (jz = izfirst; jz <= izfirst+1; jz++) {
908         for (jy = iyfirst; jy <= iyfirst+1; jy++) {
909           for (jx = ixfirst; jx <= ixfirst+1; jx++) {
910             jcorner--;
911 
912             // check if neighbor cell is within bounds of ablate grid
913 
914             if (ix+jx < 1 || ix+jx > nx) continue;
915             if (iy+jy < 1 || iy+jy > ny) continue;
916             if (iz+jz < 1 || iz+jz > nz) continue;
917 
918             // jcell = local index of (jx,jy,jz) neighbor cell of icell
919 
920             jcell = walk_to_neigh(icell,jx,jy,jz);
921 
922             // update total with one corner point of jcell
923             // jcorner descends from ncorner
924 
925             if (jcell < nglocal) total += cdelta[jcell][jcorner];
926             else total += cdelta_ghost[jcell-nglocal][jcorner];
927           }
928         }
929       }
930 
931       if (total > cvalues[icell][i]) cvalues[icell][i] = 0.0;
932       else cvalues[icell][i] -= total;
933     }
934   }
935 }
936 
937 /* ----------------------------------------------------------------------
938    adjust corner point values by epsilon of too close to threshold
939    to avoid creating tiny or zero-size surface elements
940 ------------------------------------------------------------------------- */
941 
epsilon_adjust()942 void FixAblate::epsilon_adjust()
943 {
944   int i,icell;
945 
946   // insure no corner point is within EPSILON of threshold
947   // if so, set it to threshold - EPSILON
948 
949   Grid::ChildCell *cells = grid->cells;
950   Grid::ChildInfo *cinfo = grid->cinfo;
951 
952   for (icell = 0; icell < nglocal; icell++) {
953     if (!(cinfo[icell].mask & groupbit)) continue;
954     if (cells[icell].nsplit <= 0) continue;
955 
956     for (i = 0; i < ncorner; i++)
957       if (fabs(cvalues[icell][i]-thresh) < EPSILON)
958         cvalues[icell][i] = thresh - EPSILON;
959   }
960 }
961 
962 /* ----------------------------------------------------------------------
963    push corner points value to 0 or 255
964      if all surrounding neighs are below or above threshold
965      do this for all N copies of an affected corner point
966    algorithm:
967      comm my cdelta values that are shared by neighbor
968      each corner point is shared by N cells, less on borders
969      dsum = sum of decrements to that point by all N cells
970      newvalue = MAX(oldvalue-dsum,0)
971    all N copies of corner pt are set to newvalue
972      in numerically consistent manner (same order of operations)
973 ------------------------------------------------------------------------- */
974 
push_lohi()975 void FixAblate::push_lohi()
976 {
977   int i,ix,iy,iz,ixfirst,iyfirst,izfirst,jx,jy,jz;
978   int icell,jcell,jcorner,pushflag;
979 
980   comm_neigh_corners(CVALUE);
981 
982   // perform push of corner pt values for all my owned grid cells
983   //   by checking corner pt values of all cells that share same corner pt
984   // if all surrounding corner pts are > threshold, push corner pt -> 255
985   // if all surrounding corner pts are < threshold, push corner pt -> 0
986 
987   Grid::ChildCell *cells = grid->cells;
988   Grid::ChildInfo *cinfo = grid->cinfo;
989 
990   int plo = 0;
991   int phi = 0;
992 
993   for (icell = 0; icell < nglocal; icell++) {
994     if (!(cinfo[icell].mask & groupbit)) continue;
995     if (cells[icell].nsplit <= 0) continue;
996 
997     ix = ixyz[icell][0];
998     iy = ixyz[icell][1];
999     iz = ixyz[icell][2];
1000 
1001     // loop over corner points
1002 
1003     for (i = 0; i < ncorner; i++) {
1004 
1005       // flag = -1 if corner pt value < threshold, +1 if > threshold
1006 
1007       if (cvalues[icell][i] < thresh) pushflag = -1;
1008       else if (cvalues[icell][i] > thresh) pushflag = 1;
1009       else continue;
1010 
1011       // ixyz first = offset from icell of lower left cell of 2x2x2 stencil
1012       //              that shares the Ith corner point
1013 
1014       ixfirst = (i % 2) - 1;
1015       iyfirst = (i/2 % 2) - 1;
1016       if (dim == 2) izfirst = 0;
1017       else izfirst = (i / 4) - 1;
1018 
1019       // loop over 2x2x2 stencil of cells that share the corner point
1020       // also works for 2d, since izfirst = 0
1021 
1022       jcorner = ncorner;
1023 
1024       for (jz = izfirst; jz <= izfirst+1; jz++) {
1025         for (jy = iyfirst; jy <= iyfirst+1; jy++) {
1026           for (jx = ixfirst; jx <= ixfirst+1; jx++) {
1027             jcorner--;
1028 
1029             // check if neighbor cell is within bounds of ablate grid
1030 
1031             if (ix+jx < 1 || ix+jx > nx) continue;
1032             if (iy+jy < 1 || iy+jy > ny) continue;
1033             if (iz+jz < 1 || iz+jz > nz) continue;
1034 
1035             // jcell = local index of (jx,jy,jz) neighbor cell of icell
1036 
1037             jcell = walk_to_neigh(icell,jx,jy,jz);
1038 
1039             // set pushflag to 0 if jcorner pt of jcell is not
1040             //   on same side of threshold as icorner or icell
1041 
1042             if (jcell < nglocal) {
1043               if ((pushflag == -1 && cvalues[jcell][jcorner] > thresh) ||
1044                   (pushflag == 1 && cvalues[jcell][jcorner] < thresh))
1045                 pushflag = 0;
1046             } else {
1047               if ((pushflag == -1 && cdelta_ghost[jcell-nglocal][jcorner] >
1048                    thresh) ||
1049                   (pushflag == 1 && cdelta_ghost[jcell-nglocal][jcorner] <
1050                    thresh))
1051                 pushflag = 0;
1052             }
1053           }
1054         }
1055       }
1056 
1057       // DEBUG OFF
1058       if (pushflag == -1) cvalues[icell][i] = 0;
1059       else if (pushflag == 1) cvalues[icell][i] = 255;
1060 
1061       if (pushflag == -1) plo++;
1062       else if (pushflag == 1) phi++;
1063     }
1064   }
1065 
1066   bigint bplo = plo;
1067   bigint bphi = phi;
1068   bigint ploall,phiall;
1069   MPI_Allreduce(&bplo,&ploall,1,MPI_SPARTA_BIGINT,MPI_SUM,world);
1070   MPI_Allreduce(&bphi,&phiall,1,MPI_SPARTA_BIGINT,MPI_SUM,world);
1071 
1072   if (me == 0) {
1073     if (screen)
1074       fprintf(screen,"  " BIGINT_FORMAT " " BIGINT_FORMAT
1075               " pushed corner pt values\n",ploall,phiall);
1076     if (logfile)
1077       fprintf(logfile,"  " BIGINT_FORMAT " " BIGINT_FORMAT
1078               " pushed corner pt values\n",ploall,phiall);
1079   }
1080 }
1081 
1082 /* ----------------------------------------------------------------------
1083    comm my cdelta values that are shared by neighbor cells
1084    each corner point is shared by N cells, less on borders
1085    done via irregular comm
1086 ------------------------------------------------------------------------- */
1087 
comm_neigh_corners(int which)1088 void FixAblate::comm_neigh_corners(int which)
1089 {
1090   int i,j,m,n,ix,iy,iz,ixfirst,iyfirst,izfirst,jx,jy,jz;
1091   int icell,ifirst,jcell,proc,ilocal;
1092 
1093   Grid::ChildCell *cells = grid->cells;
1094   Grid::ChildInfo *cinfo = grid->cinfo;
1095 
1096   // make list of datums to send to neighbor procs
1097   // 8 or 26 cells surrounding icell need icell's cdelta info
1098   // but only if they are owned by a neighbor proc
1099   // insure icell is only sent once to same neighbor proc
1100   // also set proclist and locallist for each sent datum
1101 
1102   int nsend = 0;
1103 
1104   for (icell = 0; icell < nglocal; icell++) {
1105     if (!(cinfo[icell].mask & groupbit)) continue;
1106     if (cells[icell].nsplit <= 0) continue;
1107 
1108     ix = ixyz[icell][0];
1109     iy = ixyz[icell][1];
1110     iz = ixyz[icell][2];
1111     ifirst = nsend;
1112 
1113     // loop over 3x3x3 stencil of neighbor cells centered on icell
1114 
1115     for (jz = -1; jz <= 1; jz++) {
1116       for (jy = -1; jy <= 1; jy++) {
1117         for (jx = -1; jx <= 1; jx++) {
1118 
1119           // skip neigh = self
1120 
1121           if (jx == 0 && jy == 0 && jz == 0) continue;
1122 
1123           // check if neighbor cell is within bounds of ablate grid
1124 
1125           if (ix+jx < 1 || ix+jx > nx) continue;
1126           if (iy+jy < 1 || iy+jy > ny) continue;
1127           if (iz+jz < 1 || iz+jz > nz) continue;
1128 
1129           // jcell = local index of (jx,jy,jz) neighbor cell of icell
1130 
1131           jcell = walk_to_neigh(icell,jx,jy,jz);
1132 
1133           // add a send list entry of icell to proc != me if haven't already
1134 
1135           proc = cells[jcell].proc;
1136           if (proc != me) {
1137             for (j = ifirst; j < nsend; j++)
1138               if (proc == proclist[j]) break;
1139             if (j == nsend) {
1140               if (nsend == maxsend) grow_send();
1141               proclist[nsend] = proc;
1142               // NOTE: change locallist to another name
1143               // NOTE: what about cellint vs int
1144               locallist[nsend++] = cells[icell].id;   // no longer an int
1145             }
1146           }
1147         }
1148       }
1149     }
1150 
1151     // # of neighbor procs to send icell to
1152 
1153     numsend[icell] = nsend - ifirst;
1154   }
1155 
1156   // realloc sbuf if necessary
1157   // ncomm = ilocal + Ncorner values
1158 
1159   int ncomm = 1 + ncorner;
1160 
1161   if (nsend*ncomm > maxbuf) {
1162     memory->destroy(sbuf);
1163     maxbuf = nsend*ncomm;
1164     memory->create(sbuf,maxbuf,"ablate:sbuf");
1165   }
1166 
1167   // pack datums to send
1168   // datum = ilocal of neigh cell on other proc + Ncorner values
1169 
1170   nsend = 0;
1171   m = 0;
1172 
1173   for (icell = 0; icell < nglocal; icell++) {
1174     if (!(cinfo[icell].mask & groupbit)) continue;
1175     if (cells[icell].nsplit <= 0) continue;
1176 
1177     n = numsend[icell];
1178     for (i = 0; i < n; i++) {
1179       sbuf[m++] = locallist[nsend];
1180       if (which == CDELTA) {
1181         for (j = 0; j < ncorner; j++)
1182           sbuf[m++] = cdelta[icell][j];
1183       } else if (which == CVALUE) {
1184         for (j = 0; j < ncorner; j++)
1185           sbuf[m++] = cvalues[icell][j];
1186       }
1187       nsend++;
1188     }
1189   }
1190 
1191   // perform irregular neighbor comm
1192   // Comm class manages rbuf memory
1193 
1194   double *rbuf;
1195   int nrecv = comm->irregular_uniform_neighs(nsend,proclist,(char *) sbuf,
1196                                              ncomm*sizeof(double),
1197                                              (char **) &rbuf);
1198 
1199   // realloc cdelta_ghost if necessary
1200 
1201   if (grid->nghost > maxghost) {
1202     memory->destroy(cdelta_ghost);
1203     maxghost = grid->nghost;
1204     memory->create(cdelta_ghost,maxghost,ncorner,"ablate:cdelta_ghost");
1205   }
1206 
1207   // unpack received data into cdelta_ghost = ghost cell corner points
1208 
1209   // NOTE: need to check if hashfilled
1210   cellint cellID;
1211   Grid::MyHash *hash = grid->hash;
1212 
1213   m = 0;
1214   for (i = 0; i < nrecv; i++) {
1215     cellID = static_cast<cellint> (rbuf[m++]);   // NOTE: need ubuf logic
1216     ilocal = (*hash)[cellID];
1217     icell = ilocal - nglocal;
1218     for (j = 0; j < ncorner; j++)
1219       cdelta_ghost[icell][j] = rbuf[m++];
1220   }
1221 }
1222 
1223 /* ----------------------------------------------------------------------
1224    walk to neighbor of icell, offset by (jx,jy,jz)
1225    walk first by x, then by y, last by z
1226    return jcell = local index of neighbor cell
1227 ------------------------------------------------------------------------- */
1228 
walk_to_neigh(int icell,int jx,int jy,int jz)1229 int FixAblate::walk_to_neigh(int icell, int jx, int jy, int jz)
1230 {
1231   Grid::ChildCell *cells = grid->cells;
1232 
1233   int jcell = icell;
1234 
1235   if (jx < 0) {
1236     if (grid->neigh_decode(cells[jcell].nmask,XLO) != NCHILD)
1237       error->one(FLERR,"Fix ablate walk to neighbor cell failed");
1238     jcell = cells[jcell].neigh[0];
1239   } else if (jx > 0) {
1240     if (grid->neigh_decode(cells[jcell].nmask,XHI) != NCHILD)
1241       error->one(FLERR,"Fix ablate walk to neighbor cell failed");
1242     jcell = cells[jcell].neigh[1];
1243   }
1244 
1245   if (jy < 0) {
1246     if (grid->neigh_decode(cells[jcell].nmask,YLO) != NCHILD)
1247       error->one(FLERR,"Fix ablate walk to neighbor cell failed");
1248     jcell = cells[jcell].neigh[2];
1249   } else if (jy > 0) {
1250     if (grid->neigh_decode(cells[jcell].nmask,YHI) != NCHILD)
1251       error->one(FLERR,"Fix ablate walk to neighbor cell failed");
1252     jcell = cells[jcell].neigh[3];
1253   }
1254 
1255   if (jz < 0) {
1256     if (grid->neigh_decode(cells[jcell].nmask,ZLO) != NCHILD)
1257       error->one(FLERR,"Fix ablate walk to neighbor cell failed");
1258     jcell = cells[jcell].neigh[4];
1259   } else if (jz > 0) {
1260     if (grid->neigh_decode(cells[jcell].nmask,ZHI) != NCHILD)
1261       error->one(FLERR,"Fix ablate walk to neighbor cell failed");
1262     jcell = cells[jcell].neigh[5];
1263   }
1264 
1265   return jcell;
1266 }
1267 
1268 /* ----------------------------------------------------------------------
1269    pack icell values for per-cell arrays into buf
1270    if icell is a split cell, also pack all sub cell values
1271    return byte count of amount packed
1272    if memflag, only return count, do not fill buf
1273 ------------------------------------------------------------------------- */
1274 
pack_grid_one(int icell,char * buf,int memflag)1275 int FixAblate::pack_grid_one(int icell, char *buf, int memflag)
1276 {
1277   char *ptr = buf;
1278   Grid::ChildCell *cells = grid->cells;
1279   Grid::SplitInfo *sinfo = grid->sinfo;
1280 
1281   if (memflag) memcpy(ptr,cvalues[icell],ncorner*sizeof(double));
1282   ptr += ncorner*sizeof(double);
1283 
1284   if (tvalues_flag) {
1285     if (memflag) {
1286       double *dbuf = (double *) ptr;
1287       dbuf[0] = tvalues[icell];
1288     }
1289     ptr += sizeof(double);
1290   }
1291 
1292   if (memflag) {
1293     double *dbuf = (double *) ptr;
1294     dbuf[0] = ixyz[icell][0];
1295     dbuf[1] = ixyz[icell][1];
1296     dbuf[2] = ixyz[icell][2];
1297   }
1298   ptr += 3*sizeof(double);
1299 
1300   // DEBUG
1301 
1302   if (memflag) {
1303     double *dbuf = (double *) ptr;
1304     dbuf[0] = mcflags[icell][0];
1305     dbuf[1] = mcflags[icell][1];
1306     dbuf[2] = mcflags[icell][2];
1307     dbuf[3] = mcflags[icell][3];
1308   }
1309   ptr += 4*sizeof(double);
1310 
1311   if (cells[icell].nsplit > 1) {
1312     int isplit = cells[icell].isplit;
1313     int nsplit = cells[icell].nsplit;
1314     for (int i = 0; i < nsplit; i++) {
1315       int jcell = sinfo[isplit].csubs[i];
1316       if (memflag) memcpy(ptr,cvalues[jcell],ncorner*sizeof(double));
1317       ptr += ncorner*sizeof(double);
1318     }
1319   }
1320 
1321   return ptr-buf;
1322 }
1323 
1324 /* ----------------------------------------------------------------------
1325    unpack icell values for per-cell array from buf
1326    return byte count of amount unpacked
1327 ------------------------------------------------------------------------- */
1328 
unpack_grid_one(int icell,char * buf)1329 int FixAblate::unpack_grid_one(int icell, char *buf)
1330 {
1331   char *ptr = buf;
1332   Grid::ChildCell *cells = grid->cells;
1333   Grid::SplitInfo *sinfo = grid->sinfo;
1334 
1335   grow_percell(1);
1336 
1337   memcpy(cvalues[icell],ptr,ncorner*sizeof(double));
1338   ptr += ncorner*sizeof(double);
1339 
1340   if (tvalues_flag) {
1341     double *dbuf = (double *) ptr;
1342     tvalues[icell] = static_cast<int> (dbuf[0]);
1343     ptr += sizeof(double);
1344   }
1345 
1346   double *dbuf = (double *) ptr;
1347   ixyz[icell][0] = static_cast<int> (dbuf[0]);
1348   ixyz[icell][1] = static_cast<int> (dbuf[1]);
1349   ixyz[icell][2] = static_cast<int> (dbuf[2]);
1350   ptr += 3*sizeof(double);
1351 
1352   dbuf = (double *) ptr;
1353   mcflags[icell][0] = static_cast<int> (dbuf[0]);
1354   mcflags[icell][1] = static_cast<int> (dbuf[1]);
1355   mcflags[icell][2] = static_cast<int> (dbuf[2]);
1356   mcflags[icell][3] = static_cast<int> (dbuf[3]);
1357   ptr += 4*sizeof(double);
1358 
1359   nglocal++;
1360 
1361  if (cells[icell].nsplit > 1) {
1362     int isplit = cells[icell].isplit;
1363     int nsplit = cells[icell].nsplit;
1364     grow_percell(nsplit);
1365     for (int i = 0; i < nsplit; i++) {
1366       int jcell = sinfo[isplit].csubs[i];
1367       memcpy(cvalues[jcell],ptr,ncorner*sizeof(double));
1368       ptr += ncorner*sizeof(double);
1369     }
1370     nglocal += nsplit;
1371   }
1372 
1373   return ptr-buf;
1374 }
1375 
1376 /* ----------------------------------------------------------------------
1377    copy per-cell info from Icell to Jcell
1378    called whenever a grid cell is removed from this processor's list
1379    caller checks that Icell != Jcell
1380 ------------------------------------------------------------------------- */
1381 
copy_grid_one(int icell,int jcell)1382 void FixAblate::copy_grid_one(int icell, int jcell)
1383 {
1384   memcpy(cvalues[jcell],cvalues[icell],ncorner*sizeof(double));
1385   if (tvalues_flag) tvalues[jcell] = tvalues[icell];
1386 
1387   ixyz[jcell][0] = ixyz[icell][0];
1388   ixyz[jcell][1] = ixyz[icell][1];
1389   ixyz[jcell][2] = ixyz[icell][2];
1390 
1391   mcflags[jcell][0] = mcflags[icell][0];
1392   mcflags[jcell][1] = mcflags[icell][1];
1393   mcflags[jcell][2] = mcflags[icell][2];
1394   mcflags[jcell][3] = mcflags[icell][3];
1395 }
1396 
1397 /* ----------------------------------------------------------------------
1398    add a grid cell
1399    called when a grid cell is added to this processor's list
1400    initialize values to 0.0
1401 ------------------------------------------------------------------------- */
1402 
add_grid_one()1403 void FixAblate::add_grid_one()
1404 {
1405   grow_percell(1);
1406 
1407   for (int i = 0; i < ncorner; i++) cvalues[nglocal][i] = 0.0;
1408   if (tvalues_flag) tvalues[nglocal] = 0;
1409   ixyz[nglocal][0] = 0;
1410   ixyz[nglocal][1] = 0;
1411   ixyz[nglocal][2] = 0;
1412 
1413   mcflags[nglocal][0] = -1;
1414   mcflags[nglocal][1] = -1;
1415   mcflags[nglocal][2] = -1;
1416   mcflags[nglocal][3] = -1;
1417 
1418   nglocal++;
1419 }
1420 
1421 /* ----------------------------------------------------------------------
1422    reset final grid cell count after grid cell removals
1423 ------------------------------------------------------------------------- */
1424 
reset_grid_count(int nlocal)1425 void FixAblate::reset_grid_count(int nlocal)
1426 {
1427   nglocal = nlocal;
1428 }
1429 
1430 /* ----------------------------------------------------------------------
1431    insure per-cell arrays are allocated long enough for Nnew cells
1432 ------------------------------------------------------------------------- */
1433 
grow_percell(int nnew)1434 void FixAblate::grow_percell(int nnew)
1435 {
1436   if (nglocal+nnew < maxgrid) return;
1437   if (nnew == 0) maxgrid = nglocal;
1438   else maxgrid += DELTAGRID;
1439   memory->grow(cvalues,maxgrid,ncorner,"ablate:cvalues");
1440   if (tvalues_flag) memory->grow(tvalues,maxgrid,"ablate:tvalues");
1441   memory->grow(ixyz,maxgrid,3,"ablate:ixyz");
1442   memory->grow(mcflags,maxgrid,4,"ablate:mcflags");
1443   memory->grow(celldelta,maxgrid,"ablate:celldelta");
1444   memory->grow(cdelta,maxgrid,ncorner,"ablate:celldelta");
1445   memory->grow(numsend,maxgrid,"ablate:numsend");
1446 
1447   array_grid = cvalues;
1448 }
1449 
1450 /* ----------------------------------------------------------------------
1451    reallocate send vectors
1452 ------------------------------------------------------------------------- */
1453 
grow_send()1454 void FixAblate::grow_send()
1455 {
1456   maxsend += DELTASEND;
1457   memory->grow(proclist,maxsend,"ablate:proclist");
1458   memory->grow(locallist,maxsend,"ablate:locallist");
1459 }
1460 
1461 /* ----------------------------------------------------------------------
1462    output sum of grid cell corner point values
1463    assume boundary corner points have value = 0.0
1464    NOTE: else would have to apply duplication weights to each of 4/8 corner pts
1465 ------------------------------------------------------------------------- */
1466 
compute_scalar()1467 double FixAblate::compute_scalar()
1468 {
1469   int ix,iy,iz;
1470 
1471   Grid::ChildCell *cells = grid->cells;
1472   Grid::ChildInfo *cinfo = grid->cinfo;
1473 
1474   double sum = 0.0;
1475   for (int icell = 0; icell < nglocal; icell++) {
1476     if (!(cinfo[icell].mask & groupbit)) continue;
1477     if (cells[icell].nsplit <= 0) continue;
1478 
1479     ix = ixyz[icell][0];
1480     iy = ixyz[icell][1];
1481     iz = ixyz[icell][2];
1482 
1483     if (dim == 2 && (ix == 0 || iy == 0)) continue;
1484     if (dim == 3 && (ix == 0 || iy == 0 || iz == 0)) continue;
1485     sum += cvalues[icell][0];
1486   }
1487 
1488   double sumall;
1489   MPI_Allreduce(&sum,&sumall,1,MPI_DOUBLE,MPI_SUM,world);
1490   return sumall;
1491 }
1492 
1493 /* ----------------------------------------------------------------------
1494    vector outputs
1495    1 = last ablation decrement
1496    2 = # of deleted inside particles at last ablation
1497 ------------------------------------------------------------------------- */
1498 
compute_vector(int i)1499 double FixAblate::compute_vector(int i)
1500 {
1501   if (i == 0) return sum_delta;
1502   if (i == 1) return 1.0*ndelete;
1503   return 0.0;
1504 }
1505 
1506 /* ----------------------------------------------------------------------
1507    memory usage
1508 ------------------------------------------------------------------------- */
1509 
memory_usage()1510 double FixAblate::memory_usage()
1511 {
1512   double bytes = 0.0;
1513   bytes += maxgrid*ncorner * sizeof(double);   // cvalues
1514   if (tvalues_flag) bytes += maxgrid * sizeof(int);   // tvalues
1515   bytes += maxgrid*3 * sizeof(int);            // ixyz
1516   // NOTE: add for mcflags if keep
1517   bytes += maxgrid * sizeof(double);           // celldelta
1518   bytes += maxgrid*ncorner * sizeof(double);   // cdelta
1519   bytes += maxghost*ncorner * sizeof(double);  // cdelta_ghost
1520   bytes += 3*maxsend * sizeof(int);            // proclist,locallist,numsend
1521   bytes += maxbuf * sizeof(double);            // sbuf
1522   return bytes;
1523 }
1524