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