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 "string.h"
16 #include "grid.h"
17 #include "error.h"
18 
19 using namespace SPARTA_NS;
20 
21 enum{XLO,XHI,YLO,YHI,ZLO,ZHI,INTERIOR};         // same as Domain
22 
23 // operations with grid cell IDs
24 // IMPORTANT: must be careful to use cellint (32 or 64 bit) in these cases
25 //   any cell ID, child or parent
26 //   any mask for bitwise operations
27 //   for ichild = 1 to Nxyz for subcell index within a parent cell
28 //   to multiply 2 or 3 nx,ny,nz indices
29 
30 /* ----------------------------------------------------------------------
31    compute indices of child cell within parent cell that contains point X
32    lo/hi = corner points of parent cell
33    nx,ny,nz = number of child cells within parent
34    return ix,iy,iz for which child cell the point is in
35    definition of inside is >= lo boundary and < hi boundary
36    ix,iy,iz range from 0 to Nxyz-1 inclusive
37 ------------------------------------------------------------------------- */
38 
id_point_child(double * x,double * lo,double * hi,int nx,int ny,int nz,int & ix,int & iy,int & iz)39 void Grid::id_point_child(double *x, double *lo, double *hi,
40 			  int nx, int ny, int nz, int &ix, int &iy, int &iz)
41 {
42   // ix,iy,iz = child cell indices within parent lo/hi cell
43   // inverse of master equation in id_child_lohi() for cell boundaries
44   // for point on or eps from cell boundary, can produce round-off error
45 
46   ix = static_cast<int> ((x[0]-lo[0]) * nx/(hi[0]-lo[0]));
47   iy = static_cast<int> ((x[1]-lo[1]) * ny/(hi[1]-lo[1]));
48   iz = static_cast<int> ((x[2]-lo[2]) * nz/(hi[2]-lo[2]));
49 
50   // insure indices match grid cell boundaries in case of round-off error
51   // via master equation id_child_lohi() that defines cell boundaries
52 
53   double edge;
54 
55   edge = lo[0] + ix*(hi[0]-lo[0])/nx;
56   if (x[0] < edge) ix--;
57   edge = lo[0] + (ix+1)*(hi[0]-lo[0])/nx;
58   if (x[0] >= edge) ix++;
59 
60   edge = lo[1] + iy*(hi[1]-lo[1])/ny;
61   if (x[1] < edge) iy--;
62   edge = lo[1] + (iy+1)*(hi[1]-lo[1])/ny;
63   if (x[1] >= edge) iy++;
64 
65   edge = lo[2] + iz*(hi[2]-lo[2])/nz;
66   if (x[2] < edge) iz--;
67   edge = lo[2] + (iz+1)*(hi[2]-lo[2])/nz;
68   if (x[2] >= edge) iz++;
69 
70   // insure indices range from 0 to Nxyz-1 inclusive
71 
72   ix = MAX(ix,0);
73   ix = MIN(ix,nx-1);
74   iy = MAX(iy,0);
75   iy = MIN(iy,ny-1);
76   iz = MAX(iz,0);
77   iz = MIN(iz,nz-1);
78 }
79 
80 /* ----------------------------------------------------------------------
81    calculate parentID of a childID at level
82    return parentID
83 ------------------------------------------------------------------------- */
84 
id_parent_of_child(cellint childID,int level)85 cellint Grid::id_parent_of_child(cellint childID, int level)
86 {
87   // mask = all 1s for parent bits of ID
88 
89   int parentbits = plevels[level-1].nbits;
90   cellint mask = (1L << parentbits) - 1;
91   cellint parentID = childID & mask;
92 
93   return parentID;
94 }
95 
96 /* ----------------------------------------------------------------------
97    find child cell within parentID which contains point X
98    level = level of parent cell
99    oplo/ophi = original parent cell corner pts
100    pt X must be inside or on any boundary of parent cell
101    recurse from parent downward until find a child cell or reach maxlevel
102    if find child cell this proc stores (owned or ghost), return its local index
103    else return -1 for unknown
104 ------------------------------------------------------------------------- */
105 
id_find_child(cellint parentID,int plevel,double * oplo,double * ophi,double * x)106 int Grid::id_find_child(cellint parentID, int plevel,
107 			double *oplo, double *ophi, double *x)
108 {
109   int ix,iy,iz,nx,ny,nz;
110   double plo[3],phi[3],clo[3],chi[3];
111   cellint childID,ichild;
112 
113   cellint id = parentID;
114   int level = plevel;
115   double *lo = oplo;
116   double *hi = ophi;
117 
118   while (level < maxlevel) {
119     nx = plevels[level].nx;
120     ny = plevels[level].ny;
121     nz = plevels[level].nz;
122 
123     id_point_child(x,lo,hi,nx,ny,nz,ix,iy,iz);
124     ichild = (cellint) iz*nx*ny + (cellint) iy*nx + ix + 1;
125     childID = (ichild << plevels[level].nbits) | id;
126 
127     if (hash->find(childID) != hash->end()) return (*hash)[childID];
128 
129     id = childID;
130     id_child_lohi(level,lo,hi,ichild,clo,chi);
131     plo[0] = clo[0]; plo[1] = clo[1]; plo[2] = clo[2];
132     phi[0] = chi[0]; phi[1] = chi[1]; phi[2] = chi[2];
133     lo = plo; hi = phi;
134     level++;
135   }
136 
137   return -1;
138 }
139 
140 /* ----------------------------------------------------------------------
141    compute cell ID of the child cell in a full-box uniform grid at level
142    xyz grid = indices (0 to N-1) of the child cell within full-box grid
143    return the cell ID
144 ------------------------------------------------------------------------- */
145 
id_uniform_level(int level,int xgrid,int ygrid,int zgrid)146 cellint Grid::id_uniform_level(int level, int xgrid, int ygrid, int zgrid)
147 {
148   int ix,iy,iz,nx,ny,nz;
149   int parentbits;
150   cellint ichild;
151 
152   cellint childID = 0;
153 
154   for (int ilevel = level-1; ilevel >= 0; ilevel--) {
155     nx = plevels[ilevel].nx;
156     ny = plevels[ilevel].ny;
157     nz = plevels[ilevel].nz;
158 
159     ix = xgrid % nx;
160     iy = ygrid % ny;
161     iz = zgrid % nz;
162 
163     ichild = (cellint) iz*ny*nx + (cellint) iy*nx + ix + 1;
164     parentbits = plevels[ilevel].nbits;
165     childID |= ichild << parentbits;
166 
167     xgrid /= nx;
168     ygrid /= ny;
169     zgrid /= nz;
170   }
171 
172   return childID;
173 }
174 
175 /* ----------------------------------------------------------------------
176    find child cell within a uniform grid at level which contains point X
177      definition of "contains" depends on lohi flag
178    level = level of uniform grid og child cells
179    lohi = 0 for lower boundary, 1 for upper boundary
180      for 0: if pt is on lower boundary (in any dim) of child cell,
181             return index of adjacent cell (index is decremented)
182      for 1: if pt is on upper boundary (in any dim) of child cell,
183             return index of adjacent cell (index is incremented)
184      incremented/decremented indices cannot be outside simulation box
185    boxlo/boxhi = root level simulation box
186    pt X must be inside or on any boundary of simulation box
187    recurse downward to level
188    return xyz grid = indices (0 to N-1) of child cell
189      in full-box uniform grid at level
190 ------------------------------------------------------------------------- */
191 
id_find_child_uniform_level(int level,int lohi,double * boxlo,double * boxhi,double * x,int & xgrid,int & ygrid,int & zgrid)192 void Grid::id_find_child_uniform_level(int level, int lohi,
193 				       double *boxlo, double *boxhi, double *x,
194 				       int &xgrid, int &ygrid, int &zgrid)
195 {
196   int ix,iy,iz,nx,ny,nz;
197   double plo[3],phi[3],clo[3],chi[3];
198   cellint childID,ichild;
199 
200   cellint id = 0;
201   int plevel = 0;
202   double *lo = boxlo;
203   double *hi = boxhi;
204   xgrid = ygrid = zgrid = 0;
205 
206   while (plevel < level) {
207     nx = plevels[plevel].nx;
208     ny = plevels[plevel].ny;
209     nz = plevels[plevel].nz;
210 
211     id_point_child(x,lo,hi,nx,ny,nz,ix,iy,iz);
212 
213     xgrid = nx*xgrid + ix;
214     ygrid = ny*ygrid + iy;
215     zgrid = nz*zgrid + iz;
216 
217     ichild = (cellint) iz*nx*ny + (cellint) iy*nx + ix + 1;
218     childID = (ichild << plevels[plevel].nbits) | id;
219 
220     id = childID;
221     id_child_lohi(plevel,lo,hi,ichild,clo,chi);
222     plo[0] = clo[0]; plo[1] = clo[1]; plo[2] = clo[2];
223     phi[0] = chi[0]; phi[1] = chi[1]; phi[2] = chi[2];
224     lo = plo; hi = phi;
225     plevel++;
226   }
227 
228   // x >= lower edge and < upper edge of lo/hi cell with indices ix,iy,iz
229   // if lohi = 0 and pt is on lower edge, decrement index
230   // still require 0 <= index <= N-1
231 
232   if (lohi == 0) {
233     if (x[0] == lo[0] && ix != 0) xgrid--;
234     if (x[1] == lo[1] && iy != 0) ygrid--;
235     if (x[2] == lo[2] && iz != 0) zgrid--;
236   }
237 }
238 
239 /* ----------------------------------------------------------------------
240    calculate ID of neighbor cell of childID across its face
241    neighbor cell is at same level
242    assume neigbor cell has same parent
243    return neighID if that is the case (doesn't check for periodic BC)
244    return 0 if not same parent
245 ------------------------------------------------------------------------- */
246 
id_neigh_same_parent(cellint id,int level,int face)247 cellint Grid::id_neigh_same_parent(cellint id, int level, int face)
248 {
249   int ixyz[3];
250   int *nxyz;
251 
252   // mask = all 1s for parent bits of ID
253 
254   int parentbits = plevels[level-1].nbits;
255   cellint mask = (1L << parentbits) - 1;
256   cellint parent = id & mask;
257 
258   // mask = all 1s for child bits of ID
259 
260   int childbits = plevels[level-1].newbits;
261   mask = (1L << childbits) - 1;
262   cellint ichild = (id >> plevels[level-1].nbits) & mask;
263 
264   nxyz = &plevels[level-1].nx;
265 
266   ichild--;
267   ixyz[0] = ichild % nxyz[0];
268   ixyz[1] = (ichild / nxyz[0]) % nxyz[1];
269   ixyz[2] = ichild / ((cellint) nxyz[0]*nxyz[1]);
270 
271   int dim = face / 2;
272   if (face % 2) ixyz[dim]++;
273   else ixyz[dim]--;
274   if (ixyz[dim] < 0) return 0;
275   if (ixyz[dim] == nxyz[dim]) return 0;
276 
277 
278   ichild = (cellint) ixyz[2]*nxyz[1]*nxyz[0] +
279     (cellint) ixyz[1]*nxyz[0] + ixyz[0] + 1;
280   cellint neighID = (ichild << parentbits) | parent;
281 
282   return neighID;
283 }
284 
285 /* ----------------------------------------------------------------------
286    calculate ID of neighbor cell of cell ID across its face
287    neighbor cell is at same level
288    no assumption that neighbor cell has same parent
289    assume periodic BC
290    return neighID
291 ------------------------------------------------------------------------- */
292 
id_neigh_same_level(cellint id,int level,int face)293 cellint Grid::id_neigh_same_level(cellint id, int level, int face)
294 {
295   int ix,iy,iz,childbits,parentbits;
296   cellint ichild,mask;
297   int ixyz[3],fullxyz[3];
298   int *nxyz;
299 
300   // ixyz[3] = indices of cell ID in fully resolved fullxyz grid at level
301   // each index = 0 to N-1
302 
303   ixyz[0] = ixyz[1] = ixyz[2] = 0;
304   fullxyz[0] = fullxyz[1] = fullxyz[2] = 1;
305 
306   for (int ilevel = 0; ilevel < level; ilevel++) {
307     nxyz = &plevels[ilevel].nx;
308 
309     fullxyz[0] *= nxyz[0];
310     fullxyz[1] *= nxyz[1];
311     fullxyz[2] *= nxyz[2];
312 
313     ixyz[0] *= nxyz[0];
314     ixyz[1] *= nxyz[1];
315     ixyz[2] *= nxyz[2];
316 
317     // mask = all 1s for child bits at ilevel
318 
319     childbits = plevels[ilevel].newbits;
320     mask = (1L << childbits) - 1;
321     ichild = (id >> plevels[ilevel].nbits) & mask;
322 
323     ichild--;
324     ixyz[0] += ichild % nxyz[0];
325     ixyz[1] += (ichild / nxyz[0]) % nxyz[1];
326     ixyz[2] += ichild / ((cellint) nxyz[0]*nxyz[1]);
327   }
328 
329   // alter ixyz[3] to be indices of neighbor cell
330   // apply periodic boundary conditions based on fullxyz[3]
331   // each altered index = 0 to N-1
332 
333   int dim = face / 2;
334   if (face % 2) ixyz[dim]++;
335   else ixyz[dim]--;
336   if (ixyz[dim] < 0) ixyz[dim] = fullxyz[dim] - 1;
337   if (ixyz[dim] == fullxyz[dim]) ixyz[dim] = 0;
338 
339   // neighID = neighbor cell ID generated from ixyz[3]
340 
341   cellint neighID = 0;
342 
343   for (int ilevel = level-1; ilevel >= 0; ilevel--) {
344     nxyz = &plevels[ilevel].nx;
345 
346     ix = ixyz[0] % nxyz[0];
347     iy = ixyz[1] % nxyz[1];
348     iz = ixyz[2] % nxyz[2];
349 
350     ichild = (cellint) iz*nxyz[1]*nxyz[0] + (cellint) iy*nxyz[0] + ix + 1;
351     parentbits = plevels[ilevel].nbits;
352     neighID |= ichild << parentbits;
353 
354     ixyz[0] /= nxyz[0];
355     ixyz[1] /= nxyz[1];
356     ixyz[2] /= nxyz[2];
357   }
358 
359   return neighID;
360 }
361 
362 /* ----------------------------------------------------------------------
363    calculate a child ID of parent cell at level
364    choose child in center of face of parent
365    return child ID
366 ------------------------------------------------------------------------- */
367 
id_refine(cellint parentID,int plevel,int face)368 cellint Grid::id_refine(cellint parentID, int plevel, int face)
369 {
370   int *nxyz = &plevels[plevel].nx;
371 
372   int ixyz[3];
373   ixyz[0] = nxyz[0] / 2;
374   ixyz[1] = nxyz[1] / 2;
375   ixyz[2] = nxyz[2] / 2;
376 
377   if (face % 2) ixyz[face/2] = nxyz[face/2] - 1;
378   else ixyz[face/2] = 0;
379 
380   cellint ichild = (cellint) ixyz[2]*nxyz[1]*nxyz[0] +
381     (cellint) ixyz[1]*nxyz[0] + ixyz[0] + 1;
382 
383   int parentbits = plevels[plevel].nbits;
384   cellint childID = parentID | (ichild << parentbits);
385   return childID;
386 }
387 
388 /* ----------------------------------------------------------------------
389    calculate parent ID of child cell at level
390    return parent ID
391 ------------------------------------------------------------------------- */
392 
id_coarsen(cellint childID,int level)393 cellint Grid::id_coarsen(cellint childID, int level)
394 {
395   // mask = all 1s for parent bits of child
396 
397   int parentbits = plevels[level-1].nbits;
398   cellint mask = (1L << parentbits) - 1;
399   cellint parentID = childID & mask;
400   return parentID;
401 }
402 
403 /* ----------------------------------------------------------------------
404    calculate which ichild the childID of parentID is
405    plevel = grid level of parent, not child
406    return ichild = 1 to Nxyz
407    return a cellint in case Nxyz is huge, e.g. at level 1
408 ------------------------------------------------------------------------- */
409 
id_ichild(cellint childID,cellint parentID,int plevel)410 cellint Grid::id_ichild(cellint childID, cellint parentID, int plevel)
411 {
412   int parentbits = plevels[plevel].nbits;
413   cellint ichild = childID >> parentbits;
414   return ichild;
415 }
416 
417 /* ----------------------------------------------------------------------
418    return level the cell ID is at from 1 to Nlevels
419    calculate by recursing from root until id = 0
420    if id still not 0 at maxlevel, return -1
421 ------------------------------------------------------------------------- */
422 
id_level(cellint id)423 int Grid::id_level(cellint id)
424 {
425   int newbits;
426   cellint mask,ichild;
427 
428   int level = 0;
429   while (level < maxlevel) {
430     newbits = plevels[level].newbits;
431     mask = (1L << newbits) - 1;
432     ichild = id & mask;
433     id = id >> newbits;
434     if (!id) break;
435     level++;
436   }
437 
438   return level+1;
439 }
440 
441 /* ----------------------------------------------------------------------
442    compute lo/hi extent of a specific child cell within a parent cell
443    plevel = level of parent
444    plo/phi = parent cell corner points
445    ichild ranges from 1 to Nx*Ny*Nz within parent cell
446    return clo/chi corner points, caller must allocate them
447 ------------------------------------------------------------------------- */
448 
id_child_lohi(int plevel,double * plo,double * phi,cellint ichild,double * clo,double * chi)449 void Grid::id_child_lohi(int plevel, double *plo, double *phi,
450 			 cellint ichild, double *clo, double *chi)
451 {
452   int nx = plevels[plevel].nx;
453   int ny = plevels[plevel].ny;
454   int nz = plevels[plevel].nz;
455 
456   ichild--;
457   int ix = ichild % nx;
458   int iy = (ichild/nx) % ny;
459   int iz = ichild / ((cellint) nx*ny);
460 
461   clo[0] = plo[0] + ix*(phi[0]-plo[0])/nx;
462   clo[1] = plo[1] + iy*(phi[1]-plo[1])/ny;
463   clo[2] = plo[2] + iz*(phi[2]-plo[2])/nz;
464 
465   chi[0] = plo[0] + (ix+1)*(phi[0]-plo[0])/nx;
466   chi[1] = plo[1] + (iy+1)*(phi[1]-plo[1])/ny;
467   chi[2] = plo[2] + (iz+1)*(phi[2]-plo[2])/nz;
468 
469   if (ix == nx-1) chi[0] = phi[0];
470   if (iy == ny-1) chi[1] = phi[1];
471   if (iz == nz-1) chi[2] = phi[2];
472 }
473 
474 /* ----------------------------------------------------------------------
475    compute lo/hi extent of cell ID at level
476    boxlo/boxhi = global simulation box (level 0)
477    return lo/hi corner points, caller must allocate them
478 ------------------------------------------------------------------------- */
479 
id_lohi(cellint id,int level,double * boxlo,double * boxhi,double * lo,double * hi)480 void Grid::id_lohi(cellint id, int level, double *boxlo, double *boxhi,
481 		   double *lo, double *hi)
482 {
483   int childbits;
484   cellint ichild,mask;
485   double plo[3],phi[3];
486 
487   plo[0] = boxlo[0]; plo[1] = boxlo[1]; plo[2] = boxlo[2];
488   phi[0] = boxhi[0]; phi[1] = boxhi[1]; phi[2] = boxhi[2];
489 
490   for (int ilevel = 0; ilevel < level; ilevel++) {
491 
492     // mask = all 1s for child bits at ilevel
493 
494     childbits = plevels[ilevel].newbits;
495     mask = (1L << childbits) - 1;
496     ichild = (id >> plevels[ilevel].nbits) & mask;
497 
498     id_child_lohi(ilevel,plo,phi,ichild,lo,hi);
499 
500     plo[0] = lo[0]; plo[1] = lo[1]; plo[2] = lo[2];
501     phi[0] = hi[0]; phi[1] = hi[1]; phi[2] = hi[2];
502   }
503 }
504 
505 /* ----------------------------------------------------------------------
506    calculate # of bits needed to store values from 1 to Nx*Ny*Nz
507 ------------------------------------------------------------------------- */
508 
id_bits(int nx,int ny,int nz)509 int Grid::id_bits(int nx, int ny, int nz)
510 {
511   bigint n = (bigint) nx*ny*nz;
512   bigint nstore = 1;
513   int nbits = 1;
514 
515   while (nstore < n) {
516     nstore = 2*nstore + 1;
517     nbits++;
518   }
519 
520   return nbits;
521 }
522 
523 /* ----------------------------------------------------------------------
524    convert cell ID from number to string with levels separated by dashes
525    walk grid hierarchy from root to ID, generating one substr at each level
526    NOTE: should append letter for sub cells, but not enough info to do it
527          don't know the parent cell (which might be on a different proc)
528          one way to do it would be for dump_grid to have a pack_idstr
529          which sets some hi-bits to encode the sub cell #
530          but this would use up some extra bits in the ID
531 ------------------------------------------------------------------------- */
532 
id_num2str(cellint id,char * str)533 void Grid::id_num2str(cellint id, char *str)
534 {
535   int newbits;
536   cellint mask,ichild;
537 
538   // sprintf child bits one level at a time until id = 0
539 
540   int offset = 0;
541   int level = 0;
542 
543   while (1) {
544     newbits = plevels[level].newbits;
545     mask = (1L << newbits) - 1;
546     ichild = id & mask;
547     sprintf(&str[offset],"%d",ichild);
548     offset = strlen(str);
549     id = id >> newbits;
550     if (!id) return;
551     str[offset++] = '-';
552     level++;
553   }
554 }
555