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